[Privacy] Compare app signing certificates before restoring
backed up permissions to apps

Resubmitting with fix, see http://b/247728455#comment4 for details on
the fix and http://b/184847040#comment54 for testing rationale.

Earlier Reverted Changes:
If6f0df898:[automerge] Revert "[Privacy] Compare app signing ...
I9fe0701c1:Revert "[Privacy] Compare app signing certificates...
I4f031a63c:Revert "[Privacy] Compare app signing certificates...
Iec42d2fbb:[automerge] Revert "[Privacy] Compare app signing ...

Bug: 184847040
Test: atest CtsSecurityTestCases:PermissionBackupCertificateCheckTest
Merged-In: I84f48d1590ac04eac41ff2e7e59c2e986167101f
Change-Id: I84f48d1590ac04eac41ff2e7e59c2e986167101f
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 0cf3dd5..9f4cda5 100644
--- a/tests/tests/security/Android.bp
+++ b/tests/tests/security/Android.bp
@@ -33,6 +33,7 @@
         "compatibility-common-util-devicesidelib",
         "guava",
         "platform-test-annotations",
+        "permission-test-util-lib",
         "sts-device-util",
         "hamcrest-library",
         "NeneInternal",
@@ -80,7 +81,17 @@
         ":CtsDeviceInfo",
         ":RolePermissionOverrideTestApp",
         ":SplitBluetoothPermissionTestApp",
-    ],
+        ":CtsPermissionBackupAppCert1",
+        ":CtsPermissionBackupAppCert1Dup",
+        ":CtsPermissionBackupAppCert2",
+        ":CtsPermissionBackupAppCert3",
+        ":CtsPermissionBackupAppCert4",
+        ":CtsPermissionBackupAppCert12",
+        ":CtsPermissionBackupAppCert12Dup",
+        ":CtsPermissionBackupAppCert34",
+        ":CtsPermissionBackupAppCert123",
+        ":CtsPermissionBackupAppCert4History124",
+     ],
 }
 
 android_test_helper_app {
@@ -89,6 +100,95 @@
     manifest: "testdata/packageinstallertestapp.xml",
 }
 
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert1",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert1Dup",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert2",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-2",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert3",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-3",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert4",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-4",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert12",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    additional_certificates: [
+        ":permission-test-cert-2",
+    ],
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert12Dup",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    additional_certificates: [
+        ":permission-test-cert-2",
+    ],
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert34",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-3",
+    additional_certificates: [
+        ":permission-test-cert-4",
+    ],
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert123",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-1",
+    additional_certificates: [
+        ":permission-test-cert-2",
+        ":permission-test-cert-3",
+    ],
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+    name: "CtsPermissionBackupAppCert4History124",
+    min_sdk_version: "30",
+    certificate: ":permission-test-cert-4",
+    additional_certificates: [
+        ":permission-test-cert-1",
+
+    ],
+    rotationMinSdkVersion: "30",
+    lineage: ":permission-test-cert-with-rotation-history",
+    manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
 android_app_certificate {
     name: "security_cts_test_certificate",
     certificate: "security_cts_test_cert",
@@ -98,3 +198,30 @@
     name: "RolePermissionOverrideTestApp",
     manifest: "testdata/rolepermissionoverridetestapp.xml",
 }
+
+android_app_certificate {
+    name: "permission-test-cert-1",
+    certificate: "test-cert-1",
+}
+
+android_app_certificate {
+    name: "permission-test-cert-2",
+    certificate: "test-cert-2",
+}
+
+android_app_certificate {
+    name: "permission-test-cert-3",
+    certificate: "test-cert-3",
+}
+
+android_app_certificate {
+    name: "permission-test-cert-4",
+    certificate: "test-cert-4",
+}
+
+filegroup {
+    name: "permission-test-cert-with-rotation-history",
+    srcs: [
+        "test-cert-with-1-2-4-in-rotation-history",
+    ],
+}
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
index 9bd5eb7..73e6bc7 100644
--- a/tests/tests/security/AndroidTest.xml
+++ b/tests/tests/security/AndroidTest.xml
@@ -52,6 +52,16 @@
         <option name="cleanup" value="true" />
         <option name="push" value="RolePermissionOverrideTestApp.apk->/data/local/tmp/cts/security/RolePermissionOverrideTestApp.apk" />
         <option name="push" value="SplitBluetoothPermissionTestApp.apk->/data/local/tmp/cts/security/SplitBluetoothPermissionTestApp.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert1.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert1.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert1Dup.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert1Dup.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert2.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert2.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert3.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert3.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert4.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert4.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert12.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert12.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert12Dup.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert12Dup.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert123.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert123.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert34.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert34.apk" />
+        <option name="push" value="CtsPermissionBackupAppCert4History124.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert4History124.apk" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
@@ -61,4 +71,9 @@
         <option name="test-timeout" value="900000" />
         <option name="hidden-api-checks" value="false" />
     </test>
+
+    <target_preparer class="android.cts.backup.BackupPreparer">
+        <option name="enable-backup-if-needed" value="true" />
+        <option name="select-local-transport" value="true" />
+    </target_preparer>
 </configuration>
diff --git a/tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt b/tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt
new file mode 100644
index 0000000..1170939
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2018 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.security.cts
+
+import android.Manifest.permission.*
+import android.app.AppOpsManager
+import android.content.pm.PackageManager.*
+import android.os.ParcelFileDescriptor
+import android.permission.cts.PermissionUtils.grantPermission
+import android.platform.test.annotations.AppModeFull
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compatibility.common.util.BackupUtils
+import com.android.compatibility.common.util.BackupUtils.LOCAL_TRANSPORT_TOKEN
+import com.android.compatibility.common.util.BusinessLogicTestCase
+import com.android.compatibility.common.util.ShellUtils.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase
+import java.io.InputStream
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests that permissions for backed up apps are restored only after checking that their signing
+ * certificates are compared.
+ *
+ * @see [com.android.permissioncontroller.permission.service.BackupHelper]
+ */
+@AppModeFull
+@RunWith(AndroidJUnit4::class)
+class PermissionBackupCertificateCheckTest : StsExtraBusinessLogicTestCase() {
+    private val backupUtils: BackupUtils =
+        object : BackupUtils() {
+            override fun executeShellCommand(command: String): InputStream {
+                val pfd =
+                    BusinessLogicTestCase.getInstrumentation()
+                        .uiAutomation
+                        .executeShellCommand(command)
+                return ParcelFileDescriptor.AutoCloseInputStream(pfd)
+            }
+        }
+
+    private var isBackupSupported = false
+
+    private val targetContext = InstrumentationRegistry.getTargetContext()
+
+    @Before
+    fun setUp() {
+        val packageManager = BusinessLogicTestCase.getInstrumentation().context.packageManager
+        isBackupSupported =
+            (packageManager != null && packageManager.hasSystemFeature(FEATURE_BACKUP))
+
+        if (isBackupSupported) {
+            assertTrue("Backup not enabled", backupUtils.isBackupEnabled)
+            assertTrue("LocalTransport not selected", backupUtils.isLocalTransportSelected)
+            backupUtils.executeShellCommandSync("setprop log.tag.$APP_LOG_TAG VERBOSE")
+        }
+    }
+
+    @After
+    fun tearDown() {
+        uninstallIfInstalled(APP)
+        clearFlag(APP, ACCESS_FINE_LOCATION, FLAG_PERMISSION_USER_SET)
+        clearFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has the
+     * same certificate as the backed up app.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_sameCert_restoresRuntimePermissions() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_DUP)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has a
+     * different certificate as the backed up app.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_diffCert_doesNotGrantRuntimePermissions() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_3)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has the
+     * backed up app's certificate in its signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_midHistoryToRotated_restoresRuntimePermissions() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has the
+     * backed up app's certificate as the original certificate in its signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_origToRotated_restoresRuntimePermissions() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app has the
+     * restored app's certificate in its signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_rotatedToMidHistory_restoresRuntimePermissions() {
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app has the
+     * restored app's certificate in its signing history as its original certificate.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_rotatedToOrig_restoresRuntimePermissions() {
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app has the same
+     * certificate as the restored app, but the restored app additionally has signing certificate
+     * history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_sameWithHistory_restoresRuntimePermissions() {
+        install(APP_APK_CERT_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app has the same
+     * certificate as the restored app, but the backed up app additionally has signing certificate
+     * history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_sameWithoutHistory_restoresRuntimePermissions() {
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * signing history, but the backed up app's certificate is not in this signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_notInBackedUpHistory_doesNotRestoreRuntimePerms() {
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_3)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * signing history, but the backed up app's certificate is not in this signing history.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_notInRestoredHistory_doesNotRestoreRuntimePerms() {
+        install(APP_APK_CERT_3)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * multiple certificates, and the backed up app also has identical multiple certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_sameMultCerts_restoresRuntimePermissions() {
+        install(APP_APK_CERT_1_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_2_DUP)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * multiple certificates, and the backed up app do not have identical multiple certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_diffMultCerts_doesNotRestoreRuntimePermissions() {
+        install(APP_APK_CERT_1_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_3_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the app being restored has
+     * multiple certificates, and the backed up app's certificate is present in th restored app's
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_singleToMultiCert_restoresRuntimePerms() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_2_3)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app and the app
+     * being restored have multiple certificates, and the backed up app's certificates are a subset
+     * of the restored app's certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_multCertsToSuperset_doesNotRestoreRuntimePerms() {
+        install(APP_APK_CERT_1_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_2_3)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of regular runtime permissions, when the backed up app and the app
+     * being restored have multiple certificates, and the backed up app's certificates are a
+     * superset of the restored app's certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_multCertsToSubset_doesNotRestoreRuntimePermissions() {
+        install(APP_APK_CERT_1_2_3)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_1_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when both foreground and background runtime
+     * permissions are not granted and the backed up and restored app have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgBgDenied_matchingCerts_restoresFgBgPermissions() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        // Make a token change to permission state, to enable to us to determine when restore is
+        // complete.
+        grantPermission(APP, WRITE_CONTACTS)
+        // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+        // to ensure that permissions are backed up.
+        setFlag(APP, ACCESS_FINE_LOCATION, FLAG_PERMISSION_USER_SET)
+        setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+
+            // Wait until restore is complete.
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, WRITE_CONTACTS))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when both foreground and background runtime
+     * permissions are not granted and the backed up and restored app don't have compatible
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgBgDenied_notMatchingCerts_doesNotRestorePerms() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        // Make a token change to permission state, to enable to us to determine when restore is
+        // complete.
+        grantPermission(APP, WRITE_CONTACTS)
+        // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+        // to ensure that permissions are backed up.
+        setFlag(APP, ACCESS_FINE_LOCATION, FLAG_PERMISSION_USER_SET)
+        setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+
+            // Wait until restore is complete.
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, WRITE_CONTACTS))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when foreground runtime permission is
+     * granted and the backed up and restored app have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgGranted_matchingCerts_restoresFgBgPermissions() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+        // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+        // to ensure that permissions are backed up.
+        setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_FOREGROUND, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when foreground runtime permission is
+     * granted and the backed up and restored app don't have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgGranted_notMatchingCerts_doesNotRestoreFgBgPerms() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+        // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+        // to ensure that permissions are backed up.
+        setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when foreground and background runtime
+     * permissions are granted and the backed up and restored app have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgBgGranted_matchingCerts_restoresFgBgPermissions() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+        grantPermission(APP, ACCESS_BACKGROUND_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_ALLOWED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of tri-state permissions, when foreground and background runtime
+     * permissions are granted and the backed up and restored app don't have compatible
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_fgBgGranted_notMatchingCerts_restoresFgBgPerms() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+        grantPermission(APP, ACCESS_BACKGROUND_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually {
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+            assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+            assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+        }
+    }
+
+    /**
+     * Test backup and restore of flags when the backed up app and restored app have compatible
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_matchingCerts_restoresFlags() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        setFlag(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually { assertTrue(isFlagSet(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)) }
+    }
+
+    /**
+     * Test backup and restore of flags when the backed up app and restored app don't have
+     * compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_notMatchingCerts_doesNotRestoreFlag() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        setFlag(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        install(APP_APK_CERT_2)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+        eventually { assertFalse(isFlagSet(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)) }
+    }
+
+    /**
+     * Test backup and delayed restore of regular runtime permission, i.e. when an app is installed
+     * after restore has run, and the backed up app and restored app have compatible certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_appInstalledLater_matchingCerts_restoresCorrectly() {
+        install(APP_APK_CERT_2)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+
+        eventually { assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION)) }
+    }
+
+    /**
+     * Test backup and delayed restore of regular runtime permission, i.e. when an app is installed
+     * after restore has run, and the backed up app and restored app don't have compatible
+     * certificates.
+     */
+    @Test
+    @AsbSecurityTest(cveBugId = [184847040])
+    fun testRestore_appInstalledLater_notMatchingCerts_doesNotRestore() {
+        install(APP_APK_CERT_1)
+        if (!isBackupSupported) {
+            return
+        }
+        grantPermission(APP, ACCESS_FINE_LOCATION)
+
+        backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+        uninstallIfInstalled(APP)
+        backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+        install(APP_APK_CERT_4_HISTORY_1_2_4)
+
+        eventually { assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION)) }
+    }
+
+    private fun install(apk: String) {
+        val output = runShellCommand("pm install -r $apk")
+        assertEquals("Success", output)
+    }
+
+    private fun uninstallIfInstalled(packageName: String) {
+        runShellCommand("pm uninstall $packageName")
+    }
+
+    private fun setFlag(app: String, permission: String, flag: Int) {
+        runWithShellPermissionIdentity {
+            targetContext.packageManager.updatePermissionFlags(
+                permission, app, flag, flag, targetContext.user)
+        }
+    }
+
+    private fun clearFlag(app: String, permission: String, flag: Int) {
+        runWithShellPermissionIdentity {
+            targetContext.packageManager.updatePermissionFlags(
+                permission, app, flag, 0, targetContext.user)
+        }
+    }
+
+    private fun isFlagSet(app: String, permission: String, flag: Int): Boolean {
+        return try {
+            callWithShellPermissionIdentity<Int> {
+                targetContext.packageManager.getPermissionFlags(permission, app, targetContext.user)
+            } and flag == flag
+        } catch (e: Exception) {
+            throw RuntimeException(e)
+        }
+    }
+
+    private fun checkPermission(app: String, permission: String): Int {
+        return targetContext.packageManager.checkPermission(permission, app)
+    }
+
+    private fun getAppOp(app: String, permission: String): Int {
+        return try {
+            callWithShellPermissionIdentity {
+                targetContext
+                    .getSystemService<AppOpsManager>(AppOpsManager::class.java)!!
+                    .unsafeCheckOpRaw(
+                        AppOpsManager.permissionToOp(permission)!!,
+                        targetContext.packageManager.getPackageUid(app, 0),
+                        app)
+            }
+        } catch (e: Exception) {
+            throw RuntimeException(e)
+        }
+    }
+
+    companion object {
+        /** The name of the package of the apps under test */
+        private const val APP = "android.security.permissionbackup"
+        /** The apk of the packages */
+        private const val APK_PATH = "/data/local/tmp/cts/security/"
+        private const val APP_APK_CERT_1 = "${APK_PATH}CtsPermissionBackupAppCert1.apk"
+        private const val APP_APK_CERT_1_DUP = "${APK_PATH}CtsPermissionBackupAppCert1Dup.apk"
+        private const val APP_APK_CERT_2 = "${APK_PATH}CtsPermissionBackupAppCert2.apk"
+        private const val APP_APK_CERT_3 = "${APK_PATH}CtsPermissionBackupAppCert3.apk"
+        private const val APP_APK_CERT_4 = "${APK_PATH}CtsPermissionBackupAppCert4.apk"
+        private const val APP_APK_CERT_1_2 = "${APK_PATH}CtsPermissionBackupAppCert12.apk"
+        private const val APP_APK_CERT_1_2_DUP = "${APK_PATH}CtsPermissionBackupAppCert12Dup.apk"
+        private const val APP_APK_CERT_1_2_3 = "${APK_PATH}CtsPermissionBackupAppCert123.apk"
+        private const val APP_APK_CERT_3_4 = "${APK_PATH}CtsPermissionBackupAppCert34.apk"
+        private const val APP_APK_CERT_4_HISTORY_1_2_4 =
+            "${APK_PATH}CtsPermissionBackupAppCert4History124.apk"
+        private const val APP_LOG_TAG = "PermissionBackupApp"
+        /** The name of the package for backup */
+        private const val ANDROID_PACKAGE = "android"
+        private const val TIMEOUT_MILLIS: Long = 10000
+
+        /**
+         * Make sure that a [Runnable] eventually finishes without throwing an [Exception].
+         *
+         * @param r The [Runnable] to run.
+         */
+        fun eventually(r: Runnable) {
+            val start = System.currentTimeMillis()
+            while (true) {
+                try {
+                    r.run()
+                    return
+                } catch (e: Throwable) {
+                    if (System.currentTimeMillis() - start < TIMEOUT_MILLIS) {
+                        try {
+                            Thread.sleep(100)
+                        } catch (ignored: InterruptedException) {
+                            throw RuntimeException(e)
+                        }
+                    } else {
+                        throw e
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/security/test-cert-1.pk8 b/tests/tests/security/test-cert-1.pk8
new file mode 100644
index 0000000..f781c30
--- /dev/null
+++ b/tests/tests/security/test-cert-1.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-1.x509.pem b/tests/tests/security/test-cert-1.x509.pem
new file mode 100644
index 0000000..06adcfe
--- /dev/null
+++ b/tests/tests/security/test-cert-1.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbDCCARGgAwIBAgIJAMoPtk37ZudyMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMM
+B2VjLXAyNTYwHhcNMTYwMzMxMTQ1ODA2WhcNNDMwODE3MTQ1ODA2WjASMRAwDgYD
+VQQDDAdlYy1wMjU2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpl8RPSLLSROQ
+gwesMe4roOkTi3hfrGU20U6izpDStL/hlLUM3I4Wn1SnOpke8Pp2MpglvgeMx4J0
+BwPaRLTX66NQME4wHQYDVR0OBBYEFNQTNWi5WzAVizIgceqMQ/9bBczIMB8GA1Ud
+IwQYMBaAFNQTNWi5WzAVizIgceqMQ/9bBczIMAwGA1UdEwQFMAMBAf8wCgYIKoZI
+zj0EAwIDSQAwRgIhAPUEoIZsrvAp9BcULFy3E1THn/zR1kBhjfyk8Z4W23jWAiEA
++O6kgpeZwGytCMbT0tLsBeBXQVTnR+oP27gELLZVqt0=
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-2.pk8 b/tests/tests/security/test-cert-2.pk8
new file mode 100644
index 0000000..5e73f27
--- /dev/null
+++ b/tests/tests/security/test-cert-2.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-2.x509.pem b/tests/tests/security/test-cert-2.x509.pem
new file mode 100644
index 0000000..f8e5e65
--- /dev/null
+++ b/tests/tests/security/test-cert-2.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbTCCAROgAwIBAgIJAIhVvR3SsrIlMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMM
+B2VjLXAyNTYwHhcNMTgwNzEzMTc0MTUxWhcNMjgwNzEwMTc0MTUxWjAUMRIwEAYD
+VQQDDAllYy1wMjU2XzIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQdTMoEcq2X
+7jzs7w2pPWK0UMZ4gzOzbnVTzen3SrXfALu6a6lQ5oRh1wu8JxtiFR2tLeK/YgPN
+IHaAHHqdRCLho1AwTjAdBgNVHQ4EFgQUeZHZKwII/ESL9QbU78n/9CjLXl8wHwYD
+VR0jBBgwFoAU1BM1aLlbMBWLMiBx6oxD/1sFzMgwDAYDVR0TBAUwAwEB/zAKBggq
+hkjOPQQDAgNIADBFAiAnaauxtJ/C9TR5xK6SpmMdq/1SLJrLC7orQ+vrmcYwEQIh
+ANJg+x0fF2z5t/pgCYv9JDGfSQWj5f2hAKb+Giqxn/Ce
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-3.pk8 b/tests/tests/security/test-cert-3.pk8
new file mode 100644
index 0000000..d7309dd
--- /dev/null
+++ b/tests/tests/security/test-cert-3.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-3.x509.pem b/tests/tests/security/test-cert-3.x509.pem
new file mode 100644
index 0000000..c028ff7
--- /dev/null
+++ b/tests/tests/security/test-cert-3.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbjCCARWgAwIBAgIJAIOU9crRaomnMAoGCCqGSM49BAMCMBQxEjAQBgNVBAMM
+CWVjLXAyNTZfMjAeFw0xODA3MTQwMDA1MjZaFw0yODA3MTEwMDA1MjZaMBQxEjAQ
+BgNVBAMMCWVjLXAyNTZfMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPMeYkMO
+nbb8WSjZdfxOR0GbrPyy4HyJKZ5s1+NE3SGt/TCNWMtJoaKj/srM7qSGIGnzC+Fk
+O8wlUEDYCJ37N0OjUDBOMB0GA1UdDgQWBBRvjQgosT769Xf8hrDpn6PlS8vP8DAf
+BgNVHSMEGDAWgBR5kdkrAgj8RIv1BtTvyf/0KMteXzAMBgNVHRMEBTADAQH/MAoG
+CCqGSM49BAMCA0cAMEQCICVr2qJ4TCc+TMKRpZWkZ3ne6d6QRNyferggMJVn35/p
+AiAaStjGmJG1qMR0NP6VQO0fSXm1+tNIPz+gTVZ3NVpXng==
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-4.pk8 b/tests/tests/security/test-cert-4.pk8
new file mode 100644
index 0000000..3675d50
--- /dev/null
+++ b/tests/tests/security/test-cert-4.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-4.x509.pem b/tests/tests/security/test-cert-4.x509.pem
new file mode 100644
index 0000000..4060400
--- /dev/null
+++ b/tests/tests/security/test-cert-4.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBezCCASCgAwIBAgIUbIy4qBhDPB5kMfsW+zrg+1rWCqcwCgYIKoZIzj0EAwIw
+FDESMBAGA1UEAwwJZWMtcDI1Nl8zMB4XDTIwMDUxMzE5MTUyOFoXDTMwMDUxMTE5
+MTUyOFowFDESMBAGA1UEAwwJZWMtcDI1Nl80MFkwEwYHKoZIzj0CAQYIKoZIzj0D
+AQcDQgAE20pgAx55rUnLdZAH1oVdRGm5HIurBlQ08vupca3n5NGVmaD2e15wjP2n
+VD5WMMN2nTfgk2QNfHaKFRRM0OXc9KNQME4wHQYDVR0OBBYEFG54lwMyVUM2tu6J
+JOqnAjDjk/Z4MB8GA1UdIwQYMBaAFG+NCCixPvr1d/yGsOmfo+VLy8/wMAwGA1Ud
+EwQFMAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAM54bnnsdUdEYILpyvkQYU/4B1j5
+gZ+w8UhpUGer4PzUAiEApIgeMy3ewhFq0rWc+JHQ8zH/fifne3xiBseYjZtTkzA=
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-with-1-2-4-in-rotation-history b/tests/tests/security/test-cert-with-1-2-4-in-rotation-history
new file mode 100644
index 0000000..7326e46
--- /dev/null
+++ b/tests/tests/security/test-cert-with-1-2-4-in-rotation-history
Binary files differ
diff --git a/tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml b/tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml
new file mode 100644
index 0000000..2b75d8c
--- /dev/null
+++ b/tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.permissionbackup" >
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
+    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+    <application
+        android:label="Android Permission Backup CTS App">
+        <uses-library android:name="android.test.runner" />
+    </application>
+</manifest>