summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/AttestationVerificationTest/Android.bp44
-rwxr-xr-xtests/AttestationVerificationTest/AndroidManifest.xml33
-rw-r--r--tests/AttestationVerificationTest/AndroidTest.xml27
-rw-r--r--tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt90
-rw-r--r--tests/BatteryStatsPerfTest/AndroidManifest.xml2
-rw-r--r--tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java129
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/MediaDecoder.java5
-rw-r--r--tests/FlickerTests/AndroidTest.xml4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt22
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt34
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt34
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt31
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt11
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt20
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt14
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt17
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt5
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt11
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt43
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt13
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt5
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt23
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt71
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt55
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt13
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt36
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt17
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt47
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt28
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt21
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt58
-rw-r--r--tests/HwAccelerationTest/Android.bp8
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/jni/Android.bp44
-rw-r--r--tests/HwAccelerationTest/jni/native-lib.cpp62
-rw-r--r--tests/HwAccelerationTest/res/layout/pen_stylus.xml20
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java2
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java2
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/FrontBufferedLayer.kt132
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java2
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/PenStylusActivity.kt85
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java2
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java2
-rw-r--r--tests/Input/Android.bp2
-rw-r--r--tests/Input/src/com/android/test/input/AnrTest.kt119
-rw-r--r--tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt110
-rw-r--r--tests/Input/src/com/android/test/input/PointerEventDispatcherTest.kt93
-rw-r--r--tests/Input/src/com/android/test/input/SpyInputEventSenderAndReceiver.kt75
-rw-r--r--tests/InputMethodStressTest/Android.bp35
-rw-r--r--tests/InputMethodStressTest/AndroidManifest.xml29
-rw-r--r--tests/InputMethodStressTest/AndroidTest.xml29
-rw-r--r--tests/InputMethodStressTest/OWNERS3
-rw-r--r--tests/InputMethodStressTest/TEST_MAPPING7
-rw-r--r--tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java83
-rw-r--r--tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java96
-rw-r--r--tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java80
-rw-r--r--tests/Internal/src/com/android/internal/util/ParcellingTests.java77
-rw-r--r--tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java11
-rw-r--r--tests/RollbackTest/Android.bp8
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java935
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java342
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java540
-rw-r--r--tests/SoundTriggerTestApp/res/layout/main.xml8
-rw-r--r--tests/SoundTriggerTestApp/res/values/strings.xml1
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java8
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java70
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java33
-rw-r--r--tests/StagedInstallTest/Android.bp1
-rw-r--r--tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java30
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java28
-rw-r--r--tests/UpdatableSystemFontTest/Android.bp20
-rw-r--r--tests/UpdatableSystemFontTest/AndroidTest.xml18
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java13
-rw-r--r--tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java174
-rw-r--r--tests/UpdatableSystemFontTest/testdata/Android.bp60
-rw-r--r--tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java3
-rw-r--r--tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java2
-rw-r--r--tests/componentalias/Android.bp87
-rwxr-xr-xtests/componentalias/AndroidManifest.xml25
-rwxr-xr-xtests/componentalias/AndroidManifest_main.xml28
-rw-r--r--tests/componentalias/AndroidManifest_service_aliases.xml81
-rw-r--r--tests/componentalias/AndroidManifest_service_targets.xml57
-rwxr-xr-xtests/componentalias/AndroidManifest_sub1.xml28
-rwxr-xr-xtests/componentalias/AndroidManifest_sub2.xml28
-rw-r--r--tests/componentalias/AndroidTest-template.xml40
-rw-r--r--tests/componentalias/OWNERS2
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java91
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/ComponentAliasBroadcastTest.java110
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java215
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/ComponentAliasServiceTest.java315
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/ComponentAliasTestCommon.java28
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/b/BaseReceiver.java44
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/b/Target00.java21
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/b/Target01.java19
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/b/Target02.java19
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/b/Target03.java19
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/b/Target04.java19
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/s/BaseService.java70
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/s/Target00.java19
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/s/Target01.java19
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/s/Target02.java19
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/s/Target03.java19
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/s/Target04.java19
-rw-r--r--tests/utils/testutils/Android.bp2
106 files changed, 3783 insertions, 2145 deletions
diff --git a/tests/AttestationVerificationTest/Android.bp b/tests/AttestationVerificationTest/Android.bp
new file mode 100644
index 000000000000..a4741eedaac0
--- /dev/null
+++ b/tests/AttestationVerificationTest/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2021 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 {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "AttestationVerificationTest",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ defaults: ["cts_defaults"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
+ platform_apis: true,
+ certificate: "platform",
+ optimize: {
+ enabled: false,
+ },
+ test_suites: ["device-tests"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: [
+ "compatibility-device-util-axt",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "platform-test-annotations",
+ ],
+}
diff --git a/tests/AttestationVerificationTest/AndroidManifest.xml b/tests/AttestationVerificationTest/AndroidManifest.xml
new file mode 100755
index 000000000000..c42bde9dca3a
--- /dev/null
+++ b/tests/AttestationVerificationTest/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.security.attestationverification">
+
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+ <uses-permission android:name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE" />
+
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name=".SystemAttestationVerificationTest$TestActivity" />
+ </application>
+
+ <!-- self-instrumenting test package. -->
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.attestationverification">
+ </instrumentation>
+</manifest>
diff --git a/tests/AttestationVerificationTest/AndroidTest.xml b/tests/AttestationVerificationTest/AndroidTest.xml
new file mode 100644
index 000000000000..132576035952
--- /dev/null
+++ b/tests/AttestationVerificationTest/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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="Platform tests for Attestation Verification Framework">
+ <option name="test-tag" value="AttestationVerificationTest" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="AttestationVerificationTest.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.security.attestationverification" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt b/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt
new file mode 100644
index 000000000000..48bfd6f5d33c
--- /dev/null
+++ b/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt
@@ -0,0 +1,90 @@
+package android.security.attestationverification
+
+import android.os.Bundle
+import android.app.Activity
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import com.google.common.truth.Truth.assertThat
+import android.security.attestationverification.AttestationVerificationManager.PROFILE_SELF_TRUSTED
+import android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY
+import android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN
+import java.lang.IllegalArgumentException
+import java.time.Duration
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit
+
+/** Test for system-defined attestation verifiers. */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SystemAttestationVerificationTest {
+
+ @get:Rule
+ val rule = ActivityScenarioRule(TestActivity::class.java)
+
+ private lateinit var activity: Activity
+ private lateinit var avm: AttestationVerificationManager
+
+ @Before
+ fun setup() {
+ rule.getScenario().onActivity {
+ avm = it.getSystemService(AttestationVerificationManager::class.java)
+ activity = it
+ }
+ }
+
+ @Test
+ fun verifyAttestation_returnsUnknown() {
+ val future = CompletableFuture<Int>()
+ val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+ avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0),
+ activity.mainExecutor) { result, _ ->
+ future.complete(result)
+ }
+
+ assertThat(future.getSoon()).isEqualTo(RESULT_UNKNOWN)
+ }
+
+ @Test
+ fun verifyToken_returnsUnknown() {
+ val future = CompletableFuture<Int>()
+ val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+ avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0),
+ activity.mainExecutor) { _, token ->
+ val result = avm.verifyToken(profile, TYPE_PUBLIC_KEY, Bundle(), token, null)
+ future.complete(result)
+ }
+
+ assertThat(future.getSoon()).isEqualTo(RESULT_UNKNOWN)
+ }
+
+ @Test
+ fun verifyToken_tooBigMaxAgeThrows() {
+ val future = CompletableFuture<VerificationToken>()
+ val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+ avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0),
+ activity.mainExecutor) { _, token ->
+ future.complete(token)
+ }
+
+ assertThrows(IllegalArgumentException::class.java) {
+ avm.verifyToken(profile, TYPE_PUBLIC_KEY, Bundle(), future.getSoon(),
+ Duration.ofSeconds(3601))
+ }
+ }
+
+ private fun <T> CompletableFuture<T>.getSoon(): T {
+ return this.get(1, TimeUnit.SECONDS)
+ }
+
+ class TestActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ }
+ }
+}
diff --git a/tests/BatteryStatsPerfTest/AndroidManifest.xml b/tests/BatteryStatsPerfTest/AndroidManifest.xml
index 7633d5283f5e..ab5728e75b9f 100644
--- a/tests/BatteryStatsPerfTest/AndroidManifest.xml
+++ b/tests/BatteryStatsPerfTest/AndroidManifest.xml
@@ -20,6 +20,8 @@
<application>
<uses-library android:name="android.test.runner" />
+ <service android:name="com.android.internal.os.BatteryUsageStatsPerfTest$BatteryUsageStatsService"
+ android:process=":BatteryUsageStatsService" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
index 54d70478f762..fe2fe0b40891 100644
--- a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
+++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
@@ -18,13 +18,25 @@ package com.android.internal.os;
import static com.google.common.truth.Truth.assertThat;
+import android.app.Service;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.BatteryConsumer;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.Binder;
+import android.os.ConditionVariable;
+import android.os.IBinder;
+import android.os.Parcel;
import android.os.UidBatteryConsumer;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -54,7 +66,8 @@ public class BatteryUsageStatsPerfTest {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
- BatteryUsageStats batteryUsageStats = batteryStatsManager.getBatteryUsageStats();
+ BatteryUsageStats batteryUsageStats = batteryStatsManager.getBatteryUsageStats(
+ new BatteryUsageStatsQuery.Builder().setMaxStatsAgeMs(0).build());
state.pauseTiming();
@@ -71,4 +84,118 @@ public class BatteryUsageStatsPerfTest {
state.resumeTiming();
}
}
+
+ private final ConditionVariable mServiceConnected = new ConditionVariable();
+ private IBinder mService;
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mService = service;
+ mServiceConnected.open();
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ }
+ };
+
+ /**
+ * Measures the performance of transferring BatteryUsageStats over a Binder.
+ */
+ @Test
+ public void testBatteryUsageStatsTransferOverBinder() throws Exception {
+ final Context context = InstrumentationRegistry.getContext();
+ context.bindService(
+ new Intent(context, BatteryUsageStatsService.class),
+ mConnection, Context.BIND_AUTO_CREATE);
+ mServiceConnected.block(30000);
+ assertThat(mService).isNotNull();
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ final Parcel data = Parcel.obtain();
+ final Parcel reply = Parcel.obtain();
+ mService.transact(42, data, reply, 0);
+ final BatteryUsageStats batteryUsageStats =
+ BatteryUsageStats.CREATOR.createFromParcel(reply);
+ reply.recycle();
+ data.recycle();
+
+ state.pauseTiming();
+
+ assertThat(batteryUsageStats.getBatteryCapacity()).isEqualTo(4000);
+ assertThat(batteryUsageStats.getUidBatteryConsumers()).hasSize(1000);
+ final UidBatteryConsumer uidBatteryConsumer =
+ batteryUsageStats.getUidBatteryConsumers().get(0);
+ assertThat(uidBatteryConsumer.getConsumedPower(1)).isEqualTo(123);
+
+ state.resumeTiming();
+ }
+
+ context.unbindService(mConnection);
+ }
+
+ /* This service runs in a separate process */
+ public static class BatteryUsageStatsService extends Service {
+ private final BatteryUsageStats mBatteryUsageStats;
+
+ public BatteryUsageStatsService() {
+ mBatteryUsageStats = buildBatteryUsageStats();
+ }
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new Binder() {
+ @Override
+ protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
+ int flags) {
+ mBatteryUsageStats.writeToParcel(reply, 0);
+ return true;
+ }
+ };
+ }
+ }
+
+ private static BatteryUsageStats buildBatteryUsageStats() {
+ final BatteryUsageStats.Builder builder =
+ new BatteryUsageStats.Builder(new String[]{"FOO"}, true, false)
+ .setBatteryCapacity(4000)
+ .setDischargePercentage(20)
+ .setDischargedPowerRange(1000, 2000)
+ .setStatsStartTimestamp(1000)
+ .setStatsEndTimestamp(3000);
+
+ builder.getAggregateBatteryConsumerBuilder(
+ BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
+ .setConsumedPower(123)
+ .setConsumedPower(
+ BatteryConsumer.POWER_COMPONENT_CPU, 10100)
+ .setConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200)
+ .setUsageDurationMillis(
+ BatteryConsumer.POWER_COMPONENT_CPU, 10300)
+ .setUsageDurationForCustomComponentMillis(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10400);
+
+ for (int i = 0; i < 1000; i++) {
+ final UidBatteryConsumer.Builder consumerBuilder =
+ builder.getOrCreateUidBatteryConsumerBuilder(i)
+ .setPackageWithHighestDrain("example.packagename" + i)
+ .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, i * 2000)
+ .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, i * 1000);
+ for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
+ componentId++) {
+ consumerBuilder.setConsumedPower(componentId, componentId * 123.0,
+ BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+ consumerBuilder.setUsageDurationMillis(componentId, componentId * 1000);
+ }
+
+ consumerBuilder.setConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 1234)
+ .setUsageDurationForCustomComponentMillis(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 4321);
+ }
+ return builder.build();
+ }
}
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/MediaDecoder.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/MediaDecoder.java
index aa5739414df4..00fe6f2f866e 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/MediaDecoder.java
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/MediaDecoder.java
@@ -24,10 +24,12 @@ import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
+
import androidx.media.filterfw.FrameImage2D;
import androidx.media.filterfw.FrameValue;
import androidx.media.filterfw.RenderTarget;
+import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
@TargetApi(16)
@@ -276,12 +278,13 @@ public class MediaDecoder implements
}
@TargetApi(17)
- private void retrieveDefaultRotation() {
+ private void retrieveDefaultRotation() throws IOException {
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
metadataRetriever.setDataSource(mContext, mUri);
String rotationString = metadataRetriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
mDefaultRotation = rotationString == null ? 0 : Integer.parseInt(rotationString);
+ metadataRetriever.release();
}
private void onStop(boolean notifyListener) {
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 896ec9ae922c..566c725a3414 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -16,10 +16,6 @@
<!-- restart launcher to activate TAPL -->
<option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
- <!-- reboot the device to teardown any crashed tests -->
- <option name="cleanup-action" value="REBOOT" />
- </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
<option name="test-file-name" value="FlickerTests.apk"/>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 64cb790d324b..75f1337b9388 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -141,20 +141,36 @@ fun FlickerTestParameter.statusBarLayerRotatesScales() {
*
* @param originalLayer Layer that should be visible at the start
* @param newLayer Layer that should be visible at the end
+ * @param ignoreEntriesWithRotationLayer If entries with a visible rotation layer should be ignored
+ * when checking the transition. If true we will not fail the assertion if a rotation layer is
+ * visible to fill the gap between the [originalLayer] being visible and the [newLayer] being
+ * visible.
* @param ignoreSnapshot If the snapshot layer should be ignored during the transition
* (useful mostly for app launch)
+ * @param ignoreSplashscreen If the splashscreen layer should be ignored during the transition.
+ * If true then we will allow for a splashscreen to be shown before the layer is shown,
+ * otherwise we won't and the layer must appear immediately.
*/
fun FlickerTestParameter.replacesLayer(
originalLayer: FlickerComponentName,
newLayer: FlickerComponentName,
- ignoreSnapshot: Boolean = false
+ ignoreEntriesWithRotationLayer: Boolean = false,
+ ignoreSnapshot: Boolean = false,
+ ignoreSplashscreen: Boolean = true
) {
assertLayers {
val assertion = this.isVisible(originalLayer)
+
+ if (ignoreEntriesWithRotationLayer) {
+ assertion.then().isVisible(FlickerComponentName.ROTATION, isOptional = true)
+ }
if (ignoreSnapshot) {
- assertion.then()
- .isVisible(FlickerComponentName.SNAPSHOT, isOptional = true)
+ assertion.then().isVisible(FlickerComponentName.SNAPSHOT, isOptional = true)
}
+ if (ignoreSplashscreen) {
+ assertion.then().isSplashScreenVisibleFor(newLayer, isOptional = true)
+ }
+
assertion.then().isVisible(newLayer)
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 9f26c31a6d63..7076a07c8ef6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -17,6 +17,7 @@
package com.android.server.wm.flicker.close
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -24,6 +25,8 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -65,9 +68,9 @@ import org.junit.runners.Parameterized
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group4
class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this, it)
+ super.transition(this)
transitions {
device.pressBack()
wmHelper.waitForHomeActivityVisible()
@@ -79,6 +82,33 @@ class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ super.statusBarLayerRotatesScales()
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun launcherLayerReplacesApp() {
+ // This test doesn't work in shell transitions because of b/206086894
+ assumeFalse(isShellTransitionsEnabled)
+ super.launcherLayerReplacesApp()
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun entireScreenCovered() {
+ // This test doesn't work in shell transitions because of b/206086894
+ assumeFalse(isShellTransitionsEnabled)
+ super.entireScreenCovered()
+ }
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 795766fccfbd..b5d01ef24f23 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.close
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -23,6 +24,8 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -64,9 +67,9 @@ import org.junit.runners.Parameterized
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group4
class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this, it)
+ super.transition(this)
transitions {
device.pressHome()
wmHelper.waitForHomeActivityVisible()
@@ -78,6 +81,33 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ super.statusBarLayerRotatesScales()
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun launcherLayerReplacesApp() {
+ // This test doesn't work in shell transitions because of b/206086894
+ assumeFalse(isShellTransitionsEnabled)
+ super.launcherLayerReplacesApp()
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun entireScreenCovered() {
+ // This test doesn't work in shell transitions because of b/206086894
+ assumeFalse(isShellTransitionsEnabled)
+ super.entireScreenCovered()
+ }
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index 511fc26fdb38..ca73503164e6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -18,6 +18,7 @@ package com.android.server.wm.flicker.close
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
@@ -30,11 +31,12 @@ import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.flicker.replacesLayer
+import com.android.server.wm.flicker.rules.WMFlickerServiceRuleForTestSpec
+import org.junit.Rule
import org.junit.Test
/**
@@ -44,14 +46,17 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+ @get:Rule
+ val flickerRule = WMFlickerServiceRuleForTestSpec(testSpec)
+
/**
* Specification of the test transition to execute
*/
- protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ protected open val transition: FlickerBuilder.() -> Unit = {
setup {
eachRun {
testApp.launchViaIntent(wmHelper)
- this.setRotation(testSpec.config.startRotation)
+ this.setRotation(testSpec.startRotation)
}
}
teardown {
@@ -68,7 +73,7 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
- transition(testSpec.config)
+ transition()
}
}
@@ -189,4 +194,22 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
open fun launcherLayerReplacesApp() {
testSpec.replacesLayer(testApp.component, LAUNCHER_COMPONENT)
}
+
+ @FlakyTest
+ @Test
+ fun runPresubmitAssertion() {
+ flickerRule.checkPresubmitAssertions()
+ }
+
+ @FlakyTest
+ @Test
+ fun runPostsubmitAssertion() {
+ flickerRule.checkPostsubmitAssertions()
+ }
+
+ @FlakyTest
+ @Test
+ fun runFlakyAssertion() {
+ flickerRule.checkFlakyAssertions()
+ }
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 5e21aff94769..f12e4aeea4be 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -30,14 +30,15 @@ import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -63,7 +64,7 @@ import org.junit.runners.Parameterized
@Group2
class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
@@ -155,7 +156,11 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
+ fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.statusBarLayerRotatesScales()
+ }
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 0582685f2c54..0529fdd08fb3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -20,7 +20,6 @@ import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -34,11 +33,12 @@ import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -64,7 +64,7 @@ import org.junit.runners.Parameterized
@Group2
class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
@@ -104,7 +104,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
}
}
- @FlakyTest(bugId = 190189685)
+ @Presubmit
@Test
fun imeAppWindowBecomesInvisible() {
testSpec.assertWm {
@@ -116,7 +116,11 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
@Presubmit
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered()
+ fun entireScreenCovered() {
+ // This test doesn't work in shell transitions because of b/206086894
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.entireScreenCovered()
+ }
@Presubmit
@Test
@@ -154,7 +158,11 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
+ fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.statusBarLayerRotatesScales()
+ }
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 91b3d3dae3cd..d975cf40657b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -32,10 +32,12 @@ import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
-import org.junit.Assume
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -119,20 +121,24 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
fun navBarLayerRotatesAndScales() {
- Assume.assumeFalse(testSpec.isRotated)
+ assumeFalse(testSpec.isLandscapeOrSeascapeAtStart)
testSpec.navBarLayerRotatesAndScales()
}
@FlakyTest
@Test
fun navBarLayerRotatesAndScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
+ assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
testSpec.navBarLayerRotatesAndScales()
}
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
+ fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.statusBarLayerRotatesScales()
+ }
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index b589969dee14..facca9479da9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -20,7 +20,6 @@ import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -34,9 +33,11 @@ import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -104,7 +105,7 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
@Test
fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
- @FlakyTest
+ @Presubmit
@Test
fun imeAppWindowBecomesInvisible() {
testSpec.assertWm {
@@ -124,7 +125,11 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered()
+ fun entireScreenCovered() {
+ // This test doesn't work in shell transitions because of b/206086894
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.entireScreenCovered()
+ }
@Presubmit
@Test
@@ -146,7 +151,11 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
+ fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.statusBarLayerRotatesScales()
+ }
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
index a9568b325af2..005c4f59de50 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
@@ -29,7 +29,6 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.traces.common.FlickerComponentName
import org.junit.FixMethodOrder
import org.junit.Test
@@ -71,14 +70,14 @@ import org.junit.runners.Parameterized
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class LaunchAppShowImeOnStartTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
eachRun {
- this.setRotation(testSpec.config.startRotation)
+ this.setRotation(testSpec.startRotation)
}
}
teardown {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 7bf0186cd857..3ef4e4c375ad 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -20,7 +20,6 @@ import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -34,9 +33,11 @@ import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -128,7 +129,11 @@ class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
+ fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.statusBarLayerRotatesScales()
+ }
@Presubmit
@Test
@@ -138,7 +143,7 @@ class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
}
}
- @FlakyTest
+ @Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
testSpec.assertWm {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index f6febe9e2234..84e78ec40b29 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -17,10 +17,10 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.os.SystemProperties
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -37,12 +37,13 @@ import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
-import org.junit.Assume
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -60,9 +61,7 @@ import org.junit.runners.Parameterized
@Group2
class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
- private val isShellTransitionsEnabled =
- SystemProperties.getBoolean("persist.debug.shell_transit", false)
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
@@ -76,7 +75,7 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
device.pressRecentApps()
wmHelper.waitImeGone()
wmHelper.waitForAppTransitionIdle()
- this.setRotation(testSpec.config.startRotation)
+ this.setRotation(testSpec.startRotation)
}
}
transitions {
@@ -102,6 +101,8 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ // This test doesn't work in shell transitions because of b/204570898
+ assumeFalse(isShellTransitionsEnabled)
val component = FlickerComponentName("", "RecentTaskScreenshotSurface")
testSpec.assertWm {
this.visibleWindowsShownMoreThanOneConsecutiveEntry(
@@ -115,6 +116,8 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
fun launcherWindowBecomesInvisible() {
+ // This test doesn't work in shell transitions because of b/204574221
+ assumeFalse(isShellTransitionsEnabled)
testSpec.assertWm {
this.isAppWindowVisible(LAUNCHER_COMPONENT)
.then()
@@ -124,12 +127,16 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun imeWindowIsAlwaysVisible() = testSpec.imeWindowIsAlwaysVisible(!isShellTransitionsEnabled)
+ fun imeWindowIsAlwaysVisible() {
+ // This test doesn't work in shell transitions because of b/204570898
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.imeWindowIsAlwaysVisible(!isShellTransitionsEnabled)
+ }
@Presubmit
@Test
fun imeAppWindowVisibilityLegacy() {
- Assume.assumeFalse(isShellTransitionsEnabled)
+ assumeFalse(isShellTransitionsEnabled)
// the app starts visible in live tile, and stays visible for the duration of entering
// and exiting overview. However, legacy transitions seem to have a bug which causes
// everything to restart during the test, so expect the app to disappear and come back.
@@ -144,10 +151,10 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
}
}
- @Presubmit
+ @FlakyTest(bugId = 204570898)
@Test
fun imeAppWindowVisibility() {
- Assume.assumeTrue(isShellTransitionsEnabled)
+ assumeTrue(isShellTransitionsEnabled)
// the app starts visible in live tile, and stays visible for the duration of entering
// and exiting overview. Since we log 1x per frame, sometimes the activity visibility
// and the app visibility are updated together, sometimes not, thus ignore activity
@@ -173,7 +180,7 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
fun imeLayerIsBecomesVisibleLegacy() {
- Assume.assumeFalse(isShellTransitionsEnabled)
+ assumeFalse(isShellTransitionsEnabled)
testSpec.assertLayers {
this.isVisible(FlickerComponentName.IME)
.then()
@@ -183,10 +190,10 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
}
}
- @Presubmit
+ @FlakyTest(bugId = 204570898)
@Test
fun imeLayerIsBecomesVisible() {
- Assume.assumeTrue(isShellTransitionsEnabled)
+ assumeTrue(isShellTransitionsEnabled)
testSpec.assertLayers {
this.isVisible(FlickerComponentName.IME)
}
@@ -195,6 +202,8 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
fun appLayerReplacesLauncher() {
+ // This test doesn't work in shell transitions because of b/204574221
+ assumeFalse(isShellTransitionsEnabled)
testSpec.assertLayers {
this.isVisible(LAUNCHER_COMPONENT)
.then()
@@ -210,7 +219,11 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
+ fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.statusBarLayerRotatesScales()
+ }
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 4c506b0fea4d..a7a9fe289a4a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -33,7 +33,6 @@ import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
@@ -56,14 +55,14 @@ import org.junit.runners.Parameterized
class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = SimpleAppHelper(instrumentation)
- private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+ private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
eachRun {
- this.setRotation(testSpec.config.startRotation)
+ this.setRotation(testSpec.startRotation)
testApp.launchViaIntent(wmHelper)
wmHelper.waitForFullScreenApp(testApp.component)
wmHelper.waitForAppTransitionIdle()
@@ -86,7 +85,7 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
transitions {
// [Step1]: Swipe right from imeTestApp to testApp task
createTag(TAG_IME_VISIBLE)
- val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
device.swipe(0, displayBounds.bounds.height(),
displayBounds.bounds.width(), displayBounds.bounds.height(), 50)
@@ -96,7 +95,7 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
}
transitions {
// [Step2]: Swipe left to back to imeTestApp task
- val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
device.swipe(displayBounds.bounds.width(), displayBounds.bounds.height(),
0, displayBounds.bounds.height(), 50)
wmHelper.waitForFullScreenApp(imeTestApp.component)
@@ -109,8 +108,12 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
testSpec.assertWm {
isAppWindowVisible(imeTestApp.component)
.then()
+ .isAppSnapshotStartingWindowVisibleFor(testApp.component, isOptional = true)
+ .then()
.isAppWindowVisible(testApp.component)
.then()
+ .isAppSnapshotStartingWindowVisibleFor(imeTestApp.component, isOptional = true)
+ .then()
.isAppWindowVisible(imeTestApp.component)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index f74a7718461f..648353e34f92 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -26,7 +26,6 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.LAUNCHER_COMPONENT
-import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
@@ -60,7 +59,7 @@ import org.junit.runners.Parameterized
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group4
class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) {
- val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation)
/**
@@ -70,8 +69,6 @@ class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) {
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
- withTestName { testSpec.name }
- repeat { testSpec.config.repetitions }
setup {
eachRun {
testApp.launchViaIntent(wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index be919cd67c1e..fe434268fbc9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -25,9 +24,10 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -60,13 +60,13 @@ class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
/**
* Defines the transition used to run the test
*/
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this, it)
+ super.transition(this)
setup {
eachRun {
removeAllTasksButHome()
- this.setRotation(testSpec.config.startRotation)
+ this.setRotation(testSpec.startRotation)
}
}
teardown {
@@ -81,6 +81,15 @@ class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
}
/** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ super.statusBarLayerRotatesScales()
+ }
+
+ /** {@inheritDoc} */
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() {
@@ -88,12 +97,12 @@ class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
}
/** {@inheritDoc} */
- @Postsubmit
+ @Presubmit
@Test
override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
/** {@inheritDoc} */
- @Postsubmit
+ @Presubmit
@Test
override fun appWindowReplacesLauncherAsTopWindow() =
super.appWindowReplacesLauncherAsTopWindow()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 663af703f76d..53b53547707a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -17,17 +17,20 @@
package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Presubmit
+import android.view.Display
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.traces.common.WindowManagerConditionsFactory
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -62,9 +65,9 @@ class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransitio
/**
* Defines the transition used to run the test
*/
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this, it)
+ super.transition(this)
setup {
test {
testApp.launchViaIntent(wmHelper)
@@ -73,30 +76,76 @@ class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransitio
device.pressHome()
wmHelper.waitForAppTransitionIdle()
device.pressRecentApps()
- wmHelper.waitForAppTransitionIdle()
- this.setRotation(testSpec.config.startRotation)
+ wmHelper.waitFor(
+ WindowManagerConditionsFactory
+ .isAppTransitionIdle(Display.DEFAULT_DISPLAY),
+ WindowManagerConditionsFactory.isActivityVisible(LAUNCHER_COMPONENT),
+ WindowManagerConditionsFactory.hasLayersAnimating().negate()
+ )
+ this.setRotation(testSpec.startRotation)
}
}
transitions {
device.reopenAppFromOverview(wmHelper)
wmHelper.waitFor(
- WindowManagerConditionsFactory.hasLayersAnimating().negate(),
- WindowManagerConditionsFactory.isWMStateComplete(),
- WindowManagerConditionsFactory.isHomeActivityVisible().negate()
+ WindowManagerConditionsFactory.hasLayersAnimating().negate(),
+ WindowManagerConditionsFactory.isWMStateComplete(),
+ WindowManagerConditionsFactory.isLayerVisible(LAUNCHER_COMPONENT).negate(),
+ WindowManagerConditionsFactory.isActivityVisible(LAUNCHER_COMPONENT).negate()
)
wmHelper.waitForFullScreenApp(testApp.component)
}
}
/** {@inheritDoc} */
- @FlakyTest
+ @Presubmit
@Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+ override fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ super.statusBarLayerRotatesScales()
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun entireScreenCovered() {
+ // This test doesn't work in shell transitions because of b/204570898
+ assumeFalse(isShellTransitionsEnabled)
+ super.entireScreenCovered()
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() {
+ // This test doesn't work in shell transitions because of b/206085788
+ assumeFalse(isShellTransitionsEnabled)
+ super.appWindowReplacesLauncherAsTopWindow()
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun appLayerReplacesLauncher() {
+ // This test doesn't work in shell transitions because of b/206085788
+ assumeFalse(isShellTransitionsEnabled)
+ super.appLayerReplacesLauncher()
+ }
/** {@inheritDoc} */
@Presubmit
@Test
- override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ // This test doesn't work in shell transitions because of b/206090480
+ assumeFalse(isShellTransitionsEnabled)
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ /** {@inheritDoc} */
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
/** {@inheritDoc} */
@Presubmit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 08aaea70762f..3914ef6633b3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -28,9 +28,11 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.traces.common.FlickerComponentName
import com.google.common.truth.Truth
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -66,9 +68,9 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
/**
* Defines the transition used to run the test
*/
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
- get() = { args ->
- super.transition(this, args)
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ super.transition(this)
setup {
eachRun {
device.sleep()
@@ -89,16 +91,14 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
}
/**
- * Checks that the nav bar layer starts visible, becomes invisible during unlocking animation
- * and becomes visible at the end
+ * Checks that the nav bar layer starts invisible, becomes visible during unlocking animation
+ * and remains visible at the end
*/
@Postsubmit
@Test
fun navBarLayerVisibilityChanges() {
testSpec.assertLayers {
- this.isVisible(FlickerComponentName.NAV_BAR)
- .then()
- .isInvisible(FlickerComponentName.NAV_BAR)
+ this.isInvisible(FlickerComponentName.NAV_BAR)
.then()
.isVisible(FlickerComponentName.NAV_BAR)
}
@@ -108,7 +108,7 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
* Checks that the app layer doesn't exist at the start of the transition, that it is
* created (invisible) and becomes visible during the transition
*/
- @FlakyTest
+ @Postsubmit
@Test
fun appLayerBecomesVisible() {
testSpec.assertLayers {
@@ -151,26 +151,19 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
}
/**
- * Checks that the nav bar starts the transition visible, then becomes invisible during
- * then unlocking animation and becomes visible at the end of the transition
+ * Checks that the nav bar starts the transition invisible, then becomes visible during
+ * the unlocking animation and remains visible at the end of the transition
*/
@Postsubmit
@Test
fun navBarWindowsVisibilityChanges() {
testSpec.assertWm {
- this.isAboveAppWindowVisible(FlickerComponentName.NAV_BAR)
- .then()
- .isNonAppWindowInvisible(FlickerComponentName.NAV_BAR)
+ this.isNonAppWindowInvisible(FlickerComponentName.NAV_BAR)
.then()
.isAboveAppWindowVisible(FlickerComponentName.NAV_BAR)
}
}
- /** {@inheritDoc} */
- @FlakyTest
- @Test
- override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
-
/**
* Checks that the status bar layer is visible at the end of the trace
*
@@ -188,26 +181,26 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
/** {@inheritDoc} */
@FlakyTest(bugId = 202936526)
@Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+ override fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ super.statusBarLayerRotatesScales()
+ }
/** {@inheritDoc} */
@Presubmit
@Test
fun statusBarLayerPositionAtEnd() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
testSpec.assertLayersEnd {
val display = this.entry.displays.minByOrNull { it.id }
- ?: throw RuntimeException("There is no display!")
+ ?: error("There is no display!")
this.visibleRegion(FlickerComponentName.STATUS_BAR)
.coversExactly(WindowUtils.getStatusBarPosition(display))
}
}
- /** {@inheritDoc} */
- @FlakyTest
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
@@ -219,7 +212,7 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
super.visibleLayersShownMoreThanOneConsecutiveEntry()
/** {@inheritDoc} */
- @Postsubmit
+ @FlakyTest
@Test
override fun entireScreenCovered() = super.entireScreenCovered()
@@ -234,11 +227,11 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
* Checks that the screen is locked at the start of the transition ([colorFadComponent])
* layer is visible
*/
- @Postsubmit
+ @Presubmit
@Test
fun screenLockedStart() {
testSpec.assertLayersStart {
- isVisible(colorFadComponent)
+ isEmpty()
}
}
@@ -247,7 +240,7 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
* it cannot use the regular assertion (check over time), because on lock screen neither
* the app not the launcher are visible, and there is no top visible window.
*/
- @Postsubmit
+ @Presubmit
@Test
override fun appWindowReplacesLauncherAsTopWindow() {
testSpec.assertWm {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 7af7b3ab6f24..b5c81bb39ed4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -31,9 +31,7 @@ import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.replacesLayer
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
@@ -50,13 +48,11 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
/**
* Defines the transition used to run the test
*/
- protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
- withTestName { testSpec.name }
- repeat { testSpec.config.repetitions }
+ protected open val transition: FlickerBuilder.() -> Unit = {
setup {
test {
device.wakeUpAndGoToHomeScreen()
- this.setRotation(testSpec.config.startRotation)
+ this.setRotation(testSpec.startRotation)
}
}
teardown {
@@ -73,7 +69,7 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
- transition(testSpec.config)
+ transition()
}
}
@@ -170,7 +166,8 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
* is replaced by [testApp], which remains visible until the end
*/
open fun appLayerReplacesLauncher() {
- testSpec.replacesLayer(LAUNCHER_COMPONENT, testApp.component)
+ testSpec.replacesLayer(LAUNCHER_COMPONENT, testApp.component,
+ ignoreEntriesWithRotationLayer = true, ignoreSnapshot = true)
}
/**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 5edee0cf0ca0..4db01bf53833 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -24,8 +24,9 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -59,9 +60,9 @@ class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
/**
* Defines the transition used to run the test
*/
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this, it)
+ super.transition(this)
setup {
test {
testApp.launchViaIntent(wmHelper)
@@ -69,7 +70,7 @@ class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
eachRun {
device.pressHome()
wmHelper.waitForHomeActivityVisible()
- this.setRotation(testSpec.config.startRotation)
+ this.setRotation(testSpec.startRotation)
}
}
teardown {
@@ -84,6 +85,33 @@ class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
}
/** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ super.statusBarLayerRotatesScales()
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() {
+ // This test doesn't work in shell transitions because of b/206094140
+ assumeFalse(isShellTransitionsEnabled)
+ super.appWindowReplacesLauncherAsTopWindow()
+ }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ // This test doesn't work in shell transitions because of b/206094140
+ assumeFalse(isShellTransitionsEnabled)
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ /** {@inheritDoc} */
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 495e2d62a11d..769cb1ad959b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -33,8 +33,6 @@ import com.android.server.wm.flicker.helpers.NewTasksAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.flicker.testapp.ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME
@@ -71,8 +69,6 @@ class TaskTransitionTest(val testSpec: FlickerTestParameter) {
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
- withTestName { testSpec.name }
- repeat { testSpec.config.repetitions }
setup {
eachRun {
mTestApp.launchViaIntent(wmHelper)
@@ -149,7 +145,7 @@ class TaskTransitionTest(val testSpec: FlickerTestParameter) {
@Test
fun colorLayerIsVisibleDuringTransition() {
val bgColorLayer = FlickerComponentName("", "colorBackgroundLayer")
- val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
testSpec.assertLayers {
this.coversExactly(displayBounds, LAUNCH_NEW_TASK_ACTIVITY)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index 52904cce8772..0a64939cb4ca 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -18,6 +18,7 @@ package com.android.server.wm.flicker.quickswitch
import android.app.Instrumentation
import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresDevice
import android.view.Surface
import android.view.WindowManagerPolicyConstants
@@ -32,11 +33,9 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
@@ -68,7 +67,7 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
- private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
@@ -92,7 +91,7 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet
startDisplayBounds.bounds.bottom,
2 * startDisplayBounds.bounds.right / 3,
startDisplayBounds.bounds.bottom,
- if (testSpec.config.startRotation.isRotated()) 75 else 30
+ if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
)
wmHelper.waitForFullScreenApp(testApp1.component)
@@ -135,7 +134,7 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet
/**
* Checks that the transition starts with [testApp2] being the top window.
*/
- @Postsubmit
+ @Presubmit
@Test
fun startsWithApp2WindowBeingOnTop() {
testSpec.assertWmStart {
@@ -286,7 +285,7 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet
/**
* Checks that the navbar layer is visible throughout the entire transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun navBarLayerAlwaysIsVisible() = testSpec.navBarLayerIsVisible()
@@ -295,21 +294,21 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet
*
* NOTE: This doesn't check that the navbar is visible or not.
*/
- @Postsubmit
+ @Presubmit
@Test
fun navbarIsAlwaysInRightPosition() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks that the status bar window is visible throughout the entire transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsVisible()
/**
* Checks that the status bar layer is visible throughout the entire transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsVisible()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index 842aa2b548db..ded80a0b2509 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.quickswitch
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresDevice
import android.view.Surface
import android.view.WindowManagerPolicyConstants
@@ -32,12 +32,9 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
@@ -69,13 +66,11 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
- private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
- withTestName { testSpec.name }
- repeat { testSpec.config.repetitions }
setup {
eachRun {
testApp1.launchViaIntent(wmHelper)
@@ -93,7 +88,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
startDisplayBounds.bounds.bottom,
2 * startDisplayBounds.bounds.right / 3,
startDisplayBounds.bounds.bottom,
- if (testSpec.config.startRotation.isRotated()) 75 else 30
+ if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
)
wmHelper.waitForFullScreenApp(testApp1.component)
@@ -110,7 +105,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
startDisplayBounds.bounds.bottom,
startDisplayBounds.bounds.right / 3,
startDisplayBounds.bounds.bottom,
- if (testSpec.config.startRotation.isRotated()) 75 else 30
+ if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
)
wmHelper.waitForFullScreenApp(testApp2.component)
@@ -130,7 +125,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Checks that the transition starts with [testApp1]'s windows filling/covering exactly the
* entirety of the display.
*/
- @Postsubmit
+ @Presubmit
@Test
fun startsWithApp1WindowsCoverFullScreen() {
testSpec.assertWmStart {
@@ -142,7 +137,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Checks that the transition starts with [testApp1]'s layers filling/covering exactly the
* entirety of the display.
*/
- @Postsubmit
+ @Presubmit
@Test
fun startsWithApp1LayersCoverFullScreen() {
testSpec.assertLayersStart {
@@ -153,7 +148,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
/**
* Checks that the transition starts with [testApp1] being the top window.
*/
- @Postsubmit
+ @Presubmit
@Test
fun startsWithApp1WindowBeingOnTop() {
testSpec.assertWmStart {
@@ -165,7 +160,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Checks that [testApp2] windows fill the entire screen (i.e. is "fullscreen") at the end of the
* transition once we have fully quick switched from [testApp1] back to the [testApp2].
*/
- @Postsubmit
+ @Presubmit
@Test
fun endsWithApp2WindowsCoveringFullScreen() {
testSpec.assertWmEnd {
@@ -177,7 +172,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Checks that [testApp2] layers fill the entire screen (i.e. is "fullscreen") at the end of the
* transition once we have fully quick switched from [testApp1] back to the [testApp2].
*/
- @Postsubmit
+ @Presubmit
@Test
fun endsWithApp2LayersCoveringFullScreen() {
testSpec.assertLayersEnd {
@@ -189,7 +184,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Checks that [testApp2] is the top window at the end of the transition once we have fully quick
* switched from [testApp1] back to the [testApp2].
*/
- @Postsubmit
+ @Presubmit
@Test
fun endsWithApp2BeingOnTop() {
testSpec.assertWmEnd {
@@ -201,7 +196,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Checks that [testApp2]'s window starts off invisible and becomes visible at some point before
* the end of the transition and then stays visible until the end of the transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app2WindowBecomesAndStaysVisible() {
testSpec.assertWm {
@@ -217,7 +212,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Checks that [testApp2]'s layer starts off invisible and becomes visible at some point before
* the end of the transition and then stays visible until the end of the transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app2LayerBecomesAndStaysVisible() {
testSpec.assertLayers {
@@ -231,7 +226,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Checks that [testApp1]'s window starts off visible and becomes invisible at some point before
* the end of the transition and then stays invisible until the end of the transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app1WindowBecomesAndStaysInvisible() {
testSpec.assertWm {
@@ -245,7 +240,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Checks that [testApp1]'s layer starts off visible and becomes invisible at some point before
* the end of the transition and then stays invisible until the end of the transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app1LayerBecomesAndStaysInvisible() {
testSpec.assertLayers {
@@ -260,7 +255,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Ensures that at any point, either [testApp2] or [testApp1]'s windows are at least partially
* visible.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app2WindowIsVisibleOnceApp1WindowIsInvisible() {
testSpec.assertWm {
@@ -279,7 +274,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
* Ensures that at any point, either [testApp2] or [testApp1]'s windows are at least partially
* visible.
*/
- @Postsubmit
+ @Presubmit
@Test
fun app2LayerIsVisibleOnceApp1LayerIsInvisible() {
testSpec.assertLayers {
@@ -296,14 +291,14 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
/**
* Checks that the navbar window is visible throughout the entire transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsVisible()
/**
* Checks that the navbar layer is visible throughout the entire transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun navBarLayerAlwaysIsVisible() = testSpec.navBarLayerIsVisible()
@@ -312,21 +307,21 @@ class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestPara
*
* NOTE: This doesn't check that the navbar is visible or not.
*/
- @Postsubmit
+ @Presubmit
@Test
fun navbarIsAlwaysInRightPosition() = testSpec.navBarLayerRotatesAndScales()
/**
* Checks that the status bar window is visible throughout the entire transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsVisible()
/**
* Checks that the status bar layer is visible throughout the entire transition.
*/
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsVisible()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index 10ca0d9b323b..dcb5c86f32ad 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -35,7 +35,6 @@ import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
@@ -64,7 +63,7 @@ import org.junit.runners.Parameterized
class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = SimpleAppHelper(instrumentation)
- private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index fd8abc621b33..c18798f0a4b0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -26,11 +25,13 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.rules.WMFlickerServiceRuleForTestSpec
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Rule
import org.junit.Test
@@ -85,9 +86,9 @@ class ChangeAppRotationTest(
val flickerRule = WMFlickerServiceRuleForTestSpec(testSpec)
override val testApp = SimpleAppHelper(instrumentation)
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this, it)
+ super.transition(this)
setup {
test {
testApp.launchViaIntent(wmHelper)
@@ -95,13 +96,13 @@ class ChangeAppRotationTest(
}
}
- @Postsubmit
+ @FlakyTest
@Test
fun runPresubmitAssertion() {
flickerRule.checkPresubmitAssertions()
}
- @Postsubmit
+ @FlakyTest
@Test
fun runPostsubmitAssertion() {
flickerRule.checkPostsubmitAssertions()
@@ -113,11 +114,16 @@ class ChangeAppRotationTest(
flickerRule.checkFlakyAssertions()
}
- /** {@inheritDoc} */
+ /**
+ * Windows maybe recreated when rotated. Checks that the focus does not change or if it does,
+ * focus returns to [testApp]
+ */
@FlakyTest(bugId = 190185577)
@Test
- override fun focusDoesNotChange() {
- super.focusDoesNotChange()
+ fun focusChanges() {
+ testSpec.assertEventLog {
+ this.focusChanges(testApp.`package`)
+ }
}
/**
@@ -161,7 +167,11 @@ class ChangeAppRotationTest(
*/
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
+ fun statusBarLayerRotatesScales() {
+ // This test doesn't work in shell transitions because of b/206753786
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.statusBarLayerRotatesScales()
+ }
/** {@inheritDoc} */
@FlakyTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index e850632ed8af..d1bdeed81b78 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -22,14 +22,12 @@ import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.entireScreenCovered
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.traces.common.FlickerComponentName
import org.junit.Test
@@ -41,10 +39,10 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ protected open val transition: FlickerBuilder.() -> Unit = {
setup {
eachRun {
- this.setRotation(testSpec.config.startRotation)
+ this.setRotation(testSpec.startRotation)
}
}
teardown {
@@ -53,7 +51,7 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
}
}
transitions {
- this.setRotation(testSpec.config.endRotation)
+ this.setRotation(testSpec.endRotation)
}
}
@@ -64,7 +62,7 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
- transition(testSpec.config)
+ transition()
}
}
@@ -131,17 +129,6 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
open fun entireScreenCovered() = testSpec.entireScreenCovered()
/**
- * Checks that the focus doesn't change during animation
- */
- @Presubmit
- @Test
- open fun focusDoesNotChange() {
- testSpec.assertEventLog {
- this.focusDoesNotChange()
- }
- }
-
- /**
* Checks that [testApp] layer covers the entire screen at the start of the transition
*/
@Presubmit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 310f04b9710f..e44bee644ceb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -26,8 +26,10 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -81,14 +83,14 @@ class SeamlessAppRotationTest(
) : RotationTransition(testSpec) {
override val testApp = SeamlessRotationAppHelper(instrumentation)
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ override val transition: FlickerBuilder.() -> Unit
get() = {
- super.transition(this, it)
+ super.transition(this)
setup {
test {
testApp.launchViaIntent(wmHelper,
- stringExtras = mapOf(
- ActivityOptions.EXTRA_STARVE_UI_THREAD to it.starveUiThread.toString())
+ stringExtras = mapOf(ActivityOptions.EXTRA_STARVE_UI_THREAD
+ to testSpec.starveUiThread.toString())
)
}
}
@@ -100,6 +102,8 @@ class SeamlessAppRotationTest(
@Presubmit
@Test
fun appWindowFullScreen() {
+ // This test doesn't work in shell transitions because of b/206101151
+ assumeFalse(isShellTransitionsEnabled)
testSpec.assertWm {
this.invoke("isFullScreen") {
val appWindow = it.windowState(testApp.`package`)
@@ -135,6 +139,8 @@ class SeamlessAppRotationTest(
@Presubmit
@Test
fun appLayerAlwaysVisible() {
+ // This test doesn't work in shell transitions because of b/206101151
+ assumeFalse(isShellTransitionsEnabled)
testSpec.assertLayers {
isVisible(testApp.component)
}
@@ -146,6 +152,8 @@ class SeamlessAppRotationTest(
@Presubmit
@Test
fun appLayerRotates() {
+ // This test doesn't work in shell transitions because of b/206101151
+ assumeFalse(isShellTransitionsEnabled)
testSpec.assertLayers {
this.invoke("entireScreenCovered") { entry ->
entry.entry.displays.map { display ->
@@ -179,21 +187,36 @@ class SeamlessAppRotationTest(
}
}
+ /**
+ * Checks that the focus doesn't change during animation
+ */
+ @Presubmit
+ @Test
+ fun focusDoesNotChange() {
+ // This test doesn't work in shell transitions because of b/206101151
+ assumeFalse(isShellTransitionsEnabled)
+ testSpec.assertEventLog {
+ this.focusDoesNotChange()
+ }
+ }
+
/** {@inheritDoc} */
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
companion object {
- private val Map<String, Any?>.starveUiThread
- get() = this.getOrDefault(ActivityOptions.EXTRA_STARVE_UI_THREAD, false) as Boolean
+ private val FlickerTestParameter.starveUiThread
+ get() = config.getOrDefault(ActivityOptions.EXTRA_STARVE_UI_THREAD, false) as Boolean
- private fun FlickerTestParameter.createConfig(
+ private fun createConfig(
+ sourceConfig: FlickerTestParameter,
starveUiThread: Boolean
- ): MutableMap<String, Any?> {
- val config = this.config.toMutableMap()
- config[ActivityOptions.EXTRA_STARVE_UI_THREAD] = starveUiThread
- return config
+ ): FlickerTestParameter {
+ val newConfig = sourceConfig.config.toMutableMap()
+ .also { it[ActivityOptions.EXTRA_STARVE_UI_THREAD] = starveUiThread }
+ val nameExt = if (starveUiThread) "_BUSY_UI_THREAD" else ""
+ return FlickerTestParameter(newConfig, nameOverride = "$sourceConfig$nameExt")
}
/**
@@ -206,15 +229,10 @@ class SeamlessAppRotationTest(
private fun getConfigurations(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigRotationTests(repetitions = 2)
- .flatMap {
- val defaultRun = it.createConfig(starveUiThread = false)
- val busyUiRun = it.createConfig(starveUiThread = true)
- listOf(
- FlickerTestParameter(defaultRun),
- FlickerTestParameter(busyUiRun,
- name = "${FlickerTestParameter.defaultName(busyUiRun)}_BUSY_UI_THREAD"
- )
- )
+ .flatMap { sourceConfig ->
+ val defaultRun = createConfig(sourceConfig, starveUiThread = false)
+ val busyUiRun = createConfig(sourceConfig, starveUiThread = true)
+ listOf(defaultRun, busyUiRun)
}
}
diff --git a/tests/HwAccelerationTest/Android.bp b/tests/HwAccelerationTest/Android.bp
index 76063227eac1..e618ed1e3ab9 100644
--- a/tests/HwAccelerationTest/Android.bp
+++ b/tests/HwAccelerationTest/Android.bp
@@ -25,7 +25,13 @@ package {
android_test {
name: "HwAccelerationTest",
- srcs: ["**/*.java"],
+ jni_libs: [
+ "libhwaccelerationtest_jni",
+ ],
+ srcs: [
+ "**/*.java",
+ "**/*.kt",
+ ],
platform_apis: true,
certificate: "platform",
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 04a55d6038b0..22fe4242fbbb 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -436,6 +436,15 @@
</intent-filter>
</activity>
+ <activity android:name=".PenStylusActivity"
+ android:label="Pen/Draw"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
<activity android:name="GLTextureViewActivity"
android:label="TextureView/OpenGL"
android:exported="true">
diff --git a/tests/HwAccelerationTest/jni/Android.bp b/tests/HwAccelerationTest/jni/Android.bp
new file mode 100644
index 000000000000..8edddab0ad1f
--- /dev/null
+++ b/tests/HwAccelerationTest/jni/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2021 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test_library {
+
+ name: "libhwaccelerationtest_jni",
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ ],
+
+ gtest: false,
+
+ srcs: [
+ "native-lib.cpp",
+ ],
+
+ shared_libs: [
+ "libnativehelper",
+ "libandroid",
+ "liblog",
+ ],
+
+ stl: "c++_static",
+
+ sdk_version: "current",
+
+}
diff --git a/tests/HwAccelerationTest/jni/native-lib.cpp b/tests/HwAccelerationTest/jni/native-lib.cpp
new file mode 100644
index 000000000000..407d4bf76336
--- /dev/null
+++ b/tests/HwAccelerationTest/jni/native-lib.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <android/hardware_buffer.h>
+#include <android/hardware_buffer_jni.h>
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+#include <android/surface_control.h>
+#include <jni.h>
+
+struct MyWrapper {
+ MyWrapper(ANativeWindow* parent) {
+ surfaceControl = ASurfaceControl_createFromWindow(parent, "PenLayer");
+ }
+
+ ~MyWrapper() { ASurfaceControl_release(surfaceControl); }
+
+ void setBuffer(AHardwareBuffer* buffer) {
+ ASurfaceTransaction* transaction = ASurfaceTransaction_create();
+ ASurfaceTransaction_setBuffer(transaction, surfaceControl, buffer);
+ ASurfaceTransaction_setVisibility(transaction, surfaceControl,
+ ASURFACE_TRANSACTION_VISIBILITY_SHOW);
+ ASurfaceTransaction_apply(transaction);
+ ASurfaceTransaction_delete(transaction);
+ }
+
+ ASurfaceControl* surfaceControl = nullptr;
+};
+
+extern "C" JNIEXPORT jlong JNICALL
+Java_com_android_test_hwui_FrontBufferedLayer_nCreate(JNIEnv* env, jclass, jobject jSurface) {
+ ANativeWindow* window = ANativeWindow_fromSurface(env, jSurface);
+ MyWrapper* wrapper = new MyWrapper(window);
+ ANativeWindow_release(window);
+ return reinterpret_cast<jlong>(wrapper);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_com_android_test_hwui_FrontBufferedLayer_nDestroy(JNIEnv*, jclass, jlong ptr) {
+ MyWrapper* wrapper = reinterpret_cast<MyWrapper*>(ptr);
+ delete wrapper;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_com_android_test_hwui_FrontBufferedLayer_nUpdateBuffer(
+ JNIEnv* env, jclass, jlong ptr, jobject jbuffer) {
+ MyWrapper* wrapper = reinterpret_cast<MyWrapper*>(ptr);
+ AHardwareBuffer* buffer = AHardwareBuffer_fromHardwareBuffer(env, jbuffer);
+ wrapper->setBuffer(buffer);
+} \ No newline at end of file
diff --git a/tests/HwAccelerationTest/res/layout/pen_stylus.xml b/tests/HwAccelerationTest/res/layout/pen_stylus.xml
new file mode 100644
index 000000000000..37aafed208fb
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/pen_stylus.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+<com.android.test.hwui.FrontBufferedLayer
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+/> \ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index c06f8fd44c03..46d3a3d669c0 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -63,7 +63,7 @@ public class ColorFiltersMutateActivity extends Activity {
"uniform shader bitmapShader;\n"
+ "uniform float param1;\n"
+ "half4 main(float2 xy) {\n"
- + " return half4(sample(bitmapShader, xy).rgb, param1);\n"
+ + " return half4(bitmapShader.eval(xy).rgb, param1);\n"
+ "}\n";
BitmapsView(Context c) {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
index 7ea2a62d7494..d4bc2a6d3317 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
@@ -42,7 +42,7 @@ public class ColoredRectsActivity extends Activity {
swView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
frame.addView(swView);
final RectsView hwBothView = new RectsView(this, 850, Color.GREEN);
- // Don't actually need to render to a hw layer, but it's a good sanity-check that
+ // Don't actually need to render to a hw layer, but it's a good check that
// we're rendering to/from layers correctly
hwBothView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
frame.addView(hwBothView);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/FrontBufferedLayer.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/FrontBufferedLayer.kt
new file mode 100644
index 000000000000..ebec22e29d69
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/FrontBufferedLayer.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2021 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.test.hwui
+
+import android.content.Context
+import android.graphics.BlendMode
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Rect
+import android.hardware.HardwareBuffer
+import android.util.AttributeSet
+import android.view.InputDevice
+import android.view.MotionEvent
+import android.view.Surface
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import android.view.WindowInsets
+import android.view.WindowInsetsController
+
+class FrontBufferedLayer : SurfaceView, SurfaceHolder.Callback {
+ var mRenderer: PenStylusActivity.SingleBufferedCanvas? = null
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ init {
+ holder.addCallback(this)
+ setZOrderOnTop(true)
+ }
+
+ override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
+ nDestroy(mNativePtr)
+ mNativePtr = nCreate(holder.surface)
+ mRenderer = PenStylusActivity.SingleBufferedCanvas(width, height)
+ clearOverlay()
+
+ if ((false)) {
+ val canvas = holder.lockCanvas()
+ canvas.drawColor(Color.LTGRAY)
+ holder.unlockCanvasAndPost(canvas)
+ }
+ }
+
+ override fun surfaceDestroyed(holder: SurfaceHolder) {
+ mRenderer = null
+ nDestroy(mNativePtr)
+ mNativePtr = 0
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ requestUnbufferedDispatch(InputDevice.SOURCE_CLASS_POINTER)
+ this.windowInsetsController?.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT)
+ this.windowInsetsController?.hide(WindowInsets.Type.navigationBars())
+ this.windowInsetsController?.hide(WindowInsets.Type.statusBars())
+ }
+
+ private fun clearOverlay() {
+ mRenderer?.let {
+ it.update(null) {
+ drawColor(Color.WHITE, BlendMode.SRC)
+ }
+ nUpdateBuffer(mNativePtr, it.mHardwareBuffer)
+ }
+ }
+
+ private var prevX: Float = 0f
+ private var prevY: Float = 0f
+ private val paint = Paint().also {
+ it.color = Color.BLACK
+ it.strokeWidth = 10f
+ it.isAntiAlias = true
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ if (!event.isFromSource(InputDevice.SOURCE_STYLUS)) {
+ if (event.action == MotionEvent.ACTION_DOWN) {
+ clearOverlay()
+ }
+ return true
+ }
+ val action = event.actionMasked
+ if (action == MotionEvent.ACTION_DOWN ||
+ action == MotionEvent.ACTION_MOVE) {
+ mRenderer?.let {
+ val left = minOf(prevX, event.x).toInt() - 10
+ val top = minOf(prevY, event.y).toInt() - 10
+ val right = maxOf(prevX, event.x).toInt() + 10
+ val bottom = maxOf(prevY, event.y).toInt() + 10
+ it.update(Rect(left, top, right, bottom)) {
+ if (action == MotionEvent.ACTION_MOVE) {
+ drawLine(prevX, prevY, event.x, event.y, paint)
+ }
+ drawCircle(event.x, event.y, 5f, paint)
+ }
+ nUpdateBuffer(mNativePtr, it.mHardwareBuffer)
+ }
+ prevX = event.x
+ prevY = event.y
+ }
+ return true
+ }
+
+ private var mNativePtr: Long = 0
+
+ private external fun nCreate(surface: Surface): Long
+ private external fun nDestroy(ptr: Long)
+ private external fun nUpdateBuffer(ptr: Long, buffer: HardwareBuffer)
+
+ companion object {
+ init {
+ System.loadLibrary("hwaccelerationtest_jni")
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
index 7173a85f73e7..584ab596836c 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
@@ -42,7 +42,7 @@ public class Lines2Activity extends Activity {
swView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
frame.addView(swView);
final LinesView hwBothView = new LinesView(this, 850, Color.GREEN);
- // Don't actually need to render to a hw layer, but it's a good sanity-check that
+ // Don't actually need to render to a hw layer, but it's a good check that
// we're rendering to/from layers correctly
hwBothView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
frame.addView(hwBothView);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PenStylusActivity.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/PenStylusActivity.kt
new file mode 100644
index 000000000000..1445b1db801e
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PenStylusActivity.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 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.test.hwui
+
+import android.app.Activity
+import android.os.Bundle
+import android.hardware.HardwareBuffer
+import android.graphics.Canvas
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.media.ImageReader
+import android.view.Surface
+import java.lang.IllegalArgumentException
+
+const val USAGE_HWC = 0x800L
+
+class PenStylusActivity : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(FrontBufferedLayer(this))
+ }
+
+ class SingleBufferedCanvas : AutoCloseable {
+ val mHardwareBuffer: HardwareBuffer
+ private var mCanvas: Canvas?
+ private val mImageReader: ImageReader
+ private val mSurface: Surface
+
+ constructor(width: Int, height: Int) {
+ mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 1,
+ HardwareBuffer.USAGE_CPU_READ_RARELY or HardwareBuffer.USAGE_CPU_WRITE_RARELY or
+ HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or USAGE_HWC)
+
+ mSurface = mImageReader.surface
+ mSurface.unlockCanvasAndPost(mSurface.lockCanvas(null))
+ val image = mImageReader.acquireNextImage()
+ mHardwareBuffer = image.hardwareBuffer!!
+ image.close()
+ mCanvas = mSurface.lockCanvas(null)
+ }
+
+ fun lockCanvas(rect: Rect?): Canvas {
+ if (mCanvas != null) {
+ unlockCanvas(mCanvas!!)
+ }
+ mCanvas = mSurface.lockCanvas(rect)
+ return mCanvas!!
+ }
+
+ fun unlockCanvas(canvas: Canvas) {
+ if (this.mCanvas !== canvas) throw IllegalArgumentException()
+ mSurface.unlockCanvasAndPost(canvas)
+ this.mCanvas = null
+ mImageReader.acquireNextImage().close()
+ }
+
+ inline fun update(area: Rect?, func: Canvas.() -> Unit) {
+ val canvas = lockCanvas(area)
+ func(canvas)
+ unlockCanvas(canvas)
+ }
+
+ override fun close() {
+ mHardwareBuffer.close()
+ mSurface.unlockCanvasAndPost(mCanvas)
+ mImageReader.close()
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
index d925541c76d6..83e2de925ceb 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
@@ -91,7 +91,7 @@ public class RippleActivity extends Activity {
+ " d = rand(float2(x, y)) > density ? d : d * .2;\n"
+ " d = d * rand(float2(fraction, x * y));\n"
+ " float alpha = 1. - pow(fraction, 3.);\n"
- + " return float4(sample(in_paintColor, p).rgb, d * alpha);\n"
+ + " return float4(in_paintColor.eval(p).rgb, d * alpha);\n"
+ "}";
RippleView(Context c) {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
index 3307c36d9d1a..fcdee63a99a8 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
@@ -532,6 +532,6 @@ public class StretchShaderActivity extends Activity {
+ " uv.y = outV;\n"
+ " coord.x = uv.x * viewportWidth;\n"
+ " coord.y = uv.y * viewportHeight;\n"
- + " return sample(uContentTexture, coord);\n"
+ + " return uContentTexture.eval(coord);\n"
+ "}";
}
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index eacf5b287a2e..de9bbb6ef9fa 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -18,6 +18,8 @@ android_test {
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
+ "services.core.unboosted",
+ "testables",
"truth-prebuilt",
"ub-uiautomator",
],
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
index 4da3eca25ea0..1d65cc35c3bc 100644
--- a/tests/Input/src/com/android/test/input/AnrTest.kt
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -19,7 +19,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.filters.MediumTest
+import android.app.ActivityManager
+import android.app.ApplicationExitInfo
import android.graphics.Rect
+import android.os.Build
+import android.os.IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS
import android.os.SystemClock
import android.provider.Settings
import android.provider.Settings.Global.HIDE_ERROR_DIALOGS
@@ -27,10 +31,13 @@ import android.support.test.uiautomator.By
import android.support.test.uiautomator.UiDevice
import android.support.test.uiautomator.UiObject2
import android.support.test.uiautomator.Until
+import android.testing.PollingCheck
import android.view.InputDevice
import android.view.MotionEvent
import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Before
import org.junit.Test
@@ -51,28 +58,99 @@ import org.junit.runner.RunWith
class AnrTest {
companion object {
private const val TAG = "AnrTest"
+ private const val ALL_PIDS = 0
+ private const val NO_MAX = 0
}
- val mInstrumentation = InstrumentationRegistry.getInstrumentation()
- var mHideErrorDialogs = 0
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private var hideErrorDialogs = 0
+ private lateinit var PACKAGE_NAME: String
+ private val DISPATCHING_TIMEOUT = (UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
+ Build.HW_TIMEOUT_MULTIPLIER)
@Before
fun setUp() {
- val contentResolver = mInstrumentation.targetContext.contentResolver
- mHideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ val contentResolver = instrumentation.targetContext.contentResolver
+ hideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ PACKAGE_NAME = UnresponsiveGestureMonitorActivity::class.java.getPackage().getName()
}
@After
fun tearDown() {
- val contentResolver = mInstrumentation.targetContext.contentResolver
- Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, mHideErrorDialogs)
+ val contentResolver = instrumentation.targetContext.contentResolver
+ Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, hideErrorDialogs)
}
@Test
- fun testGestureMonitorAnr() {
+ fun testGestureMonitorAnr_Close() {
+ triggerAnr()
+ clickCloseAppOnAnrDialog()
+ }
+
+ @Test
+ fun testGestureMonitorAnr_Wait() {
+ triggerAnr()
+ clickWaitOnAnrDialog()
+ SystemClock.sleep(500) // Wait at least 500ms after tapping on wait
+ // ANR dialog should reappear after a delay - find the close button on it to verify
+ clickCloseAppOnAnrDialog()
+ }
+
+ private fun clickCloseAppOnAnrDialog() {
+ // Find anr dialog and kill app
+ val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
+ val closeAppButton: UiObject2? =
+ uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
+ if (closeAppButton == null) {
+ fail("Could not find anr dialog")
+ return
+ }
+ val initialReasons = getExitReasons()
+ closeAppButton.click()
+ /**
+ * We must wait for the app to be fully closed before exiting this test. This is because
+ * another test may again invoke 'am start' for the same activity.
+ * If the 1st process that got ANRd isn't killed by the time second 'am start' runs,
+ * the killing logic will apply to the newly launched 'am start' instance, and the second
+ * test will fail because the unresponsive activity will never be launched.
+ */
+ waitForNewExitReason(initialReasons[0].timestamp)
+ }
+
+ private fun clickWaitOnAnrDialog() {
+ // Find anr dialog and tap on wait
+ val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
+ val waitButton: UiObject2? =
+ uiDevice.wait(Until.findObject(By.res("android:id/aerr_wait")), 20000)
+ if (waitButton == null) {
+ fail("Could not find anr dialog/wait button")
+ return
+ }
+ waitButton.click()
+ }
+
+ private fun getExitReasons(): List<ApplicationExitInfo> {
+ lateinit var infos: List<ApplicationExitInfo>
+ instrumentation.runOnMainSync {
+ val am = instrumentation.getContext().getSystemService(ActivityManager::class.java)
+ infos = am.getHistoricalProcessExitReasons(PACKAGE_NAME, ALL_PIDS, NO_MAX)
+ }
+ return infos
+ }
+
+ private fun waitForNewExitReason(previousExitTimestamp: Long) {
+ PollingCheck.waitFor {
+ getExitReasons()[0].timestamp > previousExitTimestamp
+ }
+ val reasons = getExitReasons()
+ assertTrue(reasons[0].timestamp > previousExitTimestamp)
+ assertEquals(ApplicationExitInfo.REASON_ANR, reasons[0].reason)
+ }
+
+ private fun triggerAnr() {
startUnresponsiveActivity()
- val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+ val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
val obj: UiObject2? = uiDevice.wait(Until.findObject(
By.text("Unresponsive gesture monitor")), 10000)
@@ -87,29 +165,14 @@ class AnrTest {
MotionEvent.ACTION_DOWN, rect.left.toFloat(), rect.top.toFloat(), 0 /* metaState */)
downEvent.source = InputDevice.SOURCE_TOUCHSCREEN
- mInstrumentation.uiAutomation.injectInputEvent(downEvent, false /* sync*/)
-
- // Todo: replace using timeout from android.hardware.input.IInputManager
- SystemClock.sleep(5000) // default ANR timeout for gesture monitors
-
- clickCloseAppOnAnrDialog()
- }
+ instrumentation.uiAutomation.injectInputEvent(downEvent, false /* sync*/)
- private fun clickCloseAppOnAnrDialog() {
- // Find anr dialog and kill app
- val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
- val closeAppButton: UiObject2? =
- uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
- if (closeAppButton == null) {
- fail("Could not find anr dialog")
- return
- }
- closeAppButton.click()
+ SystemClock.sleep(DISPATCHING_TIMEOUT.toLong()) // default ANR timeout for gesture monitors
}
private fun startUnresponsiveActivity() {
val flags = " -W -n "
- val startCmd = "am start $flags com.android.test.input/.UnresponsiveGestureMonitorActivity"
- mInstrumentation.uiAutomation.executeShellCommand(startCmd)
+ val startCmd = "am start $flags $PACKAGE_NAME/.UnresponsiveGestureMonitorActivity"
+ instrumentation.uiAutomation.executeShellCommand(startCmd)
}
-} \ No newline at end of file
+}
diff --git a/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
index 014efc2b954c..37b67f4c183c 100644
--- a/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
+++ b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
@@ -17,16 +17,11 @@
package com.android.test.input
import android.os.HandlerThread
-import android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS
import android.os.Looper
import android.view.InputChannel
import android.view.InputEvent
import android.view.InputEventReceiver
-import android.view.InputEventSender
import android.view.KeyEvent
-import android.view.MotionEvent
-import java.util.concurrent.LinkedBlockingQueue
-import java.util.concurrent.TimeUnit
import org.junit.Assert.assertEquals
import org.junit.After
import org.junit.Before
@@ -46,54 +41,19 @@ private fun assertKeyEvent(expected: KeyEvent, received: KeyEvent) {
assertEquals(expected.displayId, received.displayId)
}
-private fun <T> getEvent(queue: LinkedBlockingQueue<T>): T {
- try {
- return queue.poll(DEFAULT_DISPATCHING_TIMEOUT_MILLIS.toLong(), TimeUnit.MILLISECONDS)
- } catch (e: InterruptedException) {
- throw RuntimeException("Unexpectedly interrupted while waiting for event")
- }
+private fun getTestKeyEvent(): KeyEvent {
+ return KeyEvent(1 /*downTime*/, 1 /*eventTime*/, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_A, 0 /*repeat*/)
}
-class TestInputEventReceiver(channel: InputChannel, looper: Looper) :
+private class CrashingInputEventReceiver(channel: InputChannel, looper: Looper) :
InputEventReceiver(channel, looper) {
- private val mInputEvents = LinkedBlockingQueue<InputEvent>()
-
override fun onInputEvent(event: InputEvent) {
- when (event) {
- is KeyEvent -> mInputEvents.put(KeyEvent.obtain(event))
- is MotionEvent -> mInputEvents.put(MotionEvent.obtain(event))
- else -> throw Exception("Received $event is neither a key nor a motion")
+ try {
+ throw IllegalArgumentException("This receiver crashes when it receives input event")
+ } finally {
+ finishInputEvent(event, true /*handled*/)
}
- finishInputEvent(event, true /*handled*/)
- }
-
- fun getInputEvent(): InputEvent {
- return getEvent(mInputEvents)
- }
-}
-
-class TestInputEventSender(channel: InputChannel, looper: Looper) :
- InputEventSender(channel, looper) {
- data class FinishedSignal(val seq: Int, val handled: Boolean)
- data class Timeline(val inputEventId: Int, val gpuCompletedTime: Long, val presentTime: Long)
-
- private val mFinishedSignals = LinkedBlockingQueue<FinishedSignal>()
- private val mTimelines = LinkedBlockingQueue<Timeline>()
-
- override fun onInputEventFinished(seq: Int, handled: Boolean) {
- mFinishedSignals.put(FinishedSignal(seq, handled))
- }
-
- override fun onTimelineReported(inputEventId: Int, gpuCompletedTime: Long, presentTime: Long) {
- mTimelines.put(Timeline(inputEventId, gpuCompletedTime, presentTime))
- }
-
- fun getFinishedSignal(): FinishedSignal {
- return getEvent(mFinishedSignals)
- }
-
- fun getTimeline(): Timeline {
- return getEvent(mTimelines)
}
}
@@ -102,8 +62,8 @@ class InputEventSenderAndReceiverTest {
private const val TAG = "InputEventSenderAndReceiverTest"
}
private val mHandlerThread = HandlerThread("Process input events")
- private lateinit var mReceiver: TestInputEventReceiver
- private lateinit var mSender: TestInputEventSender
+ private lateinit var mReceiver: SpyInputEventReceiver
+ private lateinit var mSender: SpyInputEventSender
@Before
fun setUp() {
@@ -111,8 +71,8 @@ class InputEventSenderAndReceiverTest {
mHandlerThread.start()
val looper = mHandlerThread.getLooper()
- mSender = TestInputEventSender(channels[0], looper)
- mReceiver = TestInputEventReceiver(channels[1], looper)
+ mSender = SpyInputEventSender(channels[0], looper)
+ mReceiver = SpyInputEventReceiver(channels[1], looper)
}
@After
@@ -122,8 +82,7 @@ class InputEventSenderAndReceiverTest {
@Test
fun testSendAndReceiveKey() {
- val key = KeyEvent(1 /*downTime*/, 1 /*eventTime*/, KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_A, 0 /*repeat*/)
+ val key = getTestKeyEvent()
val seq = 10
mSender.sendInputEvent(seq, key)
val receivedKey = mReceiver.getInputEvent() as KeyEvent
@@ -133,13 +92,13 @@ class InputEventSenderAndReceiverTest {
assertKeyEvent(key, receivedKey)
// Check sender
- assertEquals(TestInputEventSender.FinishedSignal(seq, handled = true), finishedSignal)
+ assertEquals(SpyInputEventSender.FinishedSignal(seq, handled = true), finishedSignal)
}
// The timeline case is slightly unusual because it goes from InputConsumer to InputPublisher.
@Test
fun testSendAndReceiveTimeline() {
- val sent = TestInputEventSender.Timeline(
+ val sent = SpyInputEventSender.Timeline(
inputEventId = 1, gpuCompletedTime = 2, presentTime = 3)
mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime)
val received = mSender.getTimeline()
@@ -151,7 +110,7 @@ class InputEventSenderAndReceiverTest {
// event processing.
@Test
fun testSendAndReceiveInvalidTimeline() {
- val sent = TestInputEventSender.Timeline(
+ val sent = SpyInputEventSender.Timeline(
inputEventId = 1, gpuCompletedTime = 3, presentTime = 2)
mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime)
val received = mSender.getTimeline()
@@ -162,4 +121,41 @@ class InputEventSenderAndReceiverTest {
val receivedSecondTimeline = mSender.getTimeline()
assertEquals(null, receivedSecondTimeline)
}
+
+ /**
+ * If a receiver throws an exception during 'onInputEvent' execution, the 'finally' block still
+ * completes, and therefore, finishInputEvent is called. Make sure that there's no crash in the
+ * native layer in these circumstances.
+ * In this test, we are reusing the 'mHandlerThread', but we are creating new sender and
+ * receiver.
+ */
+ @Test
+ fun testCrashingReceiverDoesNotCrash() {
+ val channels = InputChannel.openInputChannelPair("TestChannel2")
+ val sender = SpyInputEventSender(channels[0], mHandlerThread.getLooper())
+
+ // Need a separate thread for the receiver so that the sender can still get the response
+ // after the receiver crashes
+ val receiverThread = HandlerThread("Receive input events")
+ receiverThread.start()
+ val crashingReceiver = CrashingInputEventReceiver(channels[1], receiverThread.getLooper())
+ receiverThread.setUncaughtExceptionHandler { thread, exception ->
+ if (thread == receiverThread && exception is IllegalArgumentException) {
+ // do nothing - this is the exception that we need to ignore
+ } else {
+ throw exception
+ }
+ }
+
+ val key = getTestKeyEvent()
+ val seq = 11
+ sender.sendInputEvent(seq, key)
+ val finishedSignal = sender.getFinishedSignal()
+ assertEquals(SpyInputEventSender.FinishedSignal(seq, handled = true), finishedSignal)
+
+ // Clean up
+ crashingReceiver.dispose()
+ sender.dispose()
+ receiverThread.quitSafely()
+ }
}
diff --git a/tests/Input/src/com/android/test/input/PointerEventDispatcherTest.kt b/tests/Input/src/com/android/test/input/PointerEventDispatcherTest.kt
new file mode 100644
index 000000000000..1099878a1954
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/PointerEventDispatcherTest.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 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.test.input
+
+import android.os.HandlerThread
+import android.view.InputChannel
+import android.view.InputDevice
+import android.view.MotionEvent
+import android.view.WindowManagerPolicyConstants.PointerEventListener
+
+import com.android.server.UiThread
+import com.android.server.wm.PointerEventDispatcher
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+
+private class CrashingPointerEventListener : PointerEventListener {
+ override fun onPointerEvent(motionEvent: MotionEvent) {
+ throw IllegalArgumentException("This listener crashes when input event occurs")
+ }
+}
+
+class PointerEventDispatcherTest {
+ companion object {
+ private const val TAG = "PointerEventDispatcherTest"
+ }
+ private val mHandlerThread = HandlerThread("Process input events")
+ private lateinit var mSender: SpyInputEventSender
+ private lateinit var mPointerEventDispatcher: PointerEventDispatcher
+ private val mListener = CrashingPointerEventListener()
+
+ @Before
+ fun setUp() {
+ val channels = InputChannel.openInputChannelPair("TestChannel")
+
+ mHandlerThread.start()
+ val looper = mHandlerThread.getLooper()
+ mSender = SpyInputEventSender(channels[0], looper)
+
+ mPointerEventDispatcher = PointerEventDispatcher(channels[1])
+ mPointerEventDispatcher.registerInputEventListener(mListener)
+ }
+
+ @After
+ fun tearDown() {
+ mHandlerThread.quitSafely()
+ }
+
+ @Test
+ fun testSendMotionToCrashingListenerDoesNotCrash() {
+ // The exception will occur on the UiThread, so we can't catch it here on the test thread
+ UiThread.get().setUncaughtExceptionHandler { thread, exception ->
+ if (thread == UiThread.get() && exception is IllegalArgumentException) {
+ // do nothing - this is the exception that we need to ignore
+ } else {
+ throw exception
+ }
+ }
+
+ // The MotionEvent properties aren't important for this test, as long as the event
+ // is a pointer event, so that it gets processed by CrashingPointerEventListener
+ val downTime = 0L
+ val motionEvent = MotionEvent.obtain(downTime, downTime,
+ MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */, 0 /* metaState */)
+ motionEvent.source = InputDevice.SOURCE_TOUCHSCREEN
+ val seq = 10
+ mSender.sendInputEvent(seq, motionEvent)
+ val finishedSignal = mSender.getFinishedSignal()
+
+ // Since the listener raises an exception during the event handling, the event should be
+ // marked as 'not handled'.
+ assertEquals(SpyInputEventSender.FinishedSignal(seq, handled = false), finishedSignal)
+ // Ensure that there aren't double finish calls. This would crash if there's a call
+ // to finish twice.
+ assertNull(mSender.getFinishedSignal())
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/SpyInputEventSenderAndReceiver.kt b/tests/Input/src/com/android/test/input/SpyInputEventSenderAndReceiver.kt
new file mode 100644
index 000000000000..2d9af9a65d33
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/SpyInputEventSenderAndReceiver.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 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.test.input
+
+import android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS
+import android.os.Looper
+import android.view.InputChannel
+import android.view.InputEvent
+import android.view.InputEventReceiver
+import android.view.InputEventSender
+import android.view.KeyEvent
+import android.view.MotionEvent
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
+
+private fun <T> getEvent(queue: LinkedBlockingQueue<T>): T? {
+ return queue.poll(DEFAULT_DISPATCHING_TIMEOUT_MILLIS.toLong(), TimeUnit.MILLISECONDS)
+}
+
+class SpyInputEventReceiver(channel: InputChannel, looper: Looper) :
+ InputEventReceiver(channel, looper) {
+ private val mInputEvents = LinkedBlockingQueue<InputEvent>()
+
+ override fun onInputEvent(event: InputEvent) {
+ when (event) {
+ is KeyEvent -> mInputEvents.put(KeyEvent.obtain(event))
+ is MotionEvent -> mInputEvents.put(MotionEvent.obtain(event))
+ else -> throw Exception("Received $event is neither a key nor a motion")
+ }
+ finishInputEvent(event, true /*handled*/)
+ }
+
+ fun getInputEvent(): InputEvent? {
+ return getEvent(mInputEvents)
+ }
+}
+
+class SpyInputEventSender(channel: InputChannel, looper: Looper) :
+ InputEventSender(channel, looper) {
+ data class FinishedSignal(val seq: Int, val handled: Boolean)
+ data class Timeline(val inputEventId: Int, val gpuCompletedTime: Long, val presentTime: Long)
+
+ private val mFinishedSignals = LinkedBlockingQueue<FinishedSignal>()
+ private val mTimelines = LinkedBlockingQueue<Timeline>()
+
+ override fun onInputEventFinished(seq: Int, handled: Boolean) {
+ mFinishedSignals.put(FinishedSignal(seq, handled))
+ }
+
+ override fun onTimelineReported(inputEventId: Int, gpuCompletedTime: Long, presentTime: Long) {
+ mTimelines.put(Timeline(inputEventId, gpuCompletedTime, presentTime))
+ }
+
+ fun getFinishedSignal(): FinishedSignal? {
+ return getEvent(mFinishedSignals)
+ }
+
+ fun getTimeline(): Timeline? {
+ return getEvent(mTimelines)
+ }
+}
diff --git a/tests/InputMethodStressTest/Android.bp b/tests/InputMethodStressTest/Android.bp
new file mode 100644
index 000000000000..131611d28f0a
--- /dev/null
+++ b/tests/InputMethodStressTest/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2021 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 {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "InputMethodStressTest",
+ srcs: ["src/**/*.java"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.uiautomator_uiautomator",
+ "compatibility-device-util-axt",
+ "platform-test-annotations",
+ "truth-prebuilt",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ sdk_version: "31",
+}
diff --git a/tests/InputMethodStressTest/AndroidManifest.xml b/tests/InputMethodStressTest/AndroidManifest.xml
new file mode 100644
index 000000000000..f5fe8f2e8e76
--- /dev/null
+++ b/tests/InputMethodStressTest/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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="com.android.inputmethod.stresstest">
+
+ <application>
+ <activity android:name=".AutoShowTest$TestActivity"/>
+ <activity android:name=".ImeOpenCloseStressTest$TestActivity"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.inputmethod.stresstest">
+ </instrumentation>
+</manifest>
diff --git a/tests/InputMethodStressTest/AndroidTest.xml b/tests/InputMethodStressTest/AndroidTest.xml
new file mode 100644
index 000000000000..b194010a985a
--- /dev/null
+++ b/tests/InputMethodStressTest/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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="InputMethod integration/regression test">
+ <option name="test-suite-tag" value="apct" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="InputMethodStressTest.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.inputmethod.stresstest" />
+ </test>
+</configuration>
diff --git a/tests/InputMethodStressTest/OWNERS b/tests/InputMethodStressTest/OWNERS
new file mode 100644
index 000000000000..6bb4b17ed4eb
--- /dev/null
+++ b/tests/InputMethodStressTest/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 34867
+
+include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/tests/InputMethodStressTest/TEST_MAPPING b/tests/InputMethodStressTest/TEST_MAPPING
new file mode 100644
index 000000000000..ad07205ab02d
--- /dev/null
+++ b/tests/InputMethodStressTest/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "InputMethodStressTest"
+ }
+ ]
+}
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java
new file mode 100644
index 000000000000..33cad78ef73c
--- /dev/null
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 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.inputmethod.stresstest;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
+
+import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntil;
+import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsShown;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Bundle;
+import android.platform.test.annotations.RootPermissionTest;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RootPermissionTest
+@RunWith(AndroidJUnit4.class)
+public final class AutoShowTest {
+
+ @Test
+ public void autoShow() {
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ Intent intent = new Intent()
+ .setAction(Intent.ACTION_MAIN)
+ .setClass(instrumentation.getContext(), TestActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ TestActivity activity = (TestActivity) instrumentation.startActivitySync(intent);
+ EditText editText = activity.getEditText();
+ waitOnMainUntil("activity should gain focus", editText::hasWindowFocus);
+ waitOnMainUntilImeIsShown(editText);
+ }
+
+ public static class TestActivity extends Activity {
+ private EditText mEditText;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // IME will be auto-shown if the following conditions are met:
+ // 1. SoftInputMode state is SOFT_INPUT_STATE_UNSPECIFIED.
+ // 2. SoftInputMode adjust is SOFT_INPUT_ADJUST_RESIZE.
+ getWindow().setSoftInputMode(SOFT_INPUT_STATE_UNSPECIFIED | SOFT_INPUT_ADJUST_RESIZE);
+ LinearLayout rootView = new LinearLayout(this);
+ rootView.setOrientation(LinearLayout.VERTICAL);
+ mEditText = new EditText(this);
+ rootView.addView(mEditText, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ setContentView(rootView);
+ // 3. The focused view is a text editor (View#onCheckIsTextEditor() returns true).
+ mEditText.requestFocus();
+ }
+
+ public EditText getEditText() {
+ return mEditText;
+ }
+ }
+}
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java
new file mode 100644
index 000000000000..0e86bc8de152
--- /dev/null
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 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.inputmethod.stresstest;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntil;
+import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsHidden;
+import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsShown;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Bundle;
+import android.platform.test.annotations.RootPermissionTest;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RootPermissionTest
+@RunWith(AndroidJUnit4.class)
+public final class ImeOpenCloseStressTest {
+
+ private static final int NUM_TEST_ITERATIONS = 100;
+
+ @Test
+ public void test() {
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ Intent intent = new Intent()
+ .setAction(Intent.ACTION_MAIN)
+ .setClass(instrumentation.getContext(), TestActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ TestActivity activity = (TestActivity) instrumentation.startActivitySync(intent);
+ EditText editText = activity.getEditText();
+ waitOnMainUntil("activity should gain focus", editText::hasWindowFocus);
+ for (int i = 0; i < NUM_TEST_ITERATIONS; i++) {
+ instrumentation.runOnMainSync(activity::showIme);
+ waitOnMainUntilImeIsShown(editText);
+ instrumentation.runOnMainSync(activity::hideIme);
+ waitOnMainUntilImeIsHidden(editText);
+ }
+ }
+
+ public static class TestActivity extends Activity {
+
+ private EditText mEditText;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout rootView = new LinearLayout(this);
+ rootView.setOrientation(LinearLayout.VERTICAL);
+ mEditText = new EditText(this);
+ rootView.addView(mEditText, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ setContentView(rootView);
+ }
+
+ public EditText getEditText() {
+ return mEditText;
+ }
+
+ public void showIme() {
+ mEditText.requestFocus();
+ InputMethodManager imm = getSystemService(InputMethodManager.class);
+ imm.showSoftInput(mEditText, 0);
+ }
+
+ public void hideIme() {
+ InputMethodManager imm = getSystemService(InputMethodManager.class);
+ imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
+ }
+ }
+}
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
new file mode 100644
index 000000000000..ba2ba3c75bc2
--- /dev/null
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 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.inputmethod.stresstest;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.view.View;
+import android.view.WindowInsets;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/** Utility methods for IME stress test. */
+public final class ImeStressTestUtil {
+
+ private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
+
+ private ImeStressTestUtil() {
+ }
+
+ /** Checks if the IME is shown on the window that the given view belongs to. */
+ public static boolean isImeShown(View view) {
+ WindowInsets insets = view.getRootWindowInsets();
+ return insets.isVisible(WindowInsets.Type.ime());
+ }
+
+ /** Calls the callable on the main thread and returns the result. */
+ public static <V> V callOnMainSync(Callable<V> callable) {
+ AtomicReference<V> result = new AtomicReference<>();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ try {
+ result.set(callable.call());
+ } catch (Exception e) {
+ throw new RuntimeException("Exception was thrown", e);
+ }
+ });
+ return result.get();
+ }
+
+ /**
+ * Waits until {@code pred} returns true, or throws on timeout.
+ *
+ * <p>The given {@code pred} will be called on the main thread.
+ */
+ public static void waitOnMainUntil(String message, Callable<Boolean> pred) {
+ eventually(() -> assertWithMessage(message).that(pred.call()).isTrue(), TIMEOUT);
+ }
+
+ /** Waits until IME is shown, or throws on timeout. */
+ public static void waitOnMainUntilImeIsShown(View view) {
+ eventually(() -> assertWithMessage("IME should be shown").that(
+ callOnMainSync(() -> isImeShown(view))).isTrue(), TIMEOUT);
+ }
+
+ /** Waits until IME is hidden, or throws on timeout. */
+ public static void waitOnMainUntilImeIsHidden(View view) {
+ //eventually(() -> assertThat(callOnMainSync(() -> isImeShown(view))).isFalse(), TIMEOUT);
+ eventually(() -> assertWithMessage("IME should be hidden").that(
+ callOnMainSync(() -> isImeShown(view))).isFalse(), TIMEOUT);
+ }
+}
diff --git a/tests/Internal/src/com/android/internal/util/ParcellingTests.java b/tests/Internal/src/com/android/internal/util/ParcellingTests.java
new file mode 100644
index 000000000000..65a3436a4c5e
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/util/ParcellingTests.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 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.internal.util;
+
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.Parcelling.BuiltIn.ForInstant;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.time.Instant;
+
+/** Tests for {@link Parcelling}. */
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class ParcellingTests {
+
+ private Parcel mParcel = Parcel.obtain();
+
+ @Test
+ public void forInstant_normal() {
+ testForInstant(Instant.ofEpochSecond(500L, 10));
+ }
+
+ @Test
+ public void forInstant_minimum() {
+ testForInstant(Instant.MIN);
+ }
+
+ @Test
+ public void forInstant_maximum() {
+ testForInstant(Instant.MAX);
+ }
+
+ @Test
+ public void forInstant_null() {
+ testForInstant(null);
+ }
+
+ private void testForInstant(Instant instant) {
+ Parcelling<Instant> parcelling = new ForInstant();
+ parcelling.parcel(instant, mParcel, 0);
+ mParcel.setDataPosition(0);
+
+ Instant created = parcelling.unparcel(mParcel);
+
+ if (instant == null) {
+ assertNull(created);
+ } else {
+ assertEquals(instant, created);
+ }
+ }
+
+}
diff --git a/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java b/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
index e956be339bc4..dd9b294a9596 100644
--- a/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
+++ b/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
@@ -82,11 +82,10 @@ public class JobStorePerfTests {
long elapsedTimeNs = 0;
while (benchmarkState.keepRunning(elapsedTimeNs)) {
- sJobStore.clear();
+ sJobStore.clearForTesting();
for (JobStatus job : jobList) {
- sJobStore.add(job);
+ sJobStore.addForTesting(job);
}
- sJobStore.waitForWriteToCompleteForTesting(10_000);
final long startTime = SystemClock.elapsedRealtimeNanos();
sJobStore.writeStatusToDiskForTesting();
@@ -110,11 +109,11 @@ public class JobStorePerfTests {
long elapsedTimeNs = 0;
while (benchmarkState.keepRunning(elapsedTimeNs)) {
- sJobStore.clear();
+ sJobStore.clearForTesting();
for (JobStatus job : jobList) {
- sJobStore.add(job);
+ sJobStore.addForTesting(job);
}
- sJobStore.waitForWriteToCompleteForTesting(10_000);
+ sJobStore.writeStatusToDiskForTesting();
JobSet jobSet = new JobSet();
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 6e1cef496f40..9f6ce4e8425b 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -31,7 +31,8 @@ android_test {
test_config: "RollbackTest.xml",
java_resources: [
":com.android.apex.apkrollback.test_v2",
- ":com.android.apex.apkrollback.test_v2Crashing"
+ ":com.android.apex.apkrollback.test_v2Crashing",
+ ":test.rebootless_apex_v2",
],
}
@@ -47,7 +48,10 @@ java_test_host {
],
test_suites: ["general-tests"],
test_config: "StagedRollbackTest.xml",
- data: [":com.android.apex.apkrollback.test_v1"],
+ data: [
+ ":com.android.apex.apkrollback.test_v1",
+ ":test.rebootless_apex_v1",
+ ],
}
java_test_host {
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 7b2a07fd80f8..cbdcb8869628 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -16,7 +16,6 @@
package com.android.tests.rollback;
-import static com.android.cts.install.lib.InstallUtils.processUserData;
import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
import static com.android.cts.rollback.lib.RollbackUtils.waitForAvailableRollback;
@@ -31,11 +30,9 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.UserManager;
-import android.provider.DeviceConfig;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -55,7 +52,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -71,12 +67,6 @@ public class RollbackTest {
private static final String INSTRUMENTED_APP = "com.android.tests.rollback";
- // copied from PackageManagerService#PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS
- // TODO: find a better place for the property so that it can be imported in tests
- // maybe android.content.pm.PackageManager?
- private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS =
- "enable_rollback_timeout";
-
private static boolean hasRollbackInclude(List<RollbackInfo> rollbacks, String packageName) {
return rollbacks.stream().anyMatch(
ri -> ri.getPackages().stream().anyMatch(
@@ -203,740 +193,6 @@ public class RollbackTest {
}
}
- /**
- * Test that multiple available rollbacks are properly persisted.
- */
- @Test
- public void testAvailableRollbackPersistence() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- Install.single(TestApp.A2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- Uninstall.packages(TestApp.B);
- Install.single(TestApp.B1).commit();
- Install.single(TestApp.B2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
- // Both test apps should now be available for rollback.
- RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
- assertThat(rollbackA).isNotNull();
- assertThat(rollbackA).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
-
- RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
- assertThat(rollbackB).isNotNull();
- assertThat(rollbackB).packagesContainsExactly(
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- // Reload the persisted data.
- rm.reloadPersistedData();
-
- // The apps should still be available for rollback.
- rollbackA = waitForAvailableRollback(TestApp.A);
- assertThat(rollbackA).isNotNull();
- assertThat(rollbackA).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
-
- rollbackB = waitForAvailableRollback(TestApp.B);
- assertThat(rollbackB).isNotNull();
- assertThat(rollbackB).packagesContainsExactly(
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- // Rollback of B should not rollback A
- RollbackUtils.rollback(rollbackB.getRollbackId());
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test that available multi-package rollbacks are properly persisted.
- */
- @Test
- public void testAvailableMultiPackageRollbackPersistence() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- Uninstall.packages(TestApp.A, TestApp.B);
- Install.multi(TestApp.A1, TestApp.B1).commit();
- Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
-
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
- // The app should now be available for rollback.
- RollbackInfo availableA = waitForAvailableRollback(TestApp.A);
- assertThat(availableA).isNotNull();
- assertThat(availableA).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1),
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- RollbackInfo availableB = waitForAvailableRollback(TestApp.B);
- assertThat(availableB).isNotNull();
- assertThat(availableB).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1),
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- // Assert they're both the same rollback
- assertThat(availableA).hasRollbackId(availableB.getRollbackId());
-
- // Reload the persisted data.
- rm.reloadPersistedData();
-
- // The apps should still be available for rollback.
- availableA = waitForAvailableRollback(TestApp.A);
- assertThat(availableA).isNotNull();
- assertThat(availableA).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1),
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- availableB = waitForAvailableRollback(TestApp.B);
- assertThat(availableB).isNotNull();
- assertThat(availableB).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1),
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- // Rollback of B should rollback A as well
- RollbackUtils.rollback(availableB.getRollbackId());
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
-
- RollbackInfo committedA = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TestApp.A);
- assertThat(committedA).isNotNull();
- assertThat(committedA).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1),
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- RollbackInfo committedB = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TestApp.A);
- assertThat(committedB).isNotNull();
- assertThat(committedB).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1),
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- // Assert they're both the same rollback
- assertThat(committedA).hasRollbackId(committedB.getRollbackId());
- assertThat(committedA).hasRollbackId(availableA.getRollbackId());
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test that recently committed rollback data is properly persisted.
- */
- @Test
- public void testRecentlyCommittedRollbackPersistence() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- Install.single(TestApp.A2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- // The app should now be available for rollback.
- RollbackInfo available = waitForAvailableRollback(TestApp.A);
- assertThat(available).isNotNull();
-
- // Roll back the app.
- TestApp cause = new TestApp("Foo", "com.android.tests.rollback.testapp.Foo",
- /*versionCode*/ 42, /*isApex*/ false);
- RollbackUtils.rollback(available.getRollbackId(), cause);
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
- // Verify the recent rollback has been recorded.
- RollbackInfo committed = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TestApp.A);
- assertThat(committed).isNotNull();
- assertThat(committed).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
- assertThat(committed).causePackagesContainsExactly(cause);
-
- // Reload the persisted data.
- rm.reloadPersistedData();
-
- // Verify the recent rollback is still recorded.
- committed = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TestApp.A);
- assertThat(committed).isNotNull();
- assertThat(committed).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
- assertThat(committed).causePackagesContainsExactly(cause);
- assertThat(committed).hasRollbackId(available.getRollbackId());
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test the scheduling aspect of rollback expiration.
- */
- @Test
- public void testRollbackExpiresAfterLifetime() throws Exception {
- long expirationTime = TimeUnit.SECONDS.toMillis(30);
- long defaultExpirationTime = TimeUnit.HOURS.toMillis(48);
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.WRITE_DEVICE_CONFIG);
-
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
- RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
- Long.toString(expirationTime), false /* makeDefault*/);
-
- // Uninstall TestApp.A
- Uninstall.packages(TestApp.A);
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
-
- // Install v1 of the app (without rollbacks enabled).
- Install.single(TestApp.A1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
- // Upgrade from v1 to v2, with rollbacks enabled.
- Install.single(TestApp.A2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- // Check that the rollback data has not expired
- Thread.sleep(1000);
- RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
- assertThat(rollback).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
-
- // Give it a little more time, but still not long enough to expire
- Thread.sleep(expirationTime / 2);
- rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.A);
- assertThat(rollback).isNotNull();
- assertThat(rollback).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
-
- // Check that the data has expired after the expiration time (with a buffer of 1 second)
- Thread.sleep(expirationTime / 2);
- rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.A);
- assertThat(rollback).isNull();
-
- } finally {
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
- RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
- Long.toString(defaultExpirationTime), false /* makeDefault*/);
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test that available rollbacks should expire correctly when the property
- * {@link RollbackManager#PROPERTY_ROLLBACK_LIFETIME_MILLIS} is changed
- */
- @Test
- public void testRollbackExpiresWhenLifetimeChanges() throws Exception {
- long defaultExpirationTime = TimeUnit.HOURS.toMillis(48);
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.WRITE_DEVICE_CONFIG);
-
- Uninstall.packages(TestApp.A);
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
- Install.single(TestApp.A1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- Install.single(TestApp.A2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
- assertThat(rollback).packagesContainsExactly(Rollback.from(TestApp.A2).to(TestApp.A1));
-
- // Change the lifetime to 0 which should expire rollbacks immediately
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
- RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
- Long.toString(0), false /* makeDefault*/);
-
- // Keep polling until device config changes has happened (which might take more than
- // 5 sec depending how busy system_server is) and rollbacks have expired
- for (int i = 0; i < 30; ++i) {
- if (hasRollbackInclude(rm.getAvailableRollbacks(), TestApp.A)) {
- Thread.sleep(1000);
- }
- }
- rollback = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A);
- assertThat(rollback).isNull();
- } finally {
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
- RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
- Long.toString(defaultExpirationTime), false /* makeDefault*/);
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test that changing time on device does not affect the duration of time that we keep
- * rollback available
- */
- @Test
- public void testTimeChangeDoesNotAffectLifetime() throws Exception {
- long expirationTime = TimeUnit.SECONDS.toMillis(30);
- long defaultExpirationTime = TimeUnit.HOURS.toMillis(48);
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.SET_TIME);
-
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
- RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
- Long.toString(expirationTime), false /* makeDefault*/);
-
- // Install app A with rollback enabled
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- Install.single(TestApp.A2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- Thread.sleep(expirationTime / 2);
-
- // Install app B with rollback enabled
- Uninstall.packages(TestApp.B);
- Install.single(TestApp.B1).commit();
- Install.single(TestApp.B2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
- // 1 second buffer
- Thread.sleep(1000);
-
- try {
- // Change the time
- RollbackUtils.forwardTimeBy(expirationTime);
-
- // 1 second buffer to allow Rollback Manager to handle time change before loading
- // persisted data
- Thread.sleep(1000);
-
- // Load timestamps from storage
- rm.reloadPersistedData();
-
- // Wait until rollback for app A has expired
- // This will trigger an expiration run that should expire app A but not B
- Thread.sleep(expirationTime / 2);
- RollbackInfo rollbackA =
- getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A);
- Log.i(TAG, "Checking if the rollback for TestApp.A is null");
-
- // Rollback for app B should not be expired
- RollbackInfo rollbackB1 = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.B);
-
- // Wait until rollback for app B has expired
- Thread.sleep(expirationTime / 2);
- RollbackInfo rollbackB2 = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.B);
-
- assertThat(rollbackA).isNull();
- assertThat(rollbackB1).isNotNull();
- assertThat(rollbackB1).packagesContainsExactly(
- Rollback.from(TestApp.B2).to(TestApp.B1));
- assertThat(rollbackB2).isNull();
- } finally {
- RollbackUtils.forwardTimeBy(-expirationTime);
- }
- } finally {
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
- RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
- Long.toString(defaultExpirationTime), false /* makeDefault*/);
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test explicit expiration of rollbacks.
- * Does not test the scheduling aspects of rollback expiration.
- */
- @Test
- public void testRollbackExpiration() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
- RollbackManager rm = RollbackUtils.getRollbackManager();
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- Install.single(TestApp.A2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- // The app should now be available for rollback.
- RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
- assertThat(rollback).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
-
- // Expire the rollback.
- rm.expireRollbackForPackage(TestApp.A);
-
- // The rollback should no longer be available.
- assertThat(getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.A)).isNull();
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test that app user data is rolled back.
- */
- @Test
- public void testUserDataRollback() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- processUserData(TestApp.A);
- Install.single(TestApp.A2).setEnableRollback().commit();
- processUserData(TestApp.A);
-
- RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
- RollbackUtils.rollback(rollback.getRollbackId());
- processUserData(TestApp.A);
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test rollback of apks involving splits.
- */
- @Test
- public void testRollbackWithSplits() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.ASplit1).commit();
- processUserData(TestApp.A);
-
- Install.single(TestApp.ASplit2).setEnableRollback().commit();
- processUserData(TestApp.A);
-
- RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
- RollbackUtils.rollback(rollback.getRollbackId());
- processUserData(TestApp.A);
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test restrictions on rollback broadcast sender.
- * A random app should not be able to send a ROLLBACK_COMMITTED broadcast.
- */
- @Test
- public void testRollbackBroadcastRestrictions() throws Exception {
- RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
- Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
- try {
- InstrumentationRegistry.getContext().sendBroadcast(broadcast);
- fail("Succeeded in sending restricted broadcast from app context.");
- } catch (SecurityException se) {
- // Expected behavior.
- }
-
- // Confirm that we really haven't received the broadcast.
- // TODO: How long to wait for the expected timeout?
- assertThat(broadcastReceiver.poll(5, TimeUnit.SECONDS)).isNull();
-
- // TODO: Do we need to do this? Do we need to ensure this is always
- // called, even when the test fails?
- broadcastReceiver.unregister();
- }
-
- /**
- * Regression test for rollback in the case when multiple apps are
- * available for rollback at the same time.
- */
- @Test
- public void testMultipleRollbackAvailable() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
- // Prep installation of the test apps.
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- Install.single(TestApp.A2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- Uninstall.packages(TestApp.B);
- Install.single(TestApp.B1).commit();
- Install.single(TestApp.B2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
- // Both test apps should now be available for rollback, and the
- // RollbackInfo returned for the rollbacks should be correct.
- RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
- assertThat(rollbackA).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
-
- RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
- assertThat(rollbackB).packagesContainsExactly(
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- // Executing rollback should roll back the correct package.
- RollbackUtils.rollback(rollbackA.getRollbackId());
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- Install.single(TestApp.A2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- RollbackUtils.rollback(rollbackB.getRollbackId());
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test that the MANAGE_ROLLBACKS permission is required to call
- * RollbackManager APIs.
- */
- @Test
- public void testManageRollbacksPermission() throws Exception {
- // We shouldn't be allowed to call any of the RollbackManager APIs
- // without the MANAGE_ROLLBACKS permission.
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- try {
- rm.getAvailableRollbacks();
- fail("expected SecurityException");
- } catch (SecurityException e) {
- // Expected.
- }
-
- try {
- rm.getRecentlyCommittedRollbacks();
- fail("expected SecurityException");
- } catch (SecurityException e) {
- // Expected.
- }
-
- try {
- // TODO: What if the implementation checks arguments for non-null
- // first? Then this test isn't valid.
- rm.commitRollback(0, Collections.emptyList(), null);
- fail("expected SecurityException");
- } catch (SecurityException e) {
- // Expected.
- }
-
- try {
- rm.reloadPersistedData();
- fail("expected SecurityException");
- } catch (SecurityException e) {
- // Expected.
- }
-
- try {
- rm.expireRollbackForPackage(TestApp.A);
- fail("expected SecurityException");
- } catch (SecurityException e) {
- // Expected.
- }
- }
-
- /**
- * Test that you cannot enable rollback for a package without the
- * MANAGE_ROLLBACKS permission.
- */
- @Test
- public void testEnableRollbackPermission() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES);
-
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
- Install.single(TestApp.A2).setEnableRollback().commit();
-
- // We expect v2 of the app was installed, but rollback has not
- // been enabled.
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackUtils.getRollbackManager();
- assertThat(
- getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test that you cannot enable rollback for a non-module package when
- * holding the MANAGE_ROLLBACKS permission.
- */
- @Test
- public void testNonModuleEnableRollback() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
-
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
- Install.single(TestApp.A2).setEnableRollback().commit();
-
- // We expect v2 of the app was installed, but rollback has not
- // been enabled because the test app is not a module.
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- RollbackManager rm = RollbackUtils.getRollbackManager();
- assertThat(
- getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test rollback of multi-package installs is implemented.
- */
- @Test
- public void testMultiPackage() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- // Prep installation of the test apps.
- Uninstall.packages(TestApp.A, TestApp.B);
- Install.multi(TestApp.A1, TestApp.B1).commit();
- processUserData(TestApp.A);
- processUserData(TestApp.B);
- Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
- processUserData(TestApp.A);
- processUserData(TestApp.B);
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
- // TestApp.A should now be available for rollback.
- RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
- assertThat(rollback).isNotNull();
- assertThat(rollback).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1),
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- // Rollback the app. It should cause both test apps to be rolled
- // back.
- RollbackUtils.rollback(rollback.getRollbackId());
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
-
- // We should see recent rollbacks listed for both A and B.
- Thread.sleep(1000);
- RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TestApp.A);
-
- RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TestApp.B);
- assertThat(rollback).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1),
- Rollback.from(TestApp.B2).to(TestApp.B1));
-
- assertThat(rollbackA).hasRollbackId(rollbackB.getRollbackId());
-
- processUserData(TestApp.A);
- processUserData(TestApp.B);
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test failure to enable rollback for multi-package installs.
- * If any one of the packages fail to enable rollback, we shouldn't enable
- * rollback for any package.
- */
- @Test
- public void testMultiPackageEnableFail() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- Uninstall.packages(TestApp.A, TestApp.B);
- Install.single(TestApp.A1).commit();
- // We should fail to enable rollback here because TestApp B is not
- // already installed.
- Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
-
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
- assertThat(getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.A)).isNull();
- assertThat(getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.B)).isNull();
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
@Test
@Ignore("b/120200473")
/**
@@ -1074,195 +330,4 @@ public class RollbackTest {
InstallUtils.dropShellPermissionIdentity();
}
}
-
- @Test
- public void testEnableRollbackTimeoutFailsRollback() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.MANAGE_ROLLBACKS,
- Manifest.permission.WRITE_DEVICE_CONFIG);
-
- //setting the timeout to a very short amount that will definitely be triggered
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
- PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
- Long.toString(0), false /* makeDefault*/);
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- waitForUnavailableRollback(TestApp.A);
-
- // Block the RollbackManager to make extra sure it will not be
- // able to enable the rollback in time.
- rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(1));
- Install.single(TestApp.A2).setEnableRollback().commit();
-
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- // Give plenty of time for RollbackManager to unblock and attempt
- // to make the rollback available before asserting that the
- // rollback was not made available.
- Thread.sleep(TimeUnit.SECONDS.toMillis(2));
- assertThat(
- getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
- } finally {
- //setting the timeout back to default
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
- PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
- null, false /* makeDefault*/);
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- @Test
- public void testEnableRollbackTimeoutFailsRollback_MultiPackage() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.MANAGE_ROLLBACKS,
- Manifest.permission.WRITE_DEVICE_CONFIG);
-
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
- PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
- Long.toString(5000), false /* makeDefault*/);
- RollbackManager rm = RollbackUtils.getRollbackManager();
-
- Uninstall.packages(TestApp.A, TestApp.B);
- Install.multi(TestApp.A1, TestApp.B1).commit();
- waitForUnavailableRollback(TestApp.A);
-
- // Block the 2nd session for 10s so it will not be able to enable the rollback in time.
- rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(0));
- rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(10));
- Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
-
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
- // Give plenty of time for RollbackManager to unblock and attempt
- // to make the rollback available before asserting that the
- // rollback was not made available.
- Thread.sleep(TimeUnit.SECONDS.toMillis(2));
-
- List<RollbackInfo> available = rm.getAvailableRollbacks();
- assertThat(getUniqueRollbackInfoForPackage(available, TestApp.A)).isNull();
- assertThat(getUniqueRollbackInfoForPackage(available, TestApp.B)).isNull();
- } finally {
- //setting the timeout back to default
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
- PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
- null, false /* makeDefault*/);
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Test we can't enable rollback for non-whitelisted app without
- * TEST_MANAGE_ROLLBACKS permission
- */
- @Test
- public void testNonRollbackWhitelistedApp() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
-
- Uninstall.packages(TestApp.A);
- Install.single(TestApp.A1).commit();
- assertThat(RollbackUtils.getAvailableRollback(TestApp.A)).isNull();
-
- Install.single(TestApp.A2).setEnableRollback().commit();
- Thread.sleep(TimeUnit.SECONDS.toMillis(2));
- assertThat(RollbackUtils.getAvailableRollback(TestApp.A)).isNull();
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- @Test
- public void testRollbackDataPolicy() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
- Uninstall.packages(TestApp.A, TestApp.B, TestApp.C);
- Install.multi(TestApp.A1, TestApp.B1, TestApp.C1).commit();
- // Write user data version = 1
- InstallUtils.processUserData(TestApp.A);
- InstallUtils.processUserData(TestApp.B);
- InstallUtils.processUserData(TestApp.C);
-
- Install a2 = Install.single(TestApp.A2)
- .setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
- Install b2 = Install.single(TestApp.B2)
- .setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
- // The rollback data policy of C2 is specified in the manifest
- Install c2 = Install.single(TestApp.C2).setEnableRollback();
- Install.multi(a2, b2, c2).setEnableRollback().commit();
- // Write user data version = 2
- InstallUtils.processUserData(TestApp.A);
- InstallUtils.processUserData(TestApp.B);
- InstallUtils.processUserData(TestApp.C);
-
- RollbackInfo info = RollbackUtils.getAvailableRollback(TestApp.A);
- RollbackUtils.rollback(info.getRollbackId());
- // Read user data version from userdata.txt
- // A's user data version is -1 for user data is wiped.
- // B's user data version is 1 as rollback committed.
- // C's user data version is -1 for user data is wiped.
- assertThat(InstallUtils.getUserDataVersion(TestApp.A)).isEqualTo(-1);
- assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
- assertThat(InstallUtils.getUserDataVersion(TestApp.C)).isEqualTo(-1);
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Tests an app can be rolled back to the previous signing key.
- *
- * <p>The rollback capability in the signing lineage allows an app to be updated to an APK
- * signed with a previous signing key in the lineage; however this often defeats the purpose
- * of key rotation as a compromised key could then be used to roll an app back to the previous
- * key. To avoid requiring the rollback capability to support app rollbacks the PackageManager
- * allows an app to be rolled back to the previous signing key if the rollback install reason
- * is set.
- */
- @Test
- public void testRollbackAfterKeyRotation() throws Exception {
- try {
- InstallUtils.adoptShellPermissionIdentity(
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.TEST_MANAGE_ROLLBACKS,
- Manifest.permission.MANAGE_ROLLBACKS);
-
- // Uninstall TestApp.A
- Uninstall.packages(TestApp.A);
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
-
- // Install v1 of the app with the original signing key (without rollbacks enabled).
- Install.single(TestApp.AOriginal1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
- // Upgrade from v1 to v2 with the rotated signing key, with rollbacks enabled.
- Install.single(TestApp.ARotated2).setEnableRollback().commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
- // Roll back the app.
- RollbackInfo available = waitForAvailableRollback(TestApp.A);
- RollbackUtils.rollback(available.getRollbackId());
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- } finally {
- InstallUtils.dropShellPermissionIdentity();
- }
- }
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 642b19e6d961..bb4866f2cac4 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -22,12 +22,10 @@ import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoFo
import static com.google.common.truth.Truth.assertThat;
import android.Manifest;
-import android.content.Context;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
-import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -60,6 +58,7 @@ import java.util.concurrent.TimeUnit;
public class StagedRollbackTest {
private static final String PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT =
"watchdog_trigger_failure_count";
+ private static final String REBOOTLESS_APEX_NAME = "test.apex.rebootless";
/**
* Adopts common shell permissions needed for rollback tests.
@@ -82,155 +81,6 @@ public class StagedRollbackTest {
InstallUtils.dropShellPermissionIdentity();
}
- /**
- * Test rollbacks of staged installs involving only apks with bad update.
- * Enable rollback phase.
- */
- @Test
- public void testBadApkOnly_Phase1_Install() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
-
- Install.single(TestApp.A1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- InstallUtils.processUserData(TestApp.A);
-
- Install.single(TestApp.ACrashing2).setEnableRollback().setStaged().commit();
- }
-
- /**
- * Test rollbacks of staged installs involving only apks with bad update.
- * Confirm that rollback was successfully enabled.
- */
- @Test
- public void testBadApkOnly_Phase2_VerifyInstall() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- InstallUtils.processUserData(TestApp.A);
-
- RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.A);
- assertThat(rollback).isNotNull();
- assertThat(rollback).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
- assertThat(rollback.isStaged()).isTrue();
-
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
- PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
- Integer.toString(5), false);
- RollbackUtils.sendCrashBroadcast(TestApp.A, 4);
- // Sleep for a while to make sure we don't trigger rollback
- Thread.sleep(TimeUnit.SECONDS.toMillis(30));
- }
-
- /**
- * Test rollbacks of staged installs involving only apks.
- * Confirm rollback phase.
- */
- @Test
- public void testBadApkOnly_Phase3_VerifyRollback() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- InstallUtils.processUserData(TestApp.A);
-
- RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getRecentlyCommittedRollbacks(), TestApp.A);
- assertThat(rollback).isNotNull();
- assertThat(rollback).packagesContainsExactly(
- Rollback.from(TestApp.A2).to(TestApp.A1));
- assertThat(rollback).causePackagesContainsExactly(TestApp.ACrashing2);
- assertThat(rollback).isStaged();
- assertThat(rollback.getCommittedSessionId()).isNotEqualTo(-1);
- }
-
- /**
- * Stage install an apk with rollback that will be later triggered by unattributable crash.
- */
- @Test
- public void testNativeWatchdogTriggersRollback_Phase1_Install() throws Exception {
- Install.single(TestApp.A1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
- Install.single(TestApp.A2).setEnableRollback().setStaged().commit();
- }
-
- /**
- * Verify the rollback is available.
- */
- @Test
- public void testNativeWatchdogTriggersRollback_Phase2_VerifyInstall() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackManager rm = RollbackUtils.getRollbackManager();
- assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
- TestApp.A)).isNotNull();
- }
-
- /**
- * Verify the rollback is committed after crashing.
- */
- @Test
- public void testNativeWatchdogTriggersRollback_Phase3_VerifyRollback() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- RollbackManager rm = RollbackUtils.getRollbackManager();
- assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
- TestApp.A)).isNotNull();
- }
-
- /**
- * Stage install an apk with rollback that will be later triggered by unattributable crash.
- */
- @Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase1_InstallA() throws Exception {
- Install.single(TestApp.A1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
- Install.single(TestApp.A2).setEnableRollback().setStaged().commit();
- }
-
- /**
- * Verify the rollback is available and then install another package with rollback.
- */
- @Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase2_InstallB() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackManager rm = RollbackUtils.getRollbackManager();
- assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
- TestApp.A)).isNotNull();
-
- // Install another package with rollback
- Install.single(TestApp.B1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
-
- Install.single(TestApp.B2).setEnableRollback().setStaged().commit();
- }
-
- /**
- * Verify the rollbacks are available.
- */
- @Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase3_VerifyInstall() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
- RollbackManager rm = RollbackUtils.getRollbackManager();
- assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
- TestApp.A)).isNotNull();
- assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
- TestApp.B)).isNotNull();
- }
-
- /**
- * Verify the rollbacks are committed after crashing.
- */
- @Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase4_VerifyRollback() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
- RollbackManager rm = RollbackUtils.getRollbackManager();
- assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
- TestApp.A)).isNotNull();
- assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
- TestApp.B)).isNotNull();
- }
-
@Test
public void testPreviouslyAbandonedRollbacks_Phase1_InstallAndAbandon() throws Exception {
Install.single(TestApp.A1).commit();
@@ -293,50 +143,6 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackDataPolicy_Phase1_Install() throws Exception {
- Install.multi(TestApp.A1, TestApp.B1, TestApp.C1).commit();
- // Write user data version = 1
- InstallUtils.processUserData(TestApp.A);
- InstallUtils.processUserData(TestApp.B);
- InstallUtils.processUserData(TestApp.C);
-
- Install a2 = Install.single(TestApp.A2).setStaged()
- .setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
- Install b2 = Install.single(TestApp.B2).setStaged()
- .setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
- // The rollback data policy of C2 is specified in the manifest
- Install c2 = Install.single(TestApp.C2).setStaged().setEnableRollback();
- Install.multi(a2, b2, c2).setEnableRollback().setStaged().commit();
- }
-
- @Test
- public void testRollbackDataPolicy_Phase2_Rollback() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
- // Write user data version = 2
- InstallUtils.processUserData(TestApp.A);
- InstallUtils.processUserData(TestApp.B);
- InstallUtils.processUserData(TestApp.C);
-
- RollbackInfo info = RollbackUtils.getAvailableRollback(TestApp.A);
- RollbackUtils.rollback(info.getRollbackId());
- }
-
- @Test
- public void testRollbackDataPolicy_Phase3_VerifyRollback() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
- assertThat(InstallUtils.getInstalledVersion(TestApp.C)).isEqualTo(1);
- // Read user data version from userdata.txt
- // A's user data version is -1 for user data is wiped.
- // B's user data version is 1 as rollback committed.
- // C's user data version is -1 for user data is wiped.
- assertThat(InstallUtils.getUserDataVersion(TestApp.A)).isEqualTo(-1);
- assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
- assertThat(InstallUtils.getUserDataVersion(TestApp.C)).isEqualTo(-1);
- }
-
- @Test
public void expireRollbacks() throws Exception {
// testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
// committed on a device which doesn't support checkpoint. Let's clean up all rollbacks
@@ -359,51 +165,6 @@ public class StagedRollbackTest {
"TestApexWithApkV2Crashing", APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true,
APK_IN_APEX_TESTAPEX_NAME + "_v2Crashing.apex");
- @Test
- public void testRollbackApexWithApk_Phase1_Install() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- InstallUtils.processUserData(TestApp.A);
-
- int sessionId = Install.single(TEST_APEX_WITH_APK_V2).setStaged().setEnableRollback()
- .commit();
- InstallUtils.waitForSessionReady(sessionId);
- }
-
- @Test
- public void testRollbackApexWithApk_Phase2_Rollback() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- InstallUtils.processUserData(TestApp.A);
-
- RollbackInfo available = RollbackUtils.getAvailableRollback(APK_IN_APEX_TESTAPEX_NAME);
- assertThat(available).isStaged();
- assertThat(available).packagesContainsExactly(
- Rollback.from(TEST_APEX_WITH_APK_V2).to(TEST_APEX_WITH_APK_V1),
- Rollback.from(TestApp.A, 0).to(TestApp.A1));
-
- RollbackUtils.rollback(available.getRollbackId(), TEST_APEX_WITH_APK_V2);
- RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
- assertThat(committed).isNotNull();
- assertThat(committed).isStaged();
- assertThat(committed).packagesContainsExactly(
- Rollback.from(TEST_APEX_WITH_APK_V2).to(TEST_APEX_WITH_APK_V1),
- Rollback.from(TestApp.A, 0).to(TestApp.A1));
- assertThat(committed).causePackagesContainsExactly(TEST_APEX_WITH_APK_V2);
- assertThat(committed.getCommittedSessionId()).isNotEqualTo(-1);
-
- // Note: The app is not rolled back until after the rollback is staged
- // and the device has been rebooted.
- InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
- assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
- }
-
- @Test
- public void testRollbackApexWithApk_Phase3_VerifyRollback() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(1);
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- InstallUtils.processUserData(TestApp.A);
- }
-
/**
* Installs an apex with an apk that can crash.
*/
@@ -442,52 +203,6 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackApexDataDirectories_Phase1_Install() throws Exception {
- int sessionId = Install.single(TEST_APEX_WITH_APK_V2).setStaged().setEnableRollback()
- .commit();
- InstallUtils.waitForSessionReady(sessionId);
- }
-
- @Test
- public void testRollbackApexDataDirectories_Phase2_Rollback() throws Exception {
- RollbackInfo available = RollbackUtils.getAvailableRollback(APK_IN_APEX_TESTAPEX_NAME);
-
- RollbackUtils.rollback(available.getRollbackId(), TEST_APEX_WITH_APK_V2);
- RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
-
- // Note: The app is not rolled back until after the rollback is staged
- // and the device has been rebooted.
- InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
- }
-
- @Test
- public void testRollbackApkDataDirectories_Phase1_InstallV1() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
- Install.single(TestApp.A1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- }
-
- @Test
- public void testRollbackApkDataDirectories_Phase2_InstallV2() throws Exception {
- Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
- }
-
- @Test
- public void testRollbackApkDataDirectories_Phase3_Rollback() throws Exception {
- RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.A);
- RollbackUtils.rollback(available.getRollbackId(), TestApp.A2);
- RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
- InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
- }
-
- @Test
- public void isCheckpointSupported() {
- Context context = InstrumentationRegistry.getInstrumentation().getContext();
- StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
- assertThat(sm.isCheckpointSupported()).isTrue();
- }
-
- @Test
public void testWatchdogMonitorsAcrossReboots_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
Install.single(TestApp.A1).commit();
@@ -527,30 +242,49 @@ public class StagedRollbackTest {
}
@Test
- public void testExpireSession_Phase1_Install() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
- Install.single(TestApp.A1).commit();
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- Install.single(TestApp.A2).setEnableRollback().setStaged().commit();
+ public void testRollbackRebootlessApex() throws Exception {
+ final String packageName = REBOOTLESS_APEX_NAME;
+ assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(1);
+
+ // install
+ TestApp apex1 = new TestApp("TestRebootlessApexV1", packageName, 1,
+ /* isApex= */ true, "test.rebootless_apex_v1.apex");
+ TestApp apex2 = new TestApp("TestRebootlessApexV2", packageName, 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ Install.single(apex2).setEnableRollback(PackageManager.ROLLBACK_DATA_POLICY_RETAIN)
+ .commit();
+
+ // verify rollback
+ assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(2);
+ RollbackInfo rollback = RollbackUtils.waitForAvailableRollback(packageName);
+ assertThat(rollback).packagesContainsExactly(Rollback.from(apex2).to(apex1));
+ assertThat(rollback).isNotStaged();
+
+ // rollback
+ RollbackUtils.rollback(rollback.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(1);
}
@Test
- public void testExpireSession_Phase2_VerifyInstall() throws Exception {
- assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.A);
- assertThat(rollback).isNotNull();
- assertThat(rollback).packagesContainsExactly(Rollback.from(TestApp.A2).to(TestApp.A1));
- assertThat(rollback.isStaged()).isTrue();
+ public void testNativeWatchdogTriggersRebootlessApexRollback_Phase1_Install() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(REBOOTLESS_APEX_NAME)).isEqualTo(1);
+
+ TestApp apex2 = new TestApp("TestRebootlessApexV2", REBOOTLESS_APEX_NAME, 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ Install.single(apex2).setEnableRollback(PackageManager.ROLLBACK_DATA_POLICY_RETAIN)
+ .commit();
+ Install.single(TestApp.A1).commit();
+ Install.single(TestApp.A2).setEnableRollback().commit();
+
+ RollbackUtils.waitForAvailableRollback(TestApp.A);
+ RollbackUtils.waitForAvailableRollback(REBOOTLESS_APEX_NAME);
}
@Test
- public void testExpireSession_Phase3_VerifyRollback() throws Exception {
- RollbackManager rm = RollbackUtils.getRollbackManager();
- RollbackInfo rollback = getUniqueRollbackInfoForPackage(
- rm.getAvailableRollbacks(), TestApp.A);
- assertThat(rollback).isNotNull();
+ public void testNativeWatchdogTriggersRebootlessApexRollback_Phase2_Verify() throws Exception {
+ // Check only rebootless apex is rolled back. Other rollbacks should remain unchanged.
+ assertThat(RollbackUtils.getCommittedRollback(REBOOTLESS_APEX_NAME)).isNotNull();
+ assertThat(RollbackUtils.getAvailableRollback(TestApp.A)).isNotNull();
}
@Test
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 1aa5c249ff18..05e8bde23008 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -21,13 +21,9 @@ import static com.android.tests.rollback.host.WatchdogEventLogger.Subject.assert
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.ddmlib.Log;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.IFileEntry;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.util.CommandResult;
@@ -40,12 +36,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
-import java.time.Instant;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
/**
* Runs the staged rollback tests.
@@ -72,17 +63,6 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
private static final String TESTAPP_A = "com.android.cts.install.lib.testapp.A";
- private static final String TEST_SUBDIR = "/subdir/";
-
- private static final String TEST_FILENAME_1 = "test_file.txt";
- private static final String TEST_STRING_1 = "hello this is a test";
- private static final String TEST_FILENAME_2 = "another_file.txt";
- private static final String TEST_STRING_2 = "this is a different file";
- private static final String TEST_FILENAME_3 = "also.xyz";
- private static final String TEST_STRING_3 = "also\n a\n test\n string";
- private static final String TEST_FILENAME_4 = "one_more.test";
- private static final String TEST_STRING_4 = "once more unto the test";
-
private static final String REASON_APP_CRASH = "REASON_APP_CRASH";
private static final String REASON_NATIVE_CRASH = "REASON_NATIVE_CRASH";
@@ -116,7 +96,9 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "*",
- apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "*");
+ apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "*",
+ "/system/apex/test.rebootless_apex_v*.apex",
+ "/data/apex/active/test.apex.rebootless*.apex");
}
/**
@@ -124,26 +106,26 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
* @param files the paths of files which might contain wildcards
*/
private void deleteFiles(String... files) throws Exception {
- boolean found = false;
- for (String file : files) {
- CommandResult result = getDevice().executeShellV2Command("ls " + file);
- if (result.getStatus() == CommandStatus.SUCCESS) {
- found = true;
- break;
+ try {
+ getDevice().enableAdbRoot();
+ boolean found = false;
+ for (String file : files) {
+ CommandResult result = getDevice().executeShellV2Command("ls " + file);
+ if (result.getStatus() == CommandStatus.SUCCESS) {
+ found = true;
+ break;
+ }
}
- }
- if (found) {
- try {
- getDevice().enableAdbRoot();
+ if (found) {
getDevice().remountSystemWritable();
for (String file : files) {
getDevice().executeShellCommand("rm -rf " + file);
}
- } finally {
- getDevice().disableAdbRoot();
+ getDevice().reboot();
}
- getDevice().reboot();
+ } finally {
+ getDevice().disableAdbRoot();
}
}
@@ -153,98 +135,6 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
}
/**
- * Tests watchdog triggered staged rollbacks involving only apks.
- */
- @Test
- public void testBadApkOnly() throws Exception {
- runPhase("testBadApkOnly_Phase1_Install");
- getDevice().reboot();
- runPhase("testBadApkOnly_Phase2_VerifyInstall");
-
- // Launch the app to crash to trigger rollback
- startActivity(TESTAPP_A);
- // Wait for reboot to happen
- waitForDeviceNotAvailable(2, TimeUnit.MINUTES);
-
- getDevice().waitForDeviceAvailable();
-
- runPhase("testBadApkOnly_Phase3_VerifyRollback");
-
- assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_APP_CRASH, TESTAPP_A);
- assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
- assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
- }
-
- @Test
- public void testNativeWatchdogTriggersRollback() throws Exception {
- runPhase("testNativeWatchdogTriggersRollback_Phase1_Install");
-
- // Reboot device to activate staged package
- getDevice().reboot();
-
- runPhase("testNativeWatchdogTriggersRollback_Phase2_VerifyInstall");
-
- // crash system_server enough times to trigger a rollback
- crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
-
- // Rollback should be committed automatically now.
- // Give time for rollback to be committed. This could take a while,
- // because we need all of the following to happen:
- // 1. system_server comes back up and boot completes.
- // 2. Rollback health observer detects updatable crashing signal.
- // 3. Staged rollback session becomes ready.
- // 4. Device actually reboots.
- // So we give a generous timeout here.
- waitForDeviceNotAvailable(5, TimeUnit.MINUTES);
- getDevice().waitForDeviceAvailable();
-
- // verify rollback committed
- runPhase("testNativeWatchdogTriggersRollback_Phase3_VerifyRollback");
-
- assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_NATIVE_CRASH, null);
- assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
- assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
- }
-
- @Test
- public void testNativeWatchdogTriggersRollbackForAll() throws Exception {
- // This test requires committing multiple staged rollbacks
- assumeTrue(isCheckpointSupported());
-
- // Install a package with rollback enabled.
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase1_InstallA");
- getDevice().reboot();
-
- // Once previous staged install is applied, install another package
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase2_InstallB");
- getDevice().reboot();
-
- // Verify the new staged install has also been applied successfully.
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase3_VerifyInstall");
-
- // crash system_server enough times to trigger a rollback
- crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
-
- // Rollback should be committed automatically now.
- // Give time for rollback to be committed. This could take a while,
- // because we need all of the following to happen:
- // 1. system_server comes back up and boot completes.
- // 2. Rollback health observer detects updatable crashing signal.
- // 3. Staged rollback session becomes ready.
- // 4. Device actually reboots.
- // So we give a generous timeout here.
- waitForDeviceNotAvailable(5, TimeUnit.MINUTES);
- getDevice().waitForDeviceAvailable();
-
- // verify all available rollbacks have been committed
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase4_VerifyRollback");
-
- assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_NATIVE_CRASH, null);
- assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
- assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
- }
-
- /**
* Tests rolling back user data where there are multiple rollbacks for that package.
*/
@Test
@@ -267,44 +157,12 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
runPhase("testRollbackAllowlistedApp_Phase2_VerifyInstall");
}
- @Test
- public void testRollbackDataPolicy() throws Exception {
- List<String> before = getSnapshotDirectories("/data/misc_ce/0/rollback");
-
- runPhase("testRollbackDataPolicy_Phase1_Install");
- getDevice().reboot();
- runPhase("testRollbackDataPolicy_Phase2_Rollback");
- getDevice().reboot();
- runPhase("testRollbackDataPolicy_Phase3_VerifyRollback");
-
- // Verify snapshots are deleted after restoration
- List<String> after = getSnapshotDirectories("/data/misc_ce/0/rollback");
- // Only check directories newly created during the test
- after.removeAll(before);
- // There should be only one /data/misc_ce/0/rollback/<rollbackId> created during test
- assertThat(after).hasSize(1);
- assertDirectoryIsEmpty(after.get(0));
- }
-
- /**
- * Tests that userdata of apk-in-apex is restored when apex is rolled back.
- */
- @Test
- public void testRollbackApexWithApk() throws Exception {
- pushTestApex();
- runPhase("testRollbackApexWithApk_Phase1_Install");
- getDevice().reboot();
- runPhase("testRollbackApexWithApk_Phase2_Rollback");
- getDevice().reboot();
- runPhase("testRollbackApexWithApk_Phase3_VerifyRollback");
- }
-
/**
* Tests that RollbackPackageHealthObserver is observing apk-in-apex.
*/
@Test
public void testRollbackApexWithApkCrashing() throws Exception {
- pushTestApex();
+ pushTestApex(APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
// Install an apex with apk that crashes
runPhase("testRollbackApexWithApkCrashing_Phase1_Install");
@@ -325,239 +183,24 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
}
/**
- * Tests that data in DE_sys apex data directory is restored when apex is rolled back.
- */
- @Test
- public void testRollbackApexDataDirectories_DeSys() throws Exception {
- List<String> before = getSnapshotDirectories("/data/misc/apexrollback");
- pushTestApex();
-
- // Push files to apex data directory
- String oldFilePath1 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_1;
- String oldFilePath2 =
- apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_2;
- runAsRoot(() -> {
- pushString(TEST_STRING_1, oldFilePath1);
- pushString(TEST_STRING_2, oldFilePath2);
- });
-
- // Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1_Install");
- getDevice().reboot();
-
- // Replace files in data directory
- String newFilePath3 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_3;
- String newFilePath4 =
- apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_4;
- runAsRoot(() -> {
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
- pushString(TEST_STRING_3, newFilePath3);
- pushString(TEST_STRING_4, newFilePath4);
- });
-
- // Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
- getDevice().reboot();
-
- // Verify that old files have been restored and new files are gone
- runAsRoot(() -> {
- assertFileContents(TEST_STRING_1, oldFilePath1);
- assertFileContents(TEST_STRING_2, oldFilePath2);
- assertFileNotExists(newFilePath3);
- assertFileNotExists(newFilePath4);
- });
-
- // Verify snapshots are deleted after restoration
- List<String> after = getSnapshotDirectories("/data/misc/apexrollback");
- // Only check directories newly created during the test
- after.removeAll(before);
- // There should be only one /data/misc/apexrollback/<rollbackId> created during test
- assertThat(after).hasSize(1);
- assertDirectoryIsEmpty(after.get(0));
- }
-
- /**
- * Tests that data in DE (user) apex data directory is restored when apex is rolled back.
+ * Tests rollback is supported correctly for rebootless apex
*/
@Test
- public void testRollbackApexDataDirectories_DeUser() throws Exception {
- List<String> before = getSnapshotDirectories("/data/misc_de/0/apexrollback");
- pushTestApex();
-
- // Push files to apex data directory
- String oldFilePath1 = apexDataDirDeUser(
- APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
- String oldFilePath2 =
- apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- runAsRoot(() -> {
- pushString(TEST_STRING_1, oldFilePath1);
- pushString(TEST_STRING_2, oldFilePath2);
- });
-
- // Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1_Install");
- getDevice().reboot();
-
- // Replace files in data directory
- String newFilePath3 =
- apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3;
- String newFilePath4 =
- apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- runAsRoot(() -> {
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
- pushString(TEST_STRING_3, newFilePath3);
- pushString(TEST_STRING_4, newFilePath4);
- });
-
- // Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
- getDevice().reboot();
-
- // Verify that old files have been restored and new files are gone
- runAsRoot(() -> {
- assertFileContents(TEST_STRING_1, oldFilePath1);
- assertFileContents(TEST_STRING_2, oldFilePath2);
- assertFileNotExists(newFilePath3);
- assertFileNotExists(newFilePath4);
- });
-
- // Verify snapshots are deleted after restoration
- List<String> after = getSnapshotDirectories("/data/misc_de/0/apexrollback");
- // Only check directories newly created during the test
- after.removeAll(before);
- // There should be only one /data/misc_de/0/apexrollback/<rollbackId> created during test
- assertThat(after).hasSize(1);
- assertDirectoryIsEmpty(after.get(0));
- }
-
- /**
- * Tests that data in CE apex data directory is restored when apex is rolled back.
- */
- @Test
- public void testRollbackApexDataDirectories_Ce() throws Exception {
- List<String> before = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
- pushTestApex();
-
- // Push files to apex data directory
- String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
- String oldFilePath2 =
- apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- runAsRoot(() -> {
- pushString(TEST_STRING_1, oldFilePath1);
- pushString(TEST_STRING_2, oldFilePath2);
- });
-
- // Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1_Install");
- getDevice().reboot();
-
- // Replace files in data directory
- String newFilePath3 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3;
- String newFilePath4 =
- apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- runAsRoot(() -> {
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
- pushString(TEST_STRING_3, newFilePath3);
- pushString(TEST_STRING_4, newFilePath4);
- });
-
- // Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
- getDevice().reboot();
-
- // Verify that old files have been restored and new files are gone
- runAsRoot(() -> {
- assertFileContents(TEST_STRING_1, oldFilePath1);
- assertFileContents(TEST_STRING_2, oldFilePath2);
- assertFileNotExists(newFilePath3);
- assertFileNotExists(newFilePath4);
- });
-
- // Verify snapshots are deleted after restoration
- List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
- // Only check directories newly created during the test
- after.removeAll(before);
- // There should be only one /data/misc_ce/0/apexrollback/<rollbackId> created during test
- assertThat(after).hasSize(1);
- assertDirectoryIsEmpty(after.get(0));
+ public void testRollbackRebootlessApex() throws Exception {
+ pushTestApex("test.rebootless_apex_v1.apex");
+ runPhase("testRollbackRebootlessApex");
}
/**
- * Tests that data in DE apk data directory is restored when apk is rolled back.
+ * Tests only rebootless apex (if any) is rolled back when native crash happens
*/
@Test
- public void testRollbackApkDataDirectories_De() throws Exception {
- // Install version 1 of TESTAPP_A
- runPhase("testRollbackApkDataDirectories_Phase1_InstallV1");
-
- // Push files to apk data directory
- String oldFilePath1 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_1;
- String oldFilePath2 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- runAsRoot(() -> {
- pushString(TEST_STRING_1, oldFilePath1);
- pushString(TEST_STRING_2, oldFilePath2);
- });
-
- // Install version 2 of TESTAPP_A with rollback enabled
- runPhase("testRollbackApkDataDirectories_Phase2_InstallV2");
- getDevice().reboot();
-
- // Replace files in data directory
- String newFilePath3 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_3;
- String newFilePath4 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- runAsRoot(() -> {
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
- pushString(TEST_STRING_3, newFilePath3);
- pushString(TEST_STRING_4, newFilePath4);
- });
-
- // Roll back the APK
- runPhase("testRollbackApkDataDirectories_Phase3_Rollback");
- getDevice().reboot();
-
- // Verify that old files have been restored and new files are gone
- runAsRoot(() -> {
- assertFileContents(TEST_STRING_1, oldFilePath1);
- assertFileContents(TEST_STRING_2, oldFilePath2);
- assertFileNotExists(newFilePath3);
- assertFileNotExists(newFilePath4);
- });
- }
-
- @Test
- public void testExpireApexRollback() throws Exception {
- List<String> before = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
- pushTestApex();
-
- // Push files to apex data directory
- String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
- String oldFilePath2 =
- apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- runAsRoot(() -> {
- pushString(TEST_STRING_1, oldFilePath1);
- pushString(TEST_STRING_2, oldFilePath2);
- });
-
- // Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1_Install");
- getDevice().reboot();
-
- List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
- // Only check directories newly created during the test
- after.removeAll(before);
- // There should be only one /data/misc_ce/0/apexrollback/<rollbackId> created during test
- assertThat(after).hasSize(1);
- // Expire all rollbacks and check CE snapshot directories are deleted
- runPhase("expireRollbacks");
- runAsRoot(() -> {
- for (String dir : after) {
- assertFileNotExists(dir);
- }
- });
+ public void testNativeWatchdogTriggersRebootlessApexRollback() throws Exception {
+ pushTestApex("test.rebootless_apex_v1.apex");
+ runPhase("testNativeWatchdogTriggersRebootlessApexRollback_Phase1_Install");
+ crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
+ getDevice().waitForDeviceAvailable();
+ runPhase("testNativeWatchdogTriggersRebootlessApexRollback_Phase2_Verify");
}
/**
@@ -584,30 +227,8 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
runPhase("testWatchdogMonitorsAcrossReboots_Phase3_VerifyRollback");
}
- /**
- * Tests an available rollback shouldn't be deleted when its session expires.
- */
- @Test
- public void testExpireSession() throws Exception {
- runPhase("testExpireSession_Phase1_Install");
- getDevice().reboot();
- runPhase("testExpireSession_Phase2_VerifyInstall");
-
- // Advance system clock by 7 days to expire the staged session
- Instant t1 = Instant.ofEpochMilli(getDevice().getDeviceDate());
- Instant t2 = t1.plusMillis(TimeUnit.DAYS.toMillis(7));
- runAsRoot(() -> getDevice().setDate(Date.from(t2)));
-
- // Somehow we need to wait for a while before reboot. Otherwise the change to the
- // system clock will be reset after reboot.
- Thread.sleep(3000);
- getDevice().reboot();
- runPhase("testExpireSession_Phase3_VerifyRollback");
- }
-
- private void pushTestApex() throws Exception {
+ private void pushTestApex(String fileName) throws Exception {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
- final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
final File apex = buildHelper.getTestFile(fileName);
try {
getDevice().enableAdbRoot();
@@ -619,101 +240,20 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
getDevice().reboot();
}
- private void pushString(String contents, String path) throws Exception {
- assertWithMessage("Failed to push file to device, content=%s path=%s", contents, path)
- .that(getDevice().pushString(contents, path)).isTrue();
- }
-
- private void assertFileContents(String expectedContents, String path) throws Exception {
- String actualContents = getDevice().pullFileContents(path);
- assertWithMessage("Failed to retrieve file=%s", path).that(actualContents).isNotNull();
- assertWithMessage("Mismatched file contents, path=%s", path)
- .that(actualContents).isEqualTo(expectedContents);
- }
-
- private void assertFileNotExists(String path) throws Exception {
- assertWithMessage("File shouldn't exist, path=%s", path)
- .that(getDevice().getFileEntry(path)).isNull();
- }
-
private static String apexDataDirDeSys(String apexName) {
return String.format("/data/misc/apexdata/%s", apexName);
}
- private static String apexDataDirDeUser(String apexName, int userId) {
- return String.format("/data/misc_de/%d/apexdata/%s", userId, apexName);
- }
-
private static String apexDataDirCe(String apexName, int userId) {
return String.format("/data/misc_ce/%d/apexdata/%s", userId, apexName);
}
- private static String apkDataDirDe(String apexName, int userId) {
- return String.format("/data/user_de/%d/%s", userId, apexName);
- }
-
- private List<String> getSnapshotDirectories(String baseDir) throws Exception {
- try {
- getDevice().enableAdbRoot();
- IFileEntry f = getDevice().getFileEntry(baseDir);
- if (f == null) {
- Log.d(TAG, "baseDir doesn't exist: " + baseDir);
- return Collections.EMPTY_LIST;
- }
- List<String> list = f.getChildren(false)
- .stream().filter(entry -> entry.getName().matches("\\d+(-prerestore)?"))
- .map(entry -> entry.getFullPath())
- .collect(Collectors.toList());
- Log.d(TAG, "getSnapshotDirectories=" + list);
- return list;
- } finally {
- getDevice().disableAdbRoot();
- }
- }
-
- private void assertDirectoryIsEmpty(String path) throws Exception {
- try {
- getDevice().enableAdbRoot();
- IFileEntry file = getDevice().getFileEntry(path);
- assertWithMessage("Not a directory: " + path).that(file.isDirectory()).isTrue();
- assertWithMessage("Directory not empty: " + path)
- .that(file.getChildren(false)).isEmpty();
- } catch (DeviceNotAvailableException e) {
- fail("Can't access directory: " + path);
- } finally {
- getDevice().disableAdbRoot();
- }
- }
-
private void startActivity(String packageName) throws Exception {
String cmd = "am start -S -a android.intent.action.MAIN "
+ "-c android.intent.category.LAUNCHER " + packageName;
getDevice().executeShellCommand(cmd);
}
- private void crashProcess(String processName, int numberOfCrashes) throws Exception {
- String pid = "";
- String lastPid = "invalid";
- for (int i = 0; i < numberOfCrashes; ++i) {
- // This condition makes sure before we kill the process, the process is running AND
- // the last crash was finished.
- while ("".equals(pid) || lastPid.equals(pid)) {
- pid = getDevice().executeShellCommand("pidof " + processName);
- }
- getDevice().executeShellCommand("kill " + pid);
- lastPid = pid;
- }
- }
-
- private boolean isCheckpointSupported() throws Exception {
- try {
- runPhase("isCheckpointSupported");
- return true;
- } catch (AssertionError ignore) {
- return false;
- }
- }
-
/**
* True if this build has mainline modules installed.
*/
@@ -726,17 +266,17 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
}
}
- @FunctionalInterface
- private interface ExceptionalRunnable {
- void run() throws Exception;
- }
-
- private void runAsRoot(ExceptionalRunnable runnable) throws Exception {
- try {
- getDevice().enableAdbRoot();
- runnable.run();
- } finally {
- getDevice().disableAdbRoot();
+ private void crashProcess(String processName, int numberOfCrashes) throws Exception {
+ String pid = "";
+ String lastPid = "invalid";
+ for (int i = 0; i < numberOfCrashes; ++i) {
+ // This condition makes sure before we kill the process, the process is running AND
+ // the last crash was finished.
+ while ("".equals(pid) || lastPid.equals(pid)) {
+ pid = getDevice().executeShellCommand("pidof " + processName);
+ }
+ getDevice().executeShellCommand("kill " + pid);
+ lastPid = pid;
}
}
}
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
index 2c6c8d7cae20..1381c0a43c30 100644
--- a/tests/SoundTriggerTestApp/res/layout/main.xml
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -73,6 +73,14 @@
android:text="@string/play_trigger"
android:onClick="onPlayTriggerButtonClicked"
android:padding="20dp" />
+
+ <Button
+ android:id="@+id/get_state_id"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/get_model_state"
+ android:onClick="onGetModelStateButtonClicked"
+ android:padding="20dp" />
</LinearLayout>
<LinearLayout
diff --git a/tests/SoundTriggerTestApp/res/values/strings.xml b/tests/SoundTriggerTestApp/res/values/strings.xml
index c48b64884c5e..adb0fcf8e185 100644
--- a/tests/SoundTriggerTestApp/res/values/strings.xml
+++ b/tests/SoundTriggerTestApp/res/values/strings.xml
@@ -22,6 +22,7 @@
<string name="start_recog">Start</string>
<string name="stop_recog">Stop</string>
<string name="play_trigger">Play Trigger Audio</string>
+ <string name="get_model_state">Get State</string>
<string name="capture">Capture Audio</string>
<string name="stop_capture">Stop Capturing Audio</string>
<string name="play_capture">Play Captured Audio</string>
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java
index c3c4cf556986..72aa38dc7e4b 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java
@@ -257,6 +257,14 @@ public class SoundTriggerTestActivity extends Activity implements SoundTriggerTe
}
}
+ public synchronized void onGetModelStateButtonClicked(View v) {
+ if (mService == null) {
+ Log.e(TAG, "Can't get model state: not bound to SoundTriggerTestService");
+ } else {
+ mService.getModelState(mSelectedModelUuid);
+ }
+ }
+
public synchronized void onCaptureAudioCheckboxClicked(View v) {
// See if we have the right permissions
if (!mService.hasMicrophonePermission()) {
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index 380e29984c63..6d4ffcff7d45 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -23,6 +23,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
@@ -46,6 +48,7 @@ import java.util.Properties;
import java.util.Random;
import java.util.UUID;
+
public class SoundTriggerTestService extends Service {
private static final String TAG = "SoundTriggerTestSrv";
private static final String INTENT_ACTION = "com.android.intent.action.MANAGE_SOUND_TRIGGER";
@@ -57,6 +60,8 @@ public class SoundTriggerTestService extends Service {
private Random mRandom;
private UserActivity mUserActivity;
+ private static int captureCount;
+
public interface UserActivity {
void addModel(UUID modelUuid, String state);
void setModelState(UUID modelUuid, String state);
@@ -131,6 +136,8 @@ public class SoundTriggerTestService extends Service {
} else if (command.equals("set_capture_timeout")) {
setCaptureAudioTimeout(getModelUuidFromIntent(intent),
intent.getIntExtra("timeout", 5000));
+ } else if (command.equals("get_model_state")) {
+ getModelState(getModelUuidFromIntent(intent));
} else {
Log.e(TAG, "Unknown command '" + command + "'");
}
@@ -432,6 +439,17 @@ public class SoundTriggerTestService extends Service {
return modelInfo != null && modelInfo.captureAudioTrack != null;
}
+ public synchronized void getModelState(UUID modelUuid) {
+ ModelInfo modelInfo = mModelInfoMap.get(modelUuid);
+ if (modelInfo == null) {
+ postError("Could not find model for: " + modelUuid.toString());
+ return;
+ }
+ int status = mSoundTriggerUtil.getModelState(modelUuid);
+ postMessage("GetModelState for: " + modelInfo.name + " returns: "
+ + status);
+ }
+
private void loadModelsInDataDir() {
// Load all the models in the data dir.
boolean loadedModel = false;
@@ -527,18 +545,29 @@ public class SoundTriggerTestService extends Service {
}
}
+
private class CaptureAudioRecorder implements Runnable {
private final ModelInfo mModelInfo;
+
+ // EventPayload and RecognitionEvent are equivalant. Only one will be non-null.
private final SoundTriggerDetector.EventPayload mEvent;
+ private final RecognitionEvent mRecognitionEvent;
public CaptureAudioRecorder(ModelInfo modelInfo, SoundTriggerDetector.EventPayload event) {
mModelInfo = modelInfo;
mEvent = event;
+ mRecognitionEvent = null;
+ }
+
+ public CaptureAudioRecorder(ModelInfo modelInfo, RecognitionEvent event) {
+ mModelInfo = modelInfo;
+ mEvent = null;
+ mRecognitionEvent = event;
}
@Override
public void run() {
- AudioFormat format = mEvent.getCaptureAudioFormat();
+ AudioFormat format = getAudioFormat();
if (format == null) {
postErrorToast("No audio format in recognition event.");
return;
@@ -600,18 +629,21 @@ public class SoundTriggerTestService extends Service {
}
audioRecord = new AudioRecord(attributes, format, bytesRequired,
- mEvent.getCaptureSession());
+ getCaptureSession());
byte[] buffer = new byte[bytesRequired];
// Create a file so we can save the output data there for analysis later.
FileOutputStream fos = null;
try {
- fos = new FileOutputStream( new File(
- getFilesDir() + File.separator
- + mModelInfo.name.replace(' ', '_')
- + "_capture_" + format.getChannelCount() + "ch_"
- + format.getSampleRate() + "hz_" + encoding + ".pcm"));
+ File file = new File(
+ getFilesDir() + File.separator
+ + mModelInfo.name.replace(' ', '_')
+ + "_capture_" + format.getChannelCount() + "ch_"
+ + format.getSampleRate() + "hz_" + encoding
+ + "_" + (++captureCount) + ".pcm");
+ Log.i(TAG, "Writing audio to: " + file);
+ fos = new FileOutputStream(file);
} catch (IOException e) {
Log.e(TAG, "Failed to open output for saving PCM data", e);
postErrorToast("Failed to open output for saving PCM data: "
@@ -635,6 +667,10 @@ public class SoundTriggerTestService extends Service {
bytesRequired -= bytesRead;
}
audioRecord.stop();
+ if (fos != null) {
+ fos.flush();
+ fos.close();
+ }
} catch (Exception e) {
Log.e(TAG, "Error recording trigger audio", e);
postErrorToast("Error recording trigger audio: " + e.getMessage());
@@ -651,6 +687,26 @@ public class SoundTriggerTestService extends Service {
setModelState(mModelInfo, "Recording finished");
}
}
+
+ private AudioFormat getAudioFormat() {
+ if (mEvent != null) {
+ return mEvent.getCaptureAudioFormat();
+ }
+ if (mRecognitionEvent != null) {
+ return mRecognitionEvent.captureFormat;
+ }
+ return null;
+ }
+
+ private int getCaptureSession() {
+ if (mEvent != null) {
+ return mEvent.getCaptureSession();
+ }
+ if (mRecognitionEvent != null) {
+ return mRecognitionEvent.captureSession;
+ }
+ return 0;
+ }
}
// Implementation of SoundTriggerDetector.Callback.
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
index cfe8c855ac81..996a78f2e42a 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
@@ -18,6 +18,8 @@ package com.android.test.soundtrigger;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.media.soundtrigger.SoundTriggerDetector;
import android.media.soundtrigger.SoundTriggerManager;
import android.os.RemoteException;
@@ -27,6 +29,7 @@ import android.util.Log;
import com.android.internal.app.ISoundTriggerService;
+import java.lang.reflect.Method;
import java.lang.RuntimeException;
import java.util.UUID;
@@ -50,13 +53,31 @@ public class SoundTriggerUtil {
* The sound model must contain a valid UUID.
*
* @param soundModel The sound model to add/update.
+ * @return The true if the model was loaded successfully, false otherwise.
*/
public boolean addOrUpdateSoundModel(SoundTriggerManager.Model soundModel) {
if (soundModel == null) {
throw new RuntimeException("Bad sound model");
}
mSoundTriggerManager.updateModel(soundModel);
- return true;
+ // TODO: call loadSoundModel in the soundtrigger manager updateModel method
+ // instead of here. It is needed to keep soundtrigger manager internal
+ // state consistent.
+ return mSoundTriggerManager
+ .loadSoundModel(getGenericSoundModel(soundModel)) == 0;
+ }
+
+ private GenericSoundModel getGenericSoundModel(
+ SoundTriggerManager.Model soundModel) {
+ try {
+ Method method = SoundTriggerManager.Model.class
+ .getDeclaredMethod("getGenericSoundModel");
+ method.setAccessible(true);
+ return (GenericSoundModel) method.invoke(soundModel);
+ } catch (ReflectiveOperationException e) {
+ Log.e(TAG, "Failed to getGenericSoundModel: " + soundModel, e);
+ return null;
+ }
}
/**
@@ -92,6 +113,16 @@ public class SoundTriggerUtil {
return true;
}
+ /**
+ * Get the current model state
+ *
+ * @param modelId The model ID to look-up the sound model for.
+ * @return 0 if the call succeeds, or an error code if it fails.
+ */
+ public int getModelState(UUID modelId) {
+ return mSoundTriggerManager.getModelState(modelId);
+ }
+
public SoundTriggerDetector createSoundTriggerDetector(UUID modelId,
SoundTriggerDetector.Callback callback) {
return mSoundTriggerManager.createSoundTriggerDetector(modelId, callback, null);
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index a5852b52ff19..7906f0973ae0 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -61,6 +61,7 @@ java_test_host {
":StagedInstallTestApexV2_WrongSha",
":TestAppAv1",
":test.rebootless_apex_v1",
+ ":test.rebootless_apex_v2",
],
test_suites: ["general-tests"],
test_config: "StagedInstallInternalTest.xml",
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index f0ab63eb41b5..b21d7b5d1f4a 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -44,6 +44,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.InstallUtils;
import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
import org.junit.After;
import org.junit.Before;
@@ -108,6 +109,7 @@ public class StagedInstallInternalTest {
@Test
public void cleanUp() throws Exception {
Files.deleteIfExists(mTestStateFile.toPath());
+ Uninstall.packages(TestApp.A, TestApp.B);
}
@Test
@@ -157,8 +159,18 @@ public class StagedInstallInternalTest {
@Test
public void testStagedSessionShouldCleanUpOnVerificationFailure() throws Exception {
+ // APEX verification
InstallUtils.commitExpectingFailure(AssertionError.class, "apexd verification failed",
Install.single(APEX_WRONG_SHA_V2).setStaged());
+ InstallUtils.commitExpectingFailure(AssertionError.class, "apexd verification failed",
+ Install.multi(APEX_WRONG_SHA_V2, TestApp.A1).setStaged());
+ // APK verification
+ Install.single(TestApp.A2).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ InstallUtils.commitExpectingFailure(AssertionError.class, "Downgrade detected",
+ Install.single(TestApp.A1).setStaged());
+ InstallUtils.commitExpectingFailure(AssertionError.class, "Downgrade detected",
+ Install.multi(TestApp.A1, TestApp.B1).setStaged());
}
@Test
@@ -176,6 +188,12 @@ public class StagedInstallInternalTest {
}
@Test
+ public void testStagedSessionShouldCleanUpOnOnSuccessMultiPackage_Commit() throws Exception {
+ int sessionId = Install.multi(TestApp.A1, TestApp.Apex2).setStaged().commit();
+ storeSessionId(sessionId);
+ }
+
+ @Test
public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK",
Install.single(TestApp.AIncompleteSplit).setStaged());
@@ -483,6 +501,18 @@ public class StagedInstallInternalTest {
assertThat(captor.getValue().stagedApexModuleNames).hasLength(0);
}
+ @Test
+ public void testRebootlessDowngrade() throws Exception {
+ final String packageName = "test.apex.rebootless";
+ assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(2);
+ TestApp apex1 = new TestApp("TestRebootlessApexV1", packageName, 1,
+ /* isApex= */ true, "test.rebootless_apex_v1.apex");
+ InstallUtils.commitExpectingFailure(AssertionError.class,
+ "INSTALL_FAILED_VERSION_DOWNGRADE", Install.single(apex1));
+ Install.single(apex1).setRequestDowngrade().commit();
+ assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(1);
+ }
+
private IPackageManagerNative getPackageManagerNative() {
IBinder binder = ServiceManager.waitForService("package_native");
assertThat(binder).isNotNull();
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index cd0078363c4b..f06fa81e790c 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -92,7 +92,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
- "/system/apex/test.rebootless_apex_v1.apex",
+ "/system/apex/test.rebootless_apex_v*.apex",
"/data/apex/active/test.apex.rebootless*.apex",
TEST_VENDOR_APEX_ALLOW_LIST);
}
@@ -112,6 +112,10 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
* @param files the paths of files which might contain wildcards
*/
private void deleteFiles(String... files) throws Exception {
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+
boolean found = false;
for (String file : files) {
CommandResult result = getDevice().executeShellV2Command("ls " + file);
@@ -122,9 +126,6 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
}
if (found) {
- if (!getDevice().isAdbRoot()) {
- getDevice().enableAdbRoot();
- }
getDevice().remountSystemWritable();
for (String file : files) {
getDevice().executeShellCommand("rm -rf " + file);
@@ -301,6 +302,18 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
}
@Test
+ @LargeTest
+ public void testStagedSessionShouldCleanUpOnOnSuccessMultiPackage() throws Exception {
+ List<String> before = getStagingDirectories();
+ runPhase("testStagedSessionShouldCleanUpOnOnSuccessMultiPackage_Commit");
+ assertThat(getStagingDirectories()).isNotEqualTo(before);
+ getDevice().reboot();
+ runPhase("testStagedSessionShouldCleanUpOnOnSuccess_Verify");
+ List<String> after = getStagingDirectories();
+ assertThat(after).isEqualTo(before);
+ }
+
+ @Test
public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
List<String> before = getStagingDirectories();
runPhase("testStagedInstallationShouldCleanUpOnValidationFailure");
@@ -507,6 +520,13 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
runPhase("testStagedApexObserver");
}
+ @Test
+ public void testRebootlessDowngrade() throws Exception {
+ pushTestApex("test.rebootless_apex_v2.apex");
+ getDevice().reboot();
+ runPhase("testRebootlessDowngrade");
+ }
+
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
String baseDir = "/data/app-staging";
try {
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
index e07fbbf7a1c1..c59a41ee0cd3 100644
--- a/tests/UpdatableSystemFontTest/Android.bp
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -37,15 +37,19 @@ android_test {
"vts",
],
data: [
- ":NotoColorEmojiTtf",
+ ":NotoSerif-Regular.ttf",
+ ":NotoSerif-Bold.ttf",
":UpdatableSystemFontTestCertDer",
- ":UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
- ":UpdatableSystemFontTestNotoColorEmojiV0Ttf",
- ":UpdatableSystemFontTestNotoColorEmojiV0TtfFsvSig",
- ":UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf",
- ":UpdatableSystemFontTestNotoColorEmojiVPlus1TtfFsvSig",
- ":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
- ":UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
+ ":UpdatableSystemFontTest_NotoColorEmoji.ttf",
+ ":UpdatableSystemFontTest_NotoColorEmoji.sig",
+ ":UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
+ ":UpdatableSystemFontTest_NotoColorEmojiV0.sig",
+ ":UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf",
+ ":UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig",
+ ":UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf",
+ ":UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig",
+ ":UpdatableSystemFontTest_NotoSerif-Regular.sig",
+ ":UpdatableSystemFontTest_NotoSerif-Bold.sig",
],
sdk_version: "test_current",
}
diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml
index 4f6487e7e953..6effa7bd0a50 100644
--- a/tests/UpdatableSystemFontTest/AndroidTest.xml
+++ b/tests/UpdatableSystemFontTest/AndroidTest.xml
@@ -29,13 +29,17 @@
<option name="cleanup" value="true" />
<option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
<option name="push" value="NotoColorEmoji.ttf->/data/local/tmp/NotoColorEmoji.ttf" />
- <option name="push" value="UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig" />
- <option name="push" value="UpdatableSystemFontTestNotoColorEmojiV0.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf" />
- <option name="push" value="UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig" />
- <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf" />
- <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig" />
- <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf" />
- <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig" />
+ <option name="push" value="NotoSerif-Regular.ttf->/data/local/tmp/NotoSerif-Regular.ttf" />
+ <option name="push" value="NotoSerif-Bold.ttf->/data/local/tmp/NotoSerif-Bold.ttf" />
+ <option name="push" value="UpdatableSystemFontTest_NotoSerif-Regular.sig->/data/local/tmp/UpdatableSystemFontTest_NotoSerif-Regular.sig" />
+ <option name="push" value="UpdatableSystemFontTest_NotoSerif-Bold.sig->/data/local/tmp/UpdatableSystemFontTest_NotoSerif-Bold.sig" />
+ <option name="push" value="UpdatableSystemFontTest_NotoColorEmoji.sig->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmoji.sig" />
+ <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiV0.ttf->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiV0.ttf" />
+ <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiV0.sig->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiV0.sig" />
+ <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf" />
+ <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig" />
+ <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf" />
+ <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
index 947e9c2ff56a..a8c27fb0f116 100644
--- a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
@@ -20,6 +20,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import android.app.Activity;
+import android.graphics.Typeface;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -27,14 +28,20 @@ import android.widget.TextView;
/** Test app to render an emoji. */
public class EmojiRenderingTestActivity extends Activity {
+ private static final String TEST_NOTO_SERIF = "test-noto-serif";
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout container = new LinearLayout(this);
container.setOrientation(LinearLayout.VERTICAL);
- TextView textView = new TextView(this);
- textView.setText("\uD83E\uDD72"); // 🥲
- container.addView(textView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ TextView emojiTextView = new TextView(this);
+ emojiTextView.setText("\uD83E\uDD72"); // 🥲
+ container.addView(emojiTextView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ TextView serifTextView = new TextView(this);
+ serifTextView.setTypeface(Typeface.create(TEST_NOTO_SERIF, Typeface.NORMAL));
+ serifTextView.setText(TEST_NOTO_SERIF);
+ container.addView(serifTextView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
setContentView(container);
}
}
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
index 6bd07d0a84fd..87fda0d220e5 100644
--- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -16,6 +16,9 @@
package com.android.updatablesystemfont;
+import static android.graphics.fonts.FontStyle.FONT_SLANT_UPRIGHT;
+import static android.graphics.fonts.FontStyle.FONT_WEIGHT_BOLD;
+import static android.graphics.fonts.FontStyle.FONT_WEIGHT_NORMAL;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static com.google.common.truth.Truth.assertThat;
@@ -30,6 +33,7 @@ import android.content.Context;
import android.graphics.fonts.FontFamilyUpdateRequest;
import android.graphics.fonts.FontFileUpdateRequest;
import android.graphics.fonts.FontManager;
+import android.graphics.fonts.FontStyle;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.RootPermissionTest;
import android.security.FileIntegrityManager;
@@ -77,31 +81,45 @@ public class UpdatableSystemFontTest {
private static final String SYSTEM_FONTS_DIR = "/system/fonts/";
private static final String DATA_FONTS_DIR = "/data/fonts/files/";
private static final String CERT_PATH = "/data/local/tmp/UpdatableSystemFontTestCert.der";
- private static final String NOTO_COLOR_EMOJI_POSTSCRIPT_NAME = "NotoColorEmoji";
- private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF =
+ private static final String NOTO_COLOR_EMOJI_POSTSCRIPT_NAME = "NotoColorEmoji";
+ private static final String NOTO_COLOR_EMOJI_TTF =
"/data/local/tmp/NotoColorEmoji.ttf";
- private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG =
- "/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig";
+ private static final String NOTO_COLOR_EMOJI_SIG =
+ "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmoji.sig";
// A font with revision == 0.
private static final String TEST_NOTO_COLOR_EMOJI_V0_TTF =
- "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf";
- private static final String TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG =
- "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig";
+ "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiV0.ttf";
+ private static final String TEST_NOTO_COLOR_EMOJI_V0_SIG =
+ "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiV0.sig";
// A font with revision == original + 1
private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF =
- "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf";
- private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG =
- "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig";
+ "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf";
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG =
+ "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig";
// A font with revision == original + 2
private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF =
- "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf";
- private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG =
- "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig";
+ "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf";
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_SIG =
+ "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig";
+
+ private static final String NOTO_SERIF_REGULAR_POSTSCRIPT_NAME = "NotoSerif";
+ private static final String NOTO_SERIF_REGULAR_TTF =
+ "/data/local/tmp/NotoSerif-Regular.ttf";
+ private static final String NOTO_SERIF_REGULAR_SIG =
+ "/data/local/tmp/UpdatableSystemFontTest_NotoSerif-Regular.sig";
+
+ private static final String NOTO_SERIF_BOLD_POSTSCRIPT_NAME = "NotoSerif-Bold";
+ private static final String NOTO_SERIF_BOLD_TTF =
+ "/data/local/tmp/NotoSerif-Bold.ttf";
+ private static final String NOTO_SERIF_BOLD_SIG =
+ "/data/local/tmp/UpdatableSystemFontTest_NotoSerif-Bold.sig";
private static final String EMOJI_RENDERING_TEST_APP_ID = "com.android.emojirenderingtestapp";
private static final String EMOJI_RENDERING_TEST_ACTIVITY =
EMOJI_RENDERING_TEST_APP_ID + "/.EmojiRenderingTestActivity";
+ // This should be the same as the one in EmojiRenderingTestActivity.
+ private static final String TEST_NOTO_SERIF = "test-noto-serif";
private static final long ACTIVITY_TIMEOUT_MILLIS = SECONDS.toMillis(10);
private static final String GET_AVAILABLE_FONTS_TEST_ACTIVITY =
@@ -141,11 +159,20 @@ public class UpdatableSystemFontTest {
@Test
public void updateFont() throws Exception {
+ FontConfig oldFontConfig =
+ SystemUtil.callWithShellPermissionIdentity(mFontManager::getFontConfig);
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
.isEqualTo(FontManager.RESULT_SUCCESS);
+ // Check that font config is updated.
String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+ FontConfig newFontConfig =
+ SystemUtil.callWithShellPermissionIdentity(mFontManager::getFontConfig);
+ assertThat(newFontConfig.getConfigVersion())
+ .isGreaterThan(oldFontConfig.getConfigVersion());
+ assertThat(newFontConfig.getLastModifiedTimeMillis())
+ .isGreaterThan(oldFontConfig.getLastModifiedTimeMillis());
// The updated font should be readable and unmodifiable.
expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null");
expectCommandToFail("dd status=none if=" + CERT_PATH + " of=" + fontPath);
@@ -154,11 +181,11 @@ public class UpdatableSystemFontTest {
@Test
public void updateFont_twice() throws Exception {
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
.isEqualTo(FontManager.RESULT_SUCCESS);
String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_SIG))
.isEqualTo(FontManager.RESULT_SUCCESS);
String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
@@ -173,16 +200,16 @@ public class UpdatableSystemFontTest {
public void updateFont_allowSameVersion() throws Exception {
// Update original font to the same version
assertThat(updateFontFile(
- ORIGINAL_NOTO_COLOR_EMOJI_TTF, ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG))
+ NOTO_COLOR_EMOJI_TTF, NOTO_COLOR_EMOJI_SIG))
.isEqualTo(FontManager.RESULT_SUCCESS);
String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
.isEqualTo(FontManager.RESULT_SUCCESS);
String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
// Update updated font to the same version
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
.isEqualTo(FontManager.RESULT_SUCCESS);
String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
assertThat(fontPath).startsWith(DATA_FONTS_DIR);
@@ -195,28 +222,58 @@ public class UpdatableSystemFontTest {
@Test
public void updateFont_invalidCert() throws Exception {
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_SIG))
.isEqualTo(FontManager.RESULT_ERROR_VERIFICATION_FAILURE);
}
@Test
public void updateFont_downgradeFromSystem() throws Exception {
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_SIG))
.isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
}
@Test
public void updateFont_downgradeFromData() throws Exception {
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_SIG))
.isEqualTo(FontManager.RESULT_SUCCESS);
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
.isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
}
@Test
+ public void updateFontFamily() throws Exception {
+ assertThat(updateNotoSerifAs("serif")).isEqualTo(FontManager.RESULT_SUCCESS);
+ FontConfig.FontFamily family = findFontFamilyOrThrow("serif");
+ assertThat(family.getFontList()).hasSize(2);
+ assertThat(family.getFontList().get(0).getPostScriptName())
+ .isEqualTo(NOTO_SERIF_REGULAR_POSTSCRIPT_NAME);
+ assertThat(family.getFontList().get(0).getFile().getAbsolutePath())
+ .startsWith(DATA_FONTS_DIR);
+ assertThat(family.getFontList().get(0).getStyle().getWeight())
+ .isEqualTo(FONT_WEIGHT_NORMAL);
+ assertThat(family.getFontList().get(1).getPostScriptName())
+ .isEqualTo(NOTO_SERIF_BOLD_POSTSCRIPT_NAME);
+ assertThat(family.getFontList().get(1).getFile().getAbsolutePath())
+ .startsWith(DATA_FONTS_DIR);
+ assertThat(family.getFontList().get(1).getStyle().getWeight()).isEqualTo(FONT_WEIGHT_BOLD);
+ }
+
+ @Test
+ public void updateFontFamily_asNewFont() throws Exception {
+ assertThat(updateNotoSerifAs("UpdatableSystemFontTest-serif"))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ FontConfig.FontFamily family = findFontFamilyOrThrow("UpdatableSystemFontTest-serif");
+ assertThat(family.getFontList()).hasSize(2);
+ assertThat(family.getFontList().get(0).getPostScriptName())
+ .isEqualTo(NOTO_SERIF_REGULAR_POSTSCRIPT_NAME);
+ assertThat(family.getFontList().get(1).getPostScriptName())
+ .isEqualTo(NOTO_SERIF_BOLD_POSTSCRIPT_NAME);
+ }
+
+ @Test
public void launchApp() throws Exception {
String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
assertThat(fontPath).startsWith(SYSTEM_FONTS_DIR);
@@ -231,22 +288,25 @@ public class UpdatableSystemFontTest {
String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
assertThat(originalFontPath).startsWith(SYSTEM_FONTS_DIR);
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
.isEqualTo(FontManager.RESULT_SUCCESS);
String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
assertThat(updatedFontPath).startsWith(DATA_FONTS_DIR);
+ updateNotoSerifAs(TEST_NOTO_SERIF);
+ String notoSerifPath = getFontPath(NOTO_SERIF_REGULAR_POSTSCRIPT_NAME);
startActivity(EMOJI_RENDERING_TEST_APP_ID, EMOJI_RENDERING_TEST_ACTIVITY);
// The original font should NOT be opened by the app.
SystemUtil.eventually(() -> {
assertThat(isFileOpenedBy(updatedFontPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue();
assertThat(isFileOpenedBy(originalFontPath, EMOJI_RENDERING_TEST_APP_ID)).isFalse();
+ assertThat(isFileOpenedBy(notoSerifPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue();
}, ACTIVITY_TIMEOUT_MILLIS);
}
@Test
public void reboot() throws Exception {
expectCommandToSucceed(String.format("cmd font update %s %s",
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG));
String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
assertThat(fontPath).startsWith(DATA_FONTS_DIR);
@@ -264,7 +324,7 @@ public class UpdatableSystemFontTest {
Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF));
for (int i = 0; i < 10; i++) {
assertThat(updateFontFile(
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
.isEqualTo(FontManager.RESULT_SUCCESS);
List<String> openFiles = getOpenFiles("system_server");
for (Pattern p : Arrays.asList(PATTERN_FONT_FILES, PATTERN_SYSTEM_FONT_FILES,
@@ -285,7 +345,7 @@ public class UpdatableSystemFontTest {
public void fdLeakTest_withoutPermission() throws Exception {
Pattern patternEmojiVPlus1 =
Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF));
- byte[] signature = Files.readAllBytes(Paths.get(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+ byte[] signature = Files.readAllBytes(Paths.get(TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG));
try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(
new File(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF), MODE_READ_ONLY)) {
assertThrows(SecurityException.class,
@@ -340,18 +400,56 @@ public class UpdatableSystemFontTest {
configVersion);
}
+ private int updateNotoSerifAs(String familyName) throws IOException {
+ List<FontFamilyUpdateRequest.Font> fonts = Arrays.asList(
+ new FontFamilyUpdateRequest.Font.Builder(NOTO_SERIF_REGULAR_POSTSCRIPT_NAME,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT)).build(),
+ new FontFamilyUpdateRequest.Font.Builder(NOTO_SERIF_BOLD_POSTSCRIPT_NAME,
+ new FontStyle(FONT_WEIGHT_BOLD, FONT_SLANT_UPRIGHT)).build());
+ FontFamilyUpdateRequest.FontFamily fontFamily =
+ new FontFamilyUpdateRequest.FontFamily.Builder(familyName, fonts).build();
+ byte[] regularSig = Files.readAllBytes(Paths.get(NOTO_SERIF_REGULAR_SIG));
+ byte[] boldSig = Files.readAllBytes(Paths.get(NOTO_SERIF_BOLD_SIG));
+ try (ParcelFileDescriptor regularFd = ParcelFileDescriptor.open(
+ new File(NOTO_SERIF_REGULAR_TTF), MODE_READ_ONLY);
+ ParcelFileDescriptor boldFd = ParcelFileDescriptor.open(
+ new File(NOTO_SERIF_BOLD_TTF), MODE_READ_ONLY)) {
+ return SystemUtil.runWithShellPermissionIdentity(() -> {
+ FontConfig fontConfig = mFontManager.getFontConfig();
+ return mFontManager.updateFontFamily(new FontFamilyUpdateRequest.Builder()
+ .addFontFileUpdateRequest(
+ new FontFileUpdateRequest(regularFd, regularSig))
+ .addFontFileUpdateRequest(
+ new FontFileUpdateRequest(boldFd, boldSig))
+ .addFontFamily(fontFamily)
+ .build(), fontConfig.getConfigVersion());
+ });
+ }
+ }
+
private String getFontPath(String psName) {
- return SystemUtil.runWithShellPermissionIdentity(() -> {
- FontConfig fontConfig = mFontManager.getFontConfig();
- for (FontConfig.FontFamily family : fontConfig.getFontFamilies()) {
- for (FontConfig.Font font : family.getFontList()) {
- if (psName.equals(font.getPostScriptName())) {
- return font.getFile().getAbsolutePath();
- }
- }
- }
- throw new AssertionError("Font not found: " + psName);
- });
+ FontConfig fontConfig =
+ SystemUtil.runWithShellPermissionIdentity(mFontManager::getFontConfig);
+ return fontConfig.getFontFamilies().stream()
+ .flatMap(family -> family.getFontList().stream())
+ .filter(font -> psName.equals(font.getPostScriptName()))
+ // Return the last match, because the latter family takes precedence if two families
+ // have the same name.
+ .reduce((first, second) -> second)
+ .orElseThrow(() -> new AssertionError("Font not found: " + psName))
+ .getFile()
+ .getAbsolutePath();
+ }
+
+ private FontConfig.FontFamily findFontFamilyOrThrow(String familyName) {
+ FontConfig fontConfig =
+ SystemUtil.runWithShellPermissionIdentity(mFontManager::getFontConfig);
+ return fontConfig.getFontFamilies().stream()
+ .filter(family -> familyName.equals(family.getName()))
+ // Return the last match, because the latter family takes precedence if two families
+ // have the same name.
+ .reduce((first, second) -> second)
+ .orElseThrow(() -> new AssertionError("Family not found: " + familyName));
}
private static void startActivity(String appId, String activityId) throws Exception {
diff --git a/tests/UpdatableSystemFontTest/testdata/Android.bp b/tests/UpdatableSystemFontTest/testdata/Android.bp
index 426464ea574e..64b698dd0db0 100644
--- a/tests/UpdatableSystemFontTest/testdata/Android.bp
+++ b/tests/UpdatableSystemFontTest/testdata/Android.bp
@@ -22,9 +22,9 @@ package {
}
// An existing module name is reused to avoid merge conflicts.
-// TODO: fix the font and module name.
+// TODO: fix the font file name.
filegroup {
- name: "NotoColorEmojiTtf",
+ name: "UpdatableSystemFontTest_NotoColorEmoji.ttf",
srcs: ["NotoColorEmoji.ttf"],
}
@@ -48,9 +48,9 @@ genrule_defaults {
}
genrule {
- name: "UpdatableSystemFontTestNotoColorEmojiV0Ttf",
- srcs: [":NotoColorEmojiTtf"],
- out: ["UpdatableSystemFontTestNotoColorEmojiV0.ttf"],
+ name: "UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
+ srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
+ out: ["UpdatableSystemFontTest_NotoColorEmojiV0.ttf"],
tools: ["update_font_metadata"],
cmd: "$(location update_font_metadata) " +
"--input=$(in) " +
@@ -59,9 +59,9 @@ genrule {
}
genrule {
- name: "UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf",
- srcs: [":NotoColorEmojiTtf"],
- out: ["UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf"],
+ name: "UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf",
+ srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
+ out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf"],
tools: ["update_font_metadata"],
cmd: "$(location update_font_metadata) " +
"--input=$(in) " +
@@ -70,9 +70,9 @@ genrule {
}
genrule {
- name: "UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
- srcs: [":NotoColorEmojiTtf"],
- out: ["UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf"],
+ name: "UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf",
+ srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
+ out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf"],
tools: ["update_font_metadata"],
cmd: "$(location update_font_metadata) " +
"--input=$(in) " +
@@ -94,29 +94,43 @@ genrule_defaults {
}
genrule {
- name: "UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
+ name: "UpdatableSystemFontTest_NotoColorEmoji.sig",
defaults: ["updatable_system_font_sig_gen_default"],
- srcs: [":NotoColorEmojiTtf"],
- out: ["UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig"],
+ srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
+ out: ["UpdatableSystemFontTest_NotoColorEmoji.sig"],
}
genrule {
- name: "UpdatableSystemFontTestNotoColorEmojiV0TtfFsvSig",
+ name: "UpdatableSystemFontTest_NotoColorEmojiV0.sig",
defaults: ["updatable_system_font_sig_gen_default"],
- srcs: [":UpdatableSystemFontTestNotoColorEmojiV0Ttf"],
- out: ["UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig"],
+ srcs: [":UpdatableSystemFontTest_NotoColorEmojiV0.ttf"],
+ out: ["UpdatableSystemFontTest_NotoColorEmojiV0.sig"],
}
genrule {
- name: "UpdatableSystemFontTestNotoColorEmojiVPlus1TtfFsvSig",
+ name: "UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig",
defaults: ["updatable_system_font_sig_gen_default"],
- srcs: [":UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf"],
- out: ["UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig"],
+ srcs: [":UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf"],
+ out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig"],
}
genrule {
- name: "UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
+ name: "UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig",
defaults: ["updatable_system_font_sig_gen_default"],
- srcs: [":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf"],
- out: ["UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig"],
+ srcs: [":UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf"],
+ out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig"],
+}
+
+genrule {
+ name: "UpdatableSystemFontTest_NotoSerif-Regular.sig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":NotoSerif-Regular.ttf"],
+ out: ["UpdatableSystemFontTest_NotoSerif-Regular.sig"],
+}
+
+genrule {
+ name: "UpdatableSystemFontTest_NotoSerif-Bold.sig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":NotoSerif-Bold.ttf"],
+ out: ["UpdatableSystemFontTest_NotoSerif-Bold.sig"],
}
diff --git a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
index 7e8a13470c35..f695cbd5daf9 100644
--- a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
+++ b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
@@ -62,12 +62,13 @@ public class UsageStatsDatabasePerfTest {
private static final StatCombiner<UsageEvents.Event> sUsageStatsCombiner =
new StatCombiner<UsageEvents.Event>() {
@Override
- public void combine(IntervalStats stats, boolean mutable,
+ public boolean combine(IntervalStats stats, boolean mutable,
List<UsageEvents.Event> accResult) {
final int size = stats.events.size();
for (int i = 0; i < size; i++) {
accResult.add(stats.events.get(i));
}
+ return true;
}
};
diff --git a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
index e4880fd10d67..1341c85feec3 100644
--- a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
+++ b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
@@ -62,7 +62,7 @@ public class TestEnrollmentActivity extends Activity {
public void onEnrollButtonClicked(View v) {
Keyphrase kp = new Keyphrase(KEYPHRASE_ID, RECOGNITION_MODES,
Locale.forLanguageTag(BCP47_LOCALE), TEXT,
- new int[] { UserManager.get(this).getUserHandle() /* current user */});
+ new int[] { UserManager.get(this).getProcessUserId() /* current user */});
UUID modelUuid = UUID.randomUUID();
// Generate a fake model to push.
byte[] data = new byte[1024];
diff --git a/tests/componentalias/Android.bp b/tests/componentalias/Android.bp
new file mode 100644
index 000000000000..e5eb3c7b6394
--- /dev/null
+++ b/tests/componentalias/Android.bp
@@ -0,0 +1,87 @@
+// Copyright (C) 2021 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_defaults {
+ name: "ComponentAliasTests_defaults",
+ static_libs: [
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "mockito-target-extended-minus-junit4",
+ "truth-prebuilt",
+ "ub-uiautomator",
+ ],
+ libs: ["android.test.base"],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ platform_apis: true, // We use hidden APIs in the test.
+}
+
+// We build three APKs from the exact same source files, so these APKs contain the exact same tests.
+// And we run the tests on each APK, so that we can test various situations:
+// - When the alias is in the same package, target in the same package.
+// - When the alias is in the same package, target in another package.
+// - When the alias is in another package, which also contains the target.
+// - When the alias is in another package, and the target is in yet another package.
+// etc etc...
+
+android_test {
+ name: "ComponentAliasTests",
+ defaults: [
+ "ComponentAliasTests_defaults",
+ ],
+ package_name: "android.content.componentalias.tests",
+ manifest: "AndroidManifest.xml",
+ additional_manifests: [
+ "AndroidManifest_main.xml",
+ "AndroidManifest_service_aliases.xml",
+ "AndroidManifest_service_targets.xml",
+ ],
+ test_config_template: "AndroidTest-template.xml",
+}
+
+android_test {
+ name: "ComponentAliasTests1",
+ defaults: [
+ "ComponentAliasTests_defaults",
+ ],
+ package_name: "android.content.componentalias.tests.sub1",
+ manifest: "AndroidManifest.xml",
+ additional_manifests: [
+ "AndroidManifest_sub1.xml",
+ "AndroidManifest_service_targets.xml",
+ ],
+ test_config_template: "AndroidTest-template.xml",
+}
+
+android_test {
+ name: "ComponentAliasTests2",
+ defaults: [
+ "ComponentAliasTests_defaults",
+ ],
+ package_name: "android.content.componentalias.tests.sub2",
+ manifest: "AndroidManifest.xml",
+ additional_manifests: [
+ "AndroidManifest_sub2.xml",
+ "AndroidManifest_service_targets.xml",
+ ],
+ test_config_template: "AndroidTest-template.xml",
+}
diff --git a/tests/componentalias/AndroidManifest.xml b/tests/componentalias/AndroidManifest.xml
new file mode 100755
index 000000000000..7bb83a336833
--- /dev/null
+++ b/tests/componentalias/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 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.content.componentalias.tests" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <property android:name="com.android.EXPERIMENTAL_COMPONENT_ALIAS_OPT_IN" android:value="true" />
+ </application>
+</manifest>
diff --git a/tests/componentalias/AndroidManifest_main.xml b/tests/componentalias/AndroidManifest_main.xml
new file mode 100755
index 000000000000..70e817ebf3e7
--- /dev/null
+++ b/tests/componentalias/AndroidManifest_main.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 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.content.componentalias.tests" >
+
+ <application>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.content.componentalias.tests" >
+ </instrumentation>
+</manifest>
diff --git a/tests/componentalias/AndroidManifest_service_aliases.xml b/tests/componentalias/AndroidManifest_service_aliases.xml
new file mode 100644
index 000000000000..e73bb6102fbf
--- /dev/null
+++ b/tests/componentalias/AndroidManifest_service_aliases.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 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.content.componentalias.tests" >
+ <application>
+ <!--
+ Note the alias components are essentially just placeholders, so the APKs don't have to
+ have the implementation classes.
+ -->
+ <service android:name=".s.Alias00" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests/android.content.componentalias.tests.s.Target00" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_00" /></intent-filter>
+ </service>
+ <service android:name=".s.Alias01" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub1/android.content.componentalias.tests.s.Target01" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_01" /></intent-filter>
+ </service>
+ <service android:name=".s.Alias02" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub2/android.content.componentalias.tests.s.Target02" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_02" /></intent-filter>
+ </service>
+ <service android:name=".s.Alias03" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub1/android.content.componentalias.tests.s.Target03" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_03" /></intent-filter>
+ </service>
+ <service android:name=".s.Alias04" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub2/android.content.componentalias.tests.s.Target04" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_ALIAS_04" /></intent-filter>
+ </service>
+
+ <receiver android:name=".b.Alias00" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests/android.content.componentalias.tests.b.Target00" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_00" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ <receiver android:name=".b.Alias01" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub1/android.content.componentalias.tests.b.Target01" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_01" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ <receiver android:name=".b.Alias02" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub2/android.content.componentalias.tests.b.Target02" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_02" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ <receiver android:name=".b.Alias03" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub1/android.content.componentalias.tests.b.Target03" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_03" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ <receiver android:name=".b.Alias04" android:exported="true" android:enabled="true" >
+ <meta-data android:name="alias_target" android:value="android.content.componentalias.tests.sub2/android.content.componentalias.tests.b.Target04" />
+ <intent-filter><action android:name="android.intent.action.EXPERIMENTAL_IS_ALIAS" /></intent-filter>
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_04" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ </application>
+</manifest>
diff --git a/tests/componentalias/AndroidManifest_service_targets.xml b/tests/componentalias/AndroidManifest_service_targets.xml
new file mode 100644
index 000000000000..24c0432bcf4c
--- /dev/null
+++ b/tests/componentalias/AndroidManifest_service_targets.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 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.content.componentalias.tests" >
+ <application>
+ <service android:name=".s.Target00" android:exported="true" android:enabled="true" >
+ </service>
+ <service android:name=".s.Target01" android:exported="true" android:enabled="true" >
+ </service>
+ <service android:name=".s.Target02" android:exported="true" android:enabled="true" >
+ </service>
+ <service android:name=".s.Target03" android:exported="true" android:enabled="true" >
+ </service>
+ <service android:name=".s.Target04" android:exported="true" android:enabled="true" >
+ </service>
+
+ <!--
+ Due to http://go/intents-match-intent-filters-guide, the target intent has to have
+ an intent filter that matches the original intent. (modulo the package name)
+ This restriction shouldn't exist in the final version.
+ -->
+ <receiver android:name=".b.Target00" android:exported="true" android:enabled="true" >
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_00" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ <receiver android:name=".b.Target01" android:exported="true" android:enabled="true" >
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_01" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ <receiver android:name=".b.Target02" android:exported="true" android:enabled="true" >
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_02" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ <receiver android:name=".b.Target03" android:exported="true" android:enabled="true" >
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_03" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ <receiver android:name=".b.Target04" android:exported="true" android:enabled="true" >
+ <intent-filter><action android:name="android.content.componentalias.tests.IS_RECEIVER_04" /></intent-filter>
+ <intent-filter><action android:name="ACTION_BROADCAST" /></intent-filter>
+ </receiver>
+ </application>
+</manifest>
diff --git a/tests/componentalias/AndroidManifest_sub1.xml b/tests/componentalias/AndroidManifest_sub1.xml
new file mode 100755
index 000000000000..21616f5edf00
--- /dev/null
+++ b/tests/componentalias/AndroidManifest_sub1.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 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.content.componentalias.tests" >
+
+ <application>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.content.componentalias.tests.sub1" >
+ </instrumentation>
+</manifest>
diff --git a/tests/componentalias/AndroidManifest_sub2.xml b/tests/componentalias/AndroidManifest_sub2.xml
new file mode 100755
index 000000000000..c11b0cd55ef4
--- /dev/null
+++ b/tests/componentalias/AndroidManifest_sub2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 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.content.componentalias.tests" >
+
+ <application>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.content.componentalias.tests.sub2" >
+ </instrumentation>
+</manifest>
diff --git a/tests/componentalias/AndroidTest-template.xml b/tests/componentalias/AndroidTest-template.xml
new file mode 100644
index 000000000000..2d4621702329
--- /dev/null
+++ b/tests/componentalias/AndroidTest-template.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="ComponentAliasTests.apk" />
+ <option name="test-file-name" value="ComponentAliasTests1.apk" />
+ <option name="test-file-name" value="ComponentAliasTests2.apk" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android" />
+
+ <!-- Exempt the helper APKs from the BG restriction, so they can start BG services. -->
+ <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests" />
+ <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests.sub1" />
+ <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests.sub2" />
+
+ <option name="teardown-command" value="cmd deviceidle whitelist -android.content.componentalias.tests" />
+ <option name="teardown-command" value="cmd deviceidle whitelist -android.content.componentalias.tests.sub1" />
+ <option name="teardown-command" value="cmd deviceidle whitelist -android.content.componentalias.tests.sub2" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="{PACKAGE}" />
+ <option name="runtime-hint" value="2m" />
+ <option name="isolated-storage" value="false" />
+ </test>
+</configuration>
diff --git a/tests/componentalias/OWNERS b/tests/componentalias/OWNERS
new file mode 100644
index 000000000000..1073c817d793
--- /dev/null
+++ b/tests/componentalias/OWNERS
@@ -0,0 +1,2 @@
+omakoto@google.com
+yamasani@google.com \ No newline at end of file
diff --git a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
new file mode 100644
index 000000000000..89db2f724302
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.provider.DeviceConfig;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.DeviceConfigStateHelper;
+import com.android.compatibility.common.util.ShellUtils;
+import com.android.compatibility.common.util.TestUtils;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+
+import java.util.function.Consumer;
+
+public class BaseComponentAliasTest {
+ protected static final Context sContext = InstrumentationRegistry.getTargetContext();
+
+ protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+ @Before
+ public void enableComponentAlias() throws Exception {
+ sDeviceConfig.set("component_alias_overrides", "");
+
+ // Make sure the feature is actually enabled.
+ TestUtils.waitUntil("Wait until component alias is actually enabled", () -> {
+ return ShellUtils.runShellCommand("dumpsys activity component-alias")
+ .indexOf("Enabled: true") > 0;
+ });
+ }
+
+ @AfterClass
+ public static void restoreDeviceConfig() throws Exception {
+ sDeviceConfig.close();
+ }
+
+ protected static void log(String message) {
+ Log.i(ComponentAliasTestCommon.TAG, "[" + sContext.getPackageName() + "] " + message);
+ }
+
+ /**
+ * Defines a test target.
+ */
+ public static class Combo {
+ public final ComponentName alias;
+ public final ComponentName target;
+ public final String action;
+
+ public Combo(ComponentName alias, ComponentName target, String action) {
+ this.alias = alias;
+ this.target = target;
+ this.action = action;
+ }
+
+ @Override
+ public String toString() {
+ return "Combo{"
+ + "alias=" + toString(alias)
+ + ", target=" + toString(target)
+ + ", action='" + action + '\''
+ + '}';
+ }
+
+ private static String toString(ComponentName cn) {
+ return cn == null ? "[null]" : cn.flattenToShortString();
+ }
+
+ public void apply(Consumer<Combo> callback) {
+ log("Testing for: " + this);
+ callback.accept(this);
+ }
+ }
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasBroadcastTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasBroadcastTest.java
new file mode 100644
index 000000000000..7d5e0b9c6d8a
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasBroadcastTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests;
+
+import static android.content.componentalias.tests.ComponentAliasTestCommon.MAIN_PACKAGE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.SUB1_PACKAGE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.SUB2_PACKAGE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.TAG;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ComponentName;
+import android.content.Intent;
+
+import com.android.compatibility.common.util.BroadcastMessenger.Receiver;
+
+import org.junit.Test;
+
+import java.util.function.Consumer;
+
+public class ComponentAliasBroadcastTest extends BaseComponentAliasTest {
+ private void forEachCombo(Consumer<Combo> callback) {
+ new Combo(
+ new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".b.Alias00"),
+ new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".b.Target00"),
+ MAIN_PACKAGE + ".IS_RECEIVER_00").apply(callback);
+
+ new Combo(
+ new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".b.Alias01"),
+ new ComponentName(SUB1_PACKAGE, MAIN_PACKAGE + ".b.Target01"),
+ MAIN_PACKAGE + ".IS_RECEIVER_01").apply(callback);
+ new Combo(
+ new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".b.Alias02"),
+ new ComponentName(SUB2_PACKAGE, MAIN_PACKAGE + ".b.Target02"),
+ MAIN_PACKAGE + ".IS_RECEIVER_02").apply(callback);
+ }
+
+ @Test
+ public void testBroadcast_explicitComponentName() {
+ forEachCombo((c) -> {
+ Intent i = new Intent().setComponent(c.alias);
+ i.setAction("ACTION_BROADCAST");
+ ComponentAliasMessage m;
+
+ try (Receiver<ComponentAliasMessage> receiver = new Receiver<>(sContext, TAG)) {
+ log("Sending: " + i);
+ sContext.sendBroadcast(i);
+
+ m = receiver.waitForNextMessage();
+
+ assertThat(m.getMethodName()).isEqualTo("onReceive");
+ assertThat(m.getSenderIdentity()).isEqualTo(c.target.flattenToShortString());
+
+ // The broadcast intent will always have the receiving component name set.
+ assertThat(m.getIntent().getComponent()).isEqualTo(c.target);
+
+ receiver.ensureNoMoreMessages();
+ }
+ });
+ }
+
+ @Test
+ public void testBroadcast_explicitPackageName() {
+ forEachCombo((c) -> {
+ // In this test, we only set the package name to the intent.
+ // If the alias and target are the same package, the intent will be sent to both of them
+ // *and* the one to the alias is redirected to the target, so the target will receive
+ // the intent twice. This case is haled at *1 below.
+
+
+ Intent i = new Intent().setPackage(c.alias.getPackageName());
+ i.setAction(c.action);
+ ComponentAliasMessage m;
+
+ try (Receiver<ComponentAliasMessage> receiver = new Receiver<>(sContext, TAG)) {
+ log("Sending broadcast: " + i);
+ sContext.sendBroadcast(i);
+
+ m = receiver.waitForNextMessage();
+
+ assertThat(m.getMethodName()).isEqualTo("onReceive");
+ assertThat(m.getSenderIdentity()).isEqualTo(c.target.flattenToShortString());
+ assertThat(m.getIntent().getComponent()).isEqualTo(c.target);
+
+ // *1 -- if the alias and target are in the same package, we expect one more
+ // message.
+ if (c.alias.getPackageName().equals(c.target.getPackageName())) {
+ m = receiver.waitForNextMessage();
+ assertThat(m.getMethodName()).isEqualTo("onReceive");
+ assertThat(m.getSenderIdentity()).isEqualTo(c.target.flattenToShortString());
+ assertThat(m.getIntent().getComponent()).isEqualTo(c.target);
+ }
+ receiver.ensureNoMoreMessages();
+ }
+ });
+ }
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java
new file mode 100644
index 000000000000..d41696f27880
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Parcelabe containing a "message" that's meant to be delivered via BroadcastMessenger.
+ *
+ * To add a new field, just add a private member field, and run:
+ * codegen $ANDROID_BUILD_TOP/frameworks/base/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java
+ */
+@DataClass(
+ genConstructor = false,
+ genSetters = true,
+ genToString = true,
+ genAidl = false)
+public final class ComponentAliasMessage implements Parcelable {
+ public ComponentAliasMessage() {
+ }
+
+ @Nullable
+ private String mMessage;
+
+ @Nullable
+ private String mMethodName;
+
+ @Nullable
+ private String mSenderIdentity;
+
+ @Nullable
+ private Intent mIntent;
+
+ @Nullable
+ private ComponentName mComponent;
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ public @Nullable String getMessage() {
+ return mMessage;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable String getMethodName() {
+ return mMethodName;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable String getSenderIdentity() {
+ return mSenderIdentity;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable Intent getIntent() {
+ return mIntent;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable ComponentName getComponent() {
+ return mComponent;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ComponentAliasMessage setMessage(@NonNull String value) {
+ mMessage = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ComponentAliasMessage setMethodName(@NonNull String value) {
+ mMethodName = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ComponentAliasMessage setSenderIdentity(@NonNull String value) {
+ mSenderIdentity = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ComponentAliasMessage setIntent(@NonNull Intent value) {
+ mIntent = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull ComponentAliasMessage setComponent(@NonNull ComponentName value) {
+ mComponent = value;
+ return this;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "ComponentAliasMessage { " +
+ "message = " + mMessage + ", " +
+ "methodName = " + mMethodName + ", " +
+ "senderIdentity = " + mSenderIdentity + ", " +
+ "intent = " + mIntent + ", " +
+ "component = " + mComponent +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mMessage != null) flg |= 0x1;
+ if (mMethodName != null) flg |= 0x2;
+ if (mSenderIdentity != null) flg |= 0x4;
+ if (mIntent != null) flg |= 0x8;
+ if (mComponent != null) flg |= 0x10;
+ dest.writeByte(flg);
+ if (mMessage != null) dest.writeString(mMessage);
+ if (mMethodName != null) dest.writeString(mMethodName);
+ if (mSenderIdentity != null) dest.writeString(mSenderIdentity);
+ if (mIntent != null) dest.writeTypedObject(mIntent, flags);
+ if (mComponent != null) dest.writeTypedObject(mComponent, flags);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ ComponentAliasMessage(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ String message = (flg & 0x1) == 0 ? null : in.readString();
+ String methodName = (flg & 0x2) == 0 ? null : in.readString();
+ String senderIdentity = (flg & 0x4) == 0 ? null : in.readString();
+ Intent intent = (flg & 0x8) == 0 ? null : (Intent) in.readTypedObject(Intent.CREATOR);
+ ComponentName component = (flg & 0x10) == 0 ? null : (ComponentName) in.readTypedObject(ComponentName.CREATOR);
+
+ this.mMessage = message;
+ this.mMethodName = methodName;
+ this.mSenderIdentity = senderIdentity;
+ this.mIntent = intent;
+ this.mComponent = component;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ComponentAliasMessage> CREATOR
+ = new Parcelable.Creator<ComponentAliasMessage>() {
+ @Override
+ public ComponentAliasMessage[] newArray(int size) {
+ return new ComponentAliasMessage[size];
+ }
+
+ @Override
+ public ComponentAliasMessage createFromParcel(@NonNull Parcel in) {
+ return new ComponentAliasMessage(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1630098801203L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasMessage.java",
+ inputSignatures = "private @android.annotation.Nullable java.lang.String mMessage\nprivate @android.annotation.Nullable java.lang.String mMethodName\nprivate @android.annotation.Nullable java.lang.String mSenderIdentity\nprivate @android.annotation.Nullable android.content.Intent mIntent\nprivate @android.annotation.Nullable android.content.ComponentName mComponent\nclass ComponentAliasMessage extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true, genToString=true, genAidl=false)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasServiceTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasServiceTest.java
new file mode 100644
index 000000000000..f0ff088815af
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasServiceTest.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests;
+
+import static android.content.Context.BIND_AUTO_CREATE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.MAIN_PACKAGE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.SUB1_PACKAGE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.SUB2_PACKAGE;
+import static android.content.componentalias.tests.ComponentAliasTestCommon.TAG;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.hamcrest.core.IsNot.not;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+
+import com.android.compatibility.common.util.BroadcastMessenger;
+import com.android.compatibility.common.util.BroadcastMessenger.Receiver;
+import com.android.compatibility.common.util.ShellUtils;
+import com.android.compatibility.common.util.TestUtils;
+
+import org.junit.Assume;
+import org.junit.Test;
+
+import java.util.function.Consumer;
+
+/**
+ * Test for the experimental "Component alias" feature.
+ *
+ * Note this test exercises the relevant APIs, but don't actually check if the aliases are
+ * resolved.
+ *
+ * Note all the helper APKs are battery-exempted (via AndroidTest.xml), so they can run
+ * BG services.
+ */
+public class ComponentAliasServiceTest extends BaseComponentAliasTest {
+ /**
+ * Service connection used throughout the tests. It sends a message for each callback via
+ * the messenger.
+ */
+ private static final ServiceConnection sServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ log("onServiceConnected: " + name);
+
+ ComponentAliasMessage m = new ComponentAliasMessage()
+ .setSenderIdentity("sServiceConnection")
+ .setMethodName("onServiceConnected")
+ .setComponent(name);
+
+ BroadcastMessenger.send(sContext, TAG, m);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ log("onServiceDisconnected: " + name);
+
+ ComponentAliasMessage m = new ComponentAliasMessage()
+ .setSenderIdentity("sServiceConnection")
+ .setMethodName("onServiceDisconnected")
+ .setComponent(name);
+
+ BroadcastMessenger.send(sContext, TAG, m);
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ log("onBindingDied: " + name);
+
+ ComponentAliasMessage m = new ComponentAliasMessage()
+ .setSenderIdentity("sServiceConnection")
+ .setMethodName("onBindingDied");
+
+ BroadcastMessenger.send(sContext, TAG, m);
+ }
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ log("onNullBinding: " + name);
+
+ ComponentAliasMessage m = new ComponentAliasMessage()
+ .setSenderIdentity("sServiceConnection")
+ .setMethodName("onNullBinding");
+
+ BroadcastMessenger.send(sContext, TAG, m);
+ }
+ };
+
+ private void testStartAndStopService_common(
+ Intent originalIntent,
+ ComponentName componentNameForClient,
+ ComponentName componentNameForTarget) {
+
+ ComponentAliasMessage m;
+
+ try (Receiver<ComponentAliasMessage> receiver = new Receiver<>(sContext, TAG)) {
+ // Start the service.
+ ComponentName result = sContext.startService(originalIntent);
+ assertThat(result).isEqualTo(componentNameForClient);
+
+ // Check
+ m = receiver.waitForNextMessage();
+
+ assertThat(m.getMethodName()).isEqualTo("onStartCommand");
+ // The app sees the rewritten intent.
+ assertThat(m.getIntent().getComponent()).isEqualTo(componentNameForTarget);
+
+ // Verify the original intent.
+ assertThat(m.getIntent().getOriginalIntent().getComponent())
+ .isEqualTo(originalIntent.getComponent());
+ assertThat(m.getIntent().getOriginalIntent().getPackage())
+ .isEqualTo(originalIntent.getPackage());
+
+ // Stop the service.
+ sContext.stopService(originalIntent);
+
+ // Check
+ m = receiver.waitForNextMessage();
+
+ assertThat(m.getMethodName()).isEqualTo("onDestroy");
+
+ receiver.ensureNoMoreMessages();
+ }
+ }
+
+ private void forEachCombo(Consumer<Combo> callback) {
+ new Combo(
+ new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias00"),
+ new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Target00"),
+ MAIN_PACKAGE + ".IS_ALIAS_00").apply(callback);
+ new Combo(
+ new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias01"),
+ new ComponentName(SUB1_PACKAGE, MAIN_PACKAGE + ".s.Target01"),
+ MAIN_PACKAGE + ".IS_ALIAS_01").apply(callback);
+ new Combo(
+ new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias02"),
+ new ComponentName(SUB2_PACKAGE, MAIN_PACKAGE + ".s.Target02"),
+ MAIN_PACKAGE + ".IS_ALIAS_02").apply(callback);
+ }
+
+ @Test
+ public void testStartAndStopService_explicitComponentName() {
+ forEachCombo((c) -> {
+ Intent i = new Intent().setComponent(c.alias);
+ testStartAndStopService_common(i, c.alias, c.target);
+ });
+ }
+
+ @Test
+ public void testStartAndStopService_explicitPackageName() {
+ forEachCombo((c) -> {
+ Intent i = new Intent().setPackage(c.alias.getPackageName());
+ i.setAction(c.action);
+
+ testStartAndStopService_common(i, c.alias, c.target);
+ });
+ }
+
+ @Test
+ public void testStartAndStopService_override() throws Exception {
+ Intent i = new Intent().setPackage(MAIN_PACKAGE);
+ i.setAction(MAIN_PACKAGE + ".IS_ALIAS_01");
+
+ // Change some of the aliases from what's defined in <meta-data>.
+
+ ComponentName aliasA = new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias01");
+ ComponentName targetA = new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Target02");
+
+ ComponentName aliasB = new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias02");
+ ComponentName targetB = new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Target01");
+
+ sDeviceConfig.set("component_alias_overrides",
+ aliasA.flattenToShortString() + ":" + targetA.flattenToShortString()
+ + ","
+ + aliasB.flattenToShortString() + ":" + targetB.flattenToShortString());
+
+ TestUtils.waitUntil("Wait until component alias is actually enabled", () -> {
+ return ShellUtils.runShellCommand("dumpsys activity component-alias")
+ .indexOf(aliasA.flattenToShortString()
+ + " -> " + targetA.flattenToShortString()) > 0;
+ });
+
+
+ testStartAndStopService_common(i, aliasA, targetA);
+ }
+
+ private void testBindAndUnbindService_common(
+ Intent originalIntent,
+ ComponentName componentNameForClient,
+ ComponentName componentNameForTarget) {
+ ComponentAliasMessage m;
+
+ try (Receiver<ComponentAliasMessage> receiver = new Receiver<>(sContext, TAG)) {
+ // Bind to the service.
+ assertThat(sContext.bindService(
+ originalIntent, sServiceConnection, BIND_AUTO_CREATE)).isTrue();
+
+ // Check the target side behavior.
+ m = receiver.waitForNextMessage();
+
+ assertThat(m.getMethodName()).isEqualTo("onBind");
+ // The app sees the rewritten intent.
+ assertThat(m.getIntent().getComponent()).isEqualTo(componentNameForTarget);
+
+ // Verify the original intent.
+ assertThat(m.getIntent().getOriginalIntent().getComponent())
+ .isEqualTo(originalIntent.getComponent());
+ assertThat(m.getIntent().getOriginalIntent().getPackage())
+ .isEqualTo(originalIntent.getPackage());
+
+ // Check the client side behavior.
+ m = receiver.waitForNextMessage();
+
+ assertThat(m.getMethodName()).isEqualTo("onServiceConnected");
+ // The app sees the rewritten intent.
+ assertThat(m.getComponent()).isEqualTo(componentNameForClient);
+
+ // Unbind.
+ sContext.unbindService(sServiceConnection);
+
+ // Check the target side behavior.
+ m = receiver.waitForNextMessage();
+
+ assertThat(m.getMethodName()).isEqualTo("onDestroy");
+
+ // Note onServiceDisconnected() won't be called in this case.
+ receiver.ensureNoMoreMessages();
+ }
+ }
+
+ @Test
+ public void testBindService_explicitComponentName() {
+ forEachCombo((c) -> {
+ Intent i = new Intent().setComponent(c.alias);
+
+ testBindAndUnbindService_common(i, c.alias, c.target);
+ });
+
+ }
+
+ @Test
+ public void testBindService_explicitPackageName() {
+ forEachCombo((c) -> {
+ Intent i = new Intent().setPackage(c.alias.getPackageName());
+ i.setAction(c.action);
+
+ testBindAndUnbindService_common(i, c.alias, c.target);
+ });
+ }
+
+ /**
+ * Make sure, when the service process is killed, the client will get a callback with the
+ * right component name.
+ */
+ @Test
+ public void testBindService_serviceKilled() {
+
+ // We need to kill SUB2_PACKAGE, don't run it for this package.
+ Assume.assumeThat(sContext.getPackageName(), not(SUB2_PACKAGE));
+
+ Intent originalIntent = new Intent().setPackage(MAIN_PACKAGE);
+ originalIntent.setAction(MAIN_PACKAGE + ".IS_ALIAS_02");
+
+ final ComponentName componentNameForClient =
+ new ComponentName(MAIN_PACKAGE, MAIN_PACKAGE + ".s.Alias02");
+ final ComponentName componentNameForTarget =
+ new ComponentName(SUB2_PACKAGE, MAIN_PACKAGE + ".s.Target02");
+
+ ComponentAliasMessage m;
+
+ try (Receiver<ComponentAliasMessage> receiver = new Receiver<>(sContext, TAG)) {
+ // Bind to the service.
+ assertThat(sContext.bindService(
+ originalIntent, sServiceConnection, BIND_AUTO_CREATE)).isTrue();
+
+ // Check the target side behavior.
+ m = receiver.waitForNextMessage();
+
+ assertThat(m.getMethodName()).isEqualTo("onBind");
+
+ m = receiver.waitForNextMessage();
+ assertThat(m.getMethodName()).isEqualTo("onServiceConnected");
+ assertThat(m.getComponent()).isEqualTo(componentNameForClient);
+ // We don't need to check all the fields because these are tested else where.
+
+ // Now kill the service process.
+ ShellUtils.runShellCommand("su 0 killall %s", SUB2_PACKAGE);
+
+ // Check the target side behavior.
+ m = receiver.waitForNextMessage();
+
+ assertThat(m.getMethodName()).isEqualTo("onServiceDisconnected");
+ assertThat(m.getComponent()).isEqualTo(componentNameForClient);
+
+ receiver.ensureNoMoreMessages();
+ }
+ }
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasTestCommon.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasTestCommon.java
new file mode 100644
index 000000000000..165d728c92a6
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasTestCommon.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests;
+
+public final class ComponentAliasTestCommon {
+ private ComponentAliasTestCommon() {
+ }
+
+ public static final String TAG = "ComponentAliasTest";
+
+ public static final String MAIN_PACKAGE = "android.content.componentalias.tests";
+
+ public static final String SUB1_PACKAGE = "android.content.componentalias.tests.sub1";
+ public static final String SUB2_PACKAGE = "android.content.componentalias.tests.sub2";
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/b/BaseReceiver.java b/tests/componentalias/src/android/content/componentalias/tests/b/BaseReceiver.java
new file mode 100644
index 000000000000..1d05e72a2f3f
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/b/BaseReceiver.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.b;
+
+import static android.content.componentalias.tests.ComponentAliasTestCommon.TAG;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.componentalias.tests.ComponentAliasMessage;
+import android.util.Log;
+
+import com.android.compatibility.common.util.BroadcastMessenger;
+
+public class BaseReceiver extends BroadcastReceiver {
+ private String getMyIdentity(Context context) {
+ return (new ComponentName(context.getPackageName(), this.getClass().getCanonicalName()))
+ .flattenToShortString();
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(TAG, "onReceive: on " + getMyIdentity(context) + " intent=" + intent);
+ ComponentAliasMessage m = new ComponentAliasMessage()
+ .setSenderIdentity(getMyIdentity(context))
+ .setMethodName("onReceive")
+ .setIntent(intent);
+ BroadcastMessenger.send(context, TAG, m);
+ }
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/b/Target00.java b/tests/componentalias/src/android/content/componentalias/tests/b/Target00.java
new file mode 100644
index 000000000000..8fb4e91f790c
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/b/Target00.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.b;
+
+import android.content.componentalias.tests.s.BaseService;
+
+public class Target00 extends BaseReceiver {
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/b/Target01.java b/tests/componentalias/src/android/content/componentalias/tests/b/Target01.java
new file mode 100644
index 000000000000..06f7a13f73d7
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/b/Target01.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.b;
+
+public class Target01 extends BaseReceiver {
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/b/Target02.java b/tests/componentalias/src/android/content/componentalias/tests/b/Target02.java
new file mode 100644
index 000000000000..df7579d8304d
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/b/Target02.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.b;
+
+public class Target02 extends BaseReceiver {
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/b/Target03.java b/tests/componentalias/src/android/content/componentalias/tests/b/Target03.java
new file mode 100644
index 000000000000..5ae55215f696
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/b/Target03.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.b;
+
+public class Target03 extends BaseReceiver {
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/b/Target04.java b/tests/componentalias/src/android/content/componentalias/tests/b/Target04.java
new file mode 100644
index 000000000000..f9b9886b0bb2
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/b/Target04.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.b;
+
+public class Target04 extends BaseReceiver {
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/s/BaseService.java b/tests/componentalias/src/android/content/componentalias/tests/s/BaseService.java
new file mode 100644
index 000000000000..535d9b80f100
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/BaseService.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.s;
+
+import static android.content.componentalias.tests.ComponentAliasTestCommon.TAG;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.componentalias.tests.ComponentAliasMessage;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.compatibility.common.util.BroadcastMessenger;
+
+public class BaseService extends Service {
+ private String getMyIdentity() {
+ return (new ComponentName(this.getPackageName(), this.getClass().getCanonicalName()))
+ .flattenToShortString();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.i(TAG, "onStartCommand: on " + getMyIdentity() + " intent=" + intent);
+ ComponentAliasMessage m = new ComponentAliasMessage()
+ .setSenderIdentity(getMyIdentity())
+ .setMethodName("onStartCommand")
+ .setIntent(intent);
+ BroadcastMessenger.send(this, TAG, m);
+
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.i(TAG, "onDestroy: on " + getMyIdentity());
+
+ ComponentAliasMessage m = new ComponentAliasMessage()
+ .setSenderIdentity(getMyIdentity())
+ .setMethodName("onDestroy");
+ BroadcastMessenger.send(this, TAG, m);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.i(TAG, "onBind: on " + getMyIdentity() + " intent=" + intent);
+
+ ComponentAliasMessage m = new ComponentAliasMessage()
+ .setSenderIdentity(getMyIdentity())
+ .setMethodName("onBind")
+ .setIntent(intent);
+ BroadcastMessenger.send(this, TAG, m);
+
+ return new Binder();
+ }
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/s/Target00.java b/tests/componentalias/src/android/content/componentalias/tests/s/Target00.java
new file mode 100644
index 000000000000..64b91f5695f5
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target00.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.s;
+
+public class Target00 extends BaseService {
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/s/Target01.java b/tests/componentalias/src/android/content/componentalias/tests/s/Target01.java
new file mode 100644
index 000000000000..bd589991d7dc
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target01.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.s;
+
+public class Target01 extends BaseService {
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/s/Target02.java b/tests/componentalias/src/android/content/componentalias/tests/s/Target02.java
new file mode 100644
index 000000000000..0ddf8188768b
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target02.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.s;
+
+public class Target02 extends BaseService {
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/s/Target03.java b/tests/componentalias/src/android/content/componentalias/tests/s/Target03.java
new file mode 100644
index 000000000000..0dbc0501b6f9
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target03.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.s;
+
+public class Target03 extends BaseService {
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/s/Target04.java b/tests/componentalias/src/android/content/componentalias/tests/s/Target04.java
new file mode 100644
index 000000000000..099425867f02
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/s/Target04.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.content.componentalias.tests.s;
+
+public class Target04 extends BaseService {
+}
diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp
index af9786b92f40..deff42a27f47 100644
--- a/tests/utils/testutils/Android.bp
+++ b/tests/utils/testutils/Android.bp
@@ -38,6 +38,6 @@ java_library {
"android.test.runner",
"android.test.base",
"android.test.mock",
- "mockito-target-minus-junit4",
+ "mockito-target-extended-minus-junit4",
],
}