diff options
author | 2022-11-11 15:16:17 +0000 | |
---|---|---|
committer | 2022-12-13 09:53:12 +0000 | |
commit | 88f66bfc0af002b2f4b6cc9b8f385d92bbae4057 (patch) | |
tree | e2baecc76c8f14d324405ff7382445ddec6bafd0 | |
parent | 344e13d2dd4305aaa93c330d716b2d729da15fae (diff) |
Add basic statsd test setup for SafetyCenter
I intend this new package to be in MTS, but am intentionally not
including it in any TEST_PATTERNS files for the moment, so we have time
to consider the various scenarios in which this test should be run and
can verify it's non flakey.
Bug: 239682646
Test: atest SafetyCenterHostSideTestCases
Change-Id: I18423a022be52e940e23d07e7c45c382ac9562fb
10 files changed, 407 insertions, 11 deletions
diff --git a/service/java/com/android/safetycenter/SafetyCenterService.java b/service/java/com/android/safetycenter/SafetyCenterService.java index 2e2d56066..7ffbf79fa 100644 --- a/service/java/com/android/safetycenter/SafetyCenterService.java +++ b/service/java/com/android/safetycenter/SafetyCenterService.java @@ -685,7 +685,8 @@ public final class SafetyCenterService extends SystemService { @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args) { - return new SafetyCenterShellCommandHandler(this) + return new SafetyCenterShellCommandHandler( + getContext(), this, mDeviceSupportsSafetyCenter) .exec( this, in.getFileDescriptor(), diff --git a/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java b/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java index d0f972a08..f66aabe94 100644 --- a/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java +++ b/service/java/com/android/safetycenter/SafetyCenterShellCommandHandler.java @@ -29,6 +29,7 @@ import static java.util.Collections.unmodifiableMap; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.content.Context; import android.os.RemoteException; import android.safetycenter.ISafetyCenterManager; import android.safetycenter.SafetyCenterManager.RefreshReason; @@ -47,10 +48,17 @@ final class SafetyCenterShellCommandHandler extends BasicShellCommandHandler { @NonNull private static final Map<String, Integer> REASONS = createReasonMap(); + @NonNull private final Context mContext; @NonNull private final ISafetyCenterManager mSafetyCenterManager; + private final boolean mDeviceSupportsSafetyCenter; - SafetyCenterShellCommandHandler(@NonNull ISafetyCenterManager safetyCenterManager) { + SafetyCenterShellCommandHandler( + @NonNull Context context, + @NonNull ISafetyCenterManager safetyCenterManager, + boolean deviceSupportsSafetyCenter) { + mContext = context; mSafetyCenterManager = safetyCenterManager; + mDeviceSupportsSafetyCenter = deviceSupportsSafetyCenter; } @Override @@ -64,10 +72,14 @@ final class SafetyCenterShellCommandHandler extends BasicShellCommandHandler { switch (cmd) { case "enabled": return onEnabled(); + case "supported": + return onSupported(); case "refresh": return onRefresh(); case "clear-data": return onClearData(); + case "package-name": + return onPackageName(); default: return handleDefaultCommands(cmd); } @@ -78,13 +90,13 @@ final class SafetyCenterShellCommandHandler extends BasicShellCommandHandler { } private int onEnabled() throws RemoteException { - if (mSafetyCenterManager.isSafetyCenterEnabled()) { - getOutPrintWriter().println("Safety Center is enabled"); - return 0; - } else { - getOutPrintWriter().println("Safety Center is not enabled"); - return 1; - } + getOutPrintWriter().println(mSafetyCenterManager.isSafetyCenterEnabled()); + return 0; + } + + private int onSupported() { + getOutPrintWriter().println(mDeviceSupportsSafetyCenter); + return 0; } private int onRefresh() throws RemoteException { @@ -136,6 +148,12 @@ final class SafetyCenterShellCommandHandler extends BasicShellCommandHandler { return 0; } + private int onPackageName() { + getOutPrintWriter() + .println(mContext.getPackageManager().getPermissionControllerPackageName()); + return 0; + } + @Override public void onHelp() { getOutPrintWriter().println("Safety Center (safety_center) commands:"); @@ -143,7 +161,11 @@ final class SafetyCenterShellCommandHandler extends BasicShellCommandHandler { printCmd( "enabled", "Check if Safety Center is enabled", - "Exits with status code 0 if enabled or 1 if not enabled"); + "Prints \"true\" if enabled, \"false\" otherwise"); + printCmd( + "supported", + "Check if this device supports Safety Center (i.e. Safety Center could be enabled)", + "Prints \"true\" if supported, \"false\" otherwise"); printCmd( "refresh [--reason REASON] [--user USERID]", "Start a refresh of all sources", @@ -155,6 +177,7 @@ final class SafetyCenterShellCommandHandler extends BasicShellCommandHandler { "clear-data", "Clear all data held by Safety Center", "Includes data held in memory and persistent storage but not the listeners."); + printCmd("package-name", "Prints the name of the package that contains Safety Center"); } /** Helper function to standardise pretty-printing of the help text. */ diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt new file mode 100644 index 000000000..a9f489df4 --- /dev/null +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterShellCommandsTest.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.safetycenter.cts + +import android.content.Context +import android.safetycenter.SafetyCenterManager +import android.safetycenter.cts.testing.SafetyCenterApisWithShellPermissions.isSafetyCenterEnabledWithPermission +import android.safetycenter.cts.testing.SafetyCenterFlags.deviceSupportsSafetyCenter +import androidx.test.core.app.ApplicationProvider.getApplicationContext +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.compatibility.common.util.SystemUtil +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +/** CTS tests for Safety Center's shell commands. */ +@RunWith(AndroidJUnit4::class) +class SafetyCenterShellCommandsTest { + private val context: Context = getApplicationContext() + + @Test + fun enabled_printsEnabledValue() { + val enabled = executeShellCommand("cmd safety_center enabled").toBoolean() + + val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!! + assertThat(enabled).isEqualTo(safetyCenterManager.isSafetyCenterEnabledWithPermission()) + } + + @Test + fun supported_printsSupportedValue() { + val supported = executeShellCommand("cmd safety_center supported").toBoolean() + + assertThat(supported).isEqualTo(context.deviceSupportsSafetyCenter()) + } + + @Test + fun packageName_printsPackageName() { + val packageName = executeShellCommand("cmd safety_center package-name") + + assertThat(packageName).isEqualTo(context.packageManager.permissionControllerPackageName) + } + + private fun executeShellCommand(command: String): String = + SystemUtil.runShellCommand(command).trim() +} diff --git a/tests/functional/safetycenter/Android.bp b/tests/functional/safetycenter/Android.bp index 9e3e8b445..fa1f03bd0 100644 --- a/tests/functional/safetycenter/Android.bp +++ b/tests/functional/safetycenter/Android.bp @@ -23,7 +23,6 @@ android_test { defaults: ["mts-target-sdk-version-current"], sdk_version: "test_current", min_sdk_version: "30", - target_sdk_version: "32", srcs: [ "src/**/*.java", "src/**/*.kt", diff --git a/tests/hostside/safetycenter/Android.bp b/tests/hostside/safetycenter/Android.bp new file mode 100644 index 000000000..33b38c688 --- /dev/null +++ b/tests/hostside/safetycenter/Android.bp @@ -0,0 +1,35 @@ +// +// Copyright (C) 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +java_test_host { + name: "SafetyCenterHostSideTestCases", + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + libs: [ + "tradefed", + "junit", + ], + static_libs: [ + "cts-statsd-atom-host-test-utils", + ], + data: [":SafetyCenterHostSideTestsHelper"], +}
\ No newline at end of file diff --git a/tests/hostside/safetycenter/AndroidTest.xml b/tests/hostside/safetycenter/AndroidTest.xml new file mode 100644 index 000000000..310ef9d04 --- /dev/null +++ b/tests/hostside/safetycenter/AndroidTest.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Config for Safety Center hostside tests"> + <!-- TODO(b/239682646): Integrate these tests into MTS --> + <option name="config-descriptor:metadata" key="component" value="framework"/> + <option name="config-descriptor:metadata" key="parameter" value="not_instant_app"/> + <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi"/> + <!-- Multi-user code is tested separately using Bedstead. See SafetyCenterMultiUsersTest. --> + <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user"/> + + <object class="com.android.tradefed.testtype.suite.module.Sdk33ModuleController" + type="module_controller"/> + + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <!-- Ensure all broadcasts are dispatched prior to running our tests, to make sure they + aren't polluted by `BOOT_COMPLETED` or similar broadcasts still being delivered, which + causes our `ActivityManager#waitForBroadcastIdle()` calls to timeout. --> + <option name="run-command" value="am wait-for-broadcast-idle" /> + <!-- Disable syncing to prevent overwriting flags during testing. --> + <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> + <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + </target_preparer> + + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.StayAwakePreparer" /> + + <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > + <option name="jar" value="SafetyCenterHostSideTestCases.jar" /> + </test> +</configuration>
\ No newline at end of file diff --git a/tests/hostside/safetycenter/helper-app/Android.bp b/tests/hostside/safetycenter/helper-app/Android.bp new file mode 100644 index 000000000..851b14795 --- /dev/null +++ b/tests/hostside/safetycenter/helper-app/Android.bp @@ -0,0 +1,35 @@ +// +// Copyright (C) 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "SafetyCenterHostSideTestsHelper", + defaults: ["mts-target-sdk-version-current"], + sdk_version: "test_current", + min_sdk_version: "33", + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + static_libs: [ + "androidx.test.rules", + "androidx.test.ext.junit", + "compatibility-device-util-axt", + ], +}
\ No newline at end of file diff --git a/tests/hostside/safetycenter/helper-app/AndroidManifest.xml b/tests/hostside/safetycenter/helper-app/AndroidManifest.xml new file mode 100644 index 000000000..ad329bbec --- /dev/null +++ b/tests/hostside/safetycenter/helper-app/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.safetycenter.hostside.device"> + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.safetycenter.hostside.device" /> +</manifest>
\ No newline at end of file diff --git a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt new file mode 100644 index 000000000..ae19dcc01 --- /dev/null +++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.safetycenter.hostside.device + +import android.content.Context +import android.content.Intent +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.compatibility.common.util.UiAutomatorUtils +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Contains "helper tests" that perform on-device setup and interaction code for Safety Center's + * interaction logging host-side tests. These "helper tests" just perform arrange and act steps and + * should not contain assertions. Assertions are performed in the host-side tests that run these + * helper tests. + * + * Some context: host-side tests are unable to interact with the device UI in a detailed manner, and + * must run "helper tests" on the device to perform in-depth interactions or setup that must be + * performed by code running on the device. + */ +@RunWith(AndroidJUnit4::class) +class SafetyCenterInteractionLoggingHelperTests { + private val context: Context = ApplicationProvider.getApplicationContext() + + @Test + fun openSafetyCenter() { + context.startActivity( + Intent(Intent.ACTION_SAFETY_CENTER) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) + + // TODO(b/239682646): Use the extracted CTS support library to launch and close activity + // (after extracting it) + val uiDevice = UiAutomatorUtils.getUiDevice() + uiDevice.waitForIdle() + uiDevice.pressBack() + } +} diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt new file mode 100644 index 000000000..32679a1f0 --- /dev/null +++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.safetycenter.hostside + +import android.cts.statsdatom.lib.AtomTestUtils +import android.cts.statsdatom.lib.ConfigUtils +import android.cts.statsdatom.lib.DeviceUtils +import android.cts.statsdatom.lib.ReportUtils +import com.android.os.AtomsProto.Atom +import com.android.os.AtomsProto.SafetyCenterInteractionReported +import com.android.tradefed.device.ITestDevice +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test +import com.android.tradefed.util.CommandStatus +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +/** Host-side test for statsd interaction logging in the Safety Center UI. */ +@RunWith(DeviceJUnit4ClassRunner::class) +class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() { + + private val shouldRunTests: Boolean by lazy { + // Device is not available when the test is first constructed + // TODO(b/239682646): These tests should enable safety center instead of only running when + // it's already enabled. + device.supportsSafetyCenter() && device.isSafetyCenterEnabled() + } + + @Before + fun assumeDeviceSupportsSafetyCenterToRunTests() { + assumeTrue(shouldRunTests) + } + + @Before + fun setUp() { + if (!shouldRunTests) return + + ConfigUtils.removeConfig(device) + ReportUtils.clearReports(device) + ConfigUtils.uploadConfigForPushedAtom( + device, + getSafetyCenterPackageName(), + Atom.SAFETY_CENTER_INTERACTION_REPORTED_FIELD_NUMBER) + Thread.sleep(AtomTestUtils.WAIT_TIME_LONG.toLong()) + + DeviceUtils.installTestApp(device, HELPER_APK_NAME, HELPER_PACKAGE, build) + + // TODO(b/239682646): Consider adding a target preparer that unlocks the device (like CTS) + } + + @After + fun tearDown() { + if (!shouldRunTests) return + + ConfigUtils.removeConfig(device) + ReportUtils.clearReports(device) + DeviceUtils.uninstallTestApp(device, HELPER_PACKAGE) + } + + @Test + fun openSafetyCenter_recordsSafetyCenterViewedEvent() { + DeviceUtils.runDeviceTests( + device, HELPER_PACKAGE, HELPER_TEST_CLASS_NAME, "openSafetyCenter") + Thread.sleep(AtomTestUtils.WAIT_TIME_LONG.toLong()) // Wait for report to be updated + + val safetyCenterViewedEvents = + ReportUtils.getEventMetricDataList(device).filter { + it.atom.safetyCenterInteractionReported.action == + SafetyCenterInteractionReported.Action.SAFETY_CENTER_VIEWED + } + assertThat(safetyCenterViewedEvents).isNotEmpty() + } + + // TODO(b/239682646): Add more tests + + private fun ITestDevice.supportsSafetyCenter(): Boolean { + val commandResult = executeShellV2Command("cmd safety_center supported") + + if (commandResult.status != CommandStatus.SUCCESS) { + throw AssertionError("Unable to check if Safety Center is supported: $commandResult") + } + + return commandResult.stdout.trim().toBoolean() + } + private fun ITestDevice.isSafetyCenterEnabled(): Boolean { + val commandResult = executeShellV2Command("cmd safety_center enabled") + + if (commandResult.status != CommandStatus.SUCCESS) { + throw AssertionError("Unable to check if Safety Center is enabled: $commandResult") + } + + return commandResult.stdout.trim().toBoolean() + } + + private fun getSafetyCenterPackageName(): String = + device.executeShellCommand("cmd safety_center package-name").trim() + + private companion object { + const val HELPER_APK_NAME = "SafetyCenterHostSideTestsHelper.apk" + const val HELPER_PACKAGE = "android.safetycenter.hostside.device" + const val HELPER_TEST_CLASS_NAME = ".SafetyCenterInteractionLoggingHelperTests" + } +} |