Merge "Add isAutomotive and isVrHeadset to device-side FeatureUtil" into stage-aosp-pi-cts-dev
am: 46f2ea1b71

Change-Id: I0f576f8e44181e80768873aa27a4dfde6535a62c
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 7f367db..f01fbde 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.cts.verifier"
       android:versionCode="5"
-      android:versionName="9.0_r2">
+      android:versionName="9.0_r1">
 
     <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28"/>
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/EmergencyCallBaseTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/EmergencyCallBaseTestActivity.java
index 531b40b..e25f758 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/EmergencyCallBaseTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/EmergencyCallBaseTestActivity.java
@@ -57,11 +57,19 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        // skip current test if device doesn't support cellular
+        if (!EmergencyCallUtil.isPhoneDevice(this)) {
+          String skipInfo = getResources().getString(R.string.emergency_call_skip_info);
+          TestResult.setPassedResult(this, super.getClass().getName(), skipInfo);
+          Toast toast = Toast.makeText(getApplicationContext(), skipInfo, Toast.LENGTH_LONG);
+          toast.show();
+          this.finish();
+          return;
+        }
         // override the test info
         mTextView.setText(R.string.location_emergency_call_test_info);
         EmergencyCallUtil.setDefaultDialer(this, this.getPackageName());
         setPassFailButtonClickListeners();
-
     }
 
     @Override
@@ -74,15 +82,7 @@
 
     @Override
     public void onClick(View target) {
-        // skip current test if device doesn't support cellular
-        if (!EmergencyCallUtil.isPhoneDevice(this)) {
-            String skipInfo = getResources().getString(R.string.emergency_call_skip_info);
-            TestResult.setPassedResult(this, super.getClass().getName(), skipInfo);
-            Toast toast = Toast.makeText(getApplicationContext(), skipInfo, Toast.LENGTH_LONG);
-            toast.show();
-            this.finish();
-            return;
-        }
+
         AlertDialog.Builder builder = new AlertDialog.Builder(this);
         final FrameLayout frameView = new FrameLayout(this);
         builder.setView(frameView);
diff --git a/hostsidetests/security/AndroidTest.xml b/hostsidetests/security/AndroidTest.xml
index 1282bd0..4b3ae9a 100755
--- a/hostsidetests/security/AndroidTest.xml
+++ b/hostsidetests/security/AndroidTest.xml
@@ -57,6 +57,7 @@
 
         <!-- Bulletin 2016-09 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2015-8839->/data/local/tmp/CVE-2015-8839" />
         <option name="push" value="CVE-2016-2471->/data/local/tmp/CVE-2016-2471" />
 
         <!--__________________-->
diff --git a/hostsidetests/security/securityPatch/CVE-2015-8839/Android.mk b/hostsidetests/security/securityPatch/CVE-2015-8839/Android.mk
new file mode 100755
index 0000000..65fe025
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2015-8839/Android.mk
@@ -0,0 +1,36 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := CVE-2015-8839
+LOCAL_SRC_FILES := poc.c
+
+LOCAL_SHARED_LIBRARIES := libcutils \
+                          liblog
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS += -Wall -Werror
+LOCAL_LDFLAGS += -fPIE -pie
+LOCAL_LDFLAGS += -rdynamic
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2015-8839/poc.c b/hostsidetests/security/securityPatch/CVE-2015-8839/poc.c
new file mode 100755
index 0000000..c6a330f
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2015-8839/poc.c
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+#define _GNU_SOURCE
+#include <cutils/log.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/falloc.h>
+#include <linux/magic.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+
+int main(void) {
+  int fd = -1, result = -1;
+  char tmpFile[32];
+  struct statfs sfs;
+
+  memset(tmpFile, 0, sizeof(tmpFile));
+  strncpy(tmpFile, "/data/local/tmp/tmpFile", 24);
+
+  fd = open(tmpFile, O_WRONLY | O_APPEND | O_CREAT, 0644);
+  if (fd < 0) {
+    ALOGE("Creation of tmp file is failed [%s]", strerror(errno));
+    return -1;
+  }
+
+  fstatfs(fd, &sfs);
+  if (sfs.f_type == EXT4_SUPER_MAGIC) {
+    result = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1);
+    if (result < 0 && errno == EOPNOTSUPP) {
+      ALOGD("fallocate result [%s] errno [%d]", strerror(errno), errno);
+      ALOGE("fallocate result EOPNOTSUPP");
+    }
+  }
+
+  if (fd) {
+    close(fd);
+  }
+
+  return 0;
+}
diff --git a/hostsidetests/security/src/android/security/cts/Poc16_09.java b/hostsidetests/security/src/android/security/cts/Poc16_09.java
index 7ab08ad..5cd86bd 100644
--- a/hostsidetests/security/src/android/security/cts/Poc16_09.java
+++ b/hostsidetests/security/src/android/security/cts/Poc16_09.java
@@ -26,4 +26,15 @@
     public void testPocCVE_2016_2471() throws Exception {
         AdbUtils.runPoc("CVE-2016-2471", getDevice(), 60);
     }
+
+    /**
+     *  b/28760453
+     */
+    @SecurityTest
+    public void testPocCVE_2015_8839() throws Exception {
+        AdbUtils.runCommandLine("logcat -c" , getDevice());
+        AdbUtils.runPoc("CVE-2015-8839", getDevice(), 60);
+        String logcat =  AdbUtils.runCommandLine("logcat -d", getDevice());
+        assertMatches("[\\s\\n\\S]*fallocate result EOPNOTSUPP[\\s\\n\\S]*", logcat);
+    }
 }
diff --git a/hostsidetests/security/src/android/security/cts/Poc17_03.java b/hostsidetests/security/src/android/security/cts/Poc17_03.java
index 80c959c..a6f1e04 100644
--- a/hostsidetests/security/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/security/src/android/security/cts/Poc17_03.java
@@ -82,4 +82,23 @@
         assertNotMatchesMultiLine(".*Fatal signal 11 \\(SIGSEGV\\).*>>> /system/bin/" +
                          "audioserver <<<.*", logcatOut);
     }
+
+    /*
+     *  b/33178389
+     */
+    @SecurityTest
+    public void testPocCVE_2017_0490() throws Exception {
+        String bootCountBefore =
+                AdbUtils.runCommandLine("settings get global boot_count", getDevice());
+        AdbUtils.runCommandLine("service call wifi 43 s16 content://settings/global/boot_count s16 "
+                + "\"application/x-wifi-config\"",
+                getDevice());
+        String bootCountAfter =
+                AdbUtils.runCommandLine("settings get global boot_count", getDevice());
+        // Poc nukes the boot_count setting, reboot to restore it to a sane value
+        AdbUtils.runCommandLine("reboot", getDevice());
+        getDevice().waitForDeviceOnline(60 * 1000);
+        updateKernelStartTime();
+        assertEquals(bootCountBefore, bootCountAfter);
+    }
 }
diff --git a/hostsidetests/security/src/android/security/cts/SecurityTestCase.java b/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
index cacceaa..e296f4c 100644
--- a/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
@@ -23,6 +23,9 @@
 import com.android.tradefed.log.LogUtil.CLog;
 
 import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.Map;
+import java.util.HashMap;
 import com.android.ddmlib.MultiLineReceiver;
 import com.android.ddmlib.Log;
 
@@ -31,7 +34,29 @@
     private static final String LOG_TAG = "SecurityTestCase";
 
     private long kernelStartTime;
-    private static Thread checkOom = null;
+
+    private static final long LOW_MEMORY_DEVICE_THRESHOLD_KB = 1024 * 1024; // 1GB
+    private boolean isLowMemoryDevice = false;
+    private static Map<ITestDevice, OomCatcher> oomCatchers = new HashMap<>();
+    private static Map<ITestDevice, Long> totalMemories = new HashMap<>();
+    private enum OomBehavior {
+        FAIL_AND_LOG, // normal behavior
+        PASS_AND_LOG, // skip tests that oom low memory devices
+        FAIL_NO_LOG,  // tests that check for oom
+    }
+    private OomBehavior oomBehavior = OomBehavior.FAIL_AND_LOG; // accessed across threads
+    private boolean oomDetected = false; // accessed across threads
+
+    private static long getMemTotal(ITestDevice device) throws Exception {
+        String memInfo = device.executeShellCommand("cat /proc/meminfo");
+        Pattern pattern = Pattern.compile("MemTotal:\\s*(.*?)\\s*[kK][bB]");
+        Matcher matcher = pattern.matcher(memInfo);
+        if (matcher.find()) {
+            return Long.parseLong(matcher.group(1));
+        } else {
+            throw new Exception("Could not get device memory total");
+        }
+    }
 
     /**
      * Waits for device to be online, marks the most recent boottime of the device
@@ -46,11 +71,35 @@
         //TODO:(badash@): Watch for other things to track.
         //     Specifically time when app framework starts
 
-        // Start Out of Memory detection in separate thread
-        //if (checkOom == null || !checkOom.isAlive()) {
-        //    checkOom = new Thread(new OomChecker());
-        //    checkOom.start();
-        //}
+        // Singleton for caching device TotalMem to avoid and adb shell for every test.
+        Long totalMemory = totalMemories.get(getDevice());
+        if (totalMemory == null) {
+            totalMemory = getMemTotal(getDevice());
+            totalMemories.put(getDevice(), totalMemory);
+        }
+        isLowMemoryDevice = totalMemory < LOW_MEMORY_DEVICE_THRESHOLD_KB;
+
+        // reset test oom behavior
+        // Low memory devices should skip (pass) tests when OOMing and log so that the
+        // high-memory-test flag can be added. Normal devices should fail tests that OOM so that
+        // they'll be ran again with --retry. If the test OOMs because previous tests used the
+        // memory, it will likely pass on a second try.
+        synchronized (this) { // synchronized for oomBehavior and oomDetected.
+            if (isLowMemoryDevice) {
+                oomBehavior = OomBehavior.PASS_AND_LOG;
+            } else {
+                oomBehavior = OomBehavior.FAIL_AND_LOG;
+            }
+            oomDetected = false;
+        }
+
+        // Singleton OOM detection in separate persistent threads for each device.
+        OomCatcher oomCatcher = oomCatchers.get(getDevice());
+        if (oomCatcher == null || !oomCatcher.isAlive()) {
+            oomCatcher = new OomCatcher();
+            oomCatchers.put(getDevice(), oomCatcher);
+            oomCatcher.start();
+        }
     }
 
     /**
@@ -102,6 +151,23 @@
                     - kernelStartTime < 2));
         //TODO(badash@): add ability to catch runtime restart
         getDevice().disableAdbRoot();
+
+        // pass, fail, or log based on the oom behavior
+        synchronized (this) { // synchronized for oomDetected and oomBehavior
+            if (oomDetected) {
+                switch (oomBehavior) {
+                    case FAIL_AND_LOG:
+                        fail("The device ran out of memory.");
+                        return;
+                    case PASS_AND_LOG:
+                        Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG, "Skipping test.");
+                        return;
+                    case FAIL_NO_LOG:
+                        fail();
+                        return;
+                }
+            }
+        }
     }
 
     public void assertMatches(String pattern, String input) throws Exception {
@@ -118,7 +184,26 @@
                    Pattern.DOTALL).matcher(input).matches());
     }
 
-    class OomChecker implements Runnable {
+    // Flag meaning the test will likely fail on devices with low memory.
+    public void setHighMemoryTest() {
+        synchronized (this) { // synchronized for oomBehavior
+            if (isLowMemoryDevice) {
+                oomBehavior = OomBehavior.PASS_AND_LOG;
+            } else {
+                oomBehavior = OomBehavior.FAIL_AND_LOG;
+            }
+        }
+    }
+
+    // Flag meaning the test uses the OOM catcher to fail the test because the test vulnerability
+    // intentionally OOMs the device.
+    public void setOomTest() {
+        synchronized (this) { // synchronized for oomBehavior
+            oomBehavior = OomBehavior.FAIL_NO_LOG;
+        }
+    }
+
+    class OomCatcher extends Thread {
 
         @Override
         public void run() {
@@ -130,7 +215,11 @@
                         if (Pattern.matches(".*lowmemorykiller.*", line)) {
                             // low memory detected, reboot device to clear memory and pass test
                             isCancelled = true;
-                            Log.i(LOG_TAG, "lowmemorykiller detected; rebooting device and passing test");
+                            Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+                                    "lowmemorykiller detected; rebooting device.");
+                            synchronized (SecurityTestCase.this) { // synchronized for oomDetected
+                                oomDetected = true;
+                            }
                             try {
                                 getDevice().rebootUntilOnline();
                                 updateKernelStartTime();
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index cce6171..47020ed 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -2010,15 +2010,20 @@
                     case RAW: {
                         Size targetSize = (numConfigs == 1) ? maxSizes.maxRawSize :
                                 overridePhysicalCameraSizes.get(j);
-                        ImageReader target = ImageReader.newInstance(
-                            targetSize.getWidth(), targetSize.getHeight(), RAW, numBuffers);
-                        target.setOnImageAvailableListener(imageDropperListener, mHandler);
-                        OutputConfiguration config = new OutputConfiguration(target.getSurface());
-                        if (numConfigs > 1) {
-                            config.setPhysicalCameraId(overridePhysicalCameraIds.get(j));
+                        // targetSize could be null in the logical camera case where only
+                        // physical camera supports RAW stream.
+                        if (targetSize != null) {
+                            ImageReader target = ImageReader.newInstance(
+                                targetSize.getWidth(), targetSize.getHeight(), RAW, numBuffers);
+                            target.setOnImageAvailableListener(imageDropperListener, mHandler);
+                            OutputConfiguration config =
+                                    new OutputConfiguration(target.getSurface());
+                            if (numConfigs > 1) {
+                                config.setPhysicalCameraId(overridePhysicalCameraIds.get(j));
+                            }
+                            outputConfigs.add(config);
+                            rawTargets.add(target);
                         }
-                        outputConfigs.add(config);
-                        rawTargets.add(target);
                         break;
                     }
                     default:
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 0342f08..3b28ad4 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -718,8 +718,8 @@
 
     @SuppressWarnings("unchecked")
     private void checkAttestationSecurityLevelDependentParams(Attestation attestation) {
-        assertThat("Attestation version must be 1 or 2", attestation.getAttestationVersion(),
-                either(is(1)).or(is(2)));
+        assertThat("Attestation version must be 1, 2, or 3", attestation.getAttestationVersion(),
+               either(is(1)).or(is(2)).or(is(3)));
 
         AuthorizationList teeEnforced = attestation.getTeeEnforced();
         AuthorizationList softwareEnforced = attestation.getSoftwareEnforced();
diff --git a/tests/tests/media/src/android/media/cts/DecoderTestXheAac.java b/tests/tests/media/src/android/media/cts/DecoderTestXheAac.java
index 2c549f2..151c94a 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTestXheAac.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTestXheAac.java
@@ -95,116 +95,124 @@
         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
 
         for (String aacDecName : sAacDecoderNames) {
-            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a running for dec=" + aacDecName);
-            // test DRC effectTypeID 1 "NIGHT"
-            // L -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
-            // R +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
             try {
-                checkUsacDrcEffectType(1, 0.5011f, 1.9952f, "Night", 2, 0, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/0 failed for dec=" + aacDecName);
-                throw new RuntimeException(e);
+                runDecodeUsacDrcEffectTypeM4a(aacDecName);
+            } catch (Error err) {
+                throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
             }
+        }
+    }
 
-            // test DRC effectTypeID 2 "NOISY"
-            // L +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
-            // R -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
-            try {
-                checkUsacDrcEffectType(2, 1.9952f, 0.2511f, "Noisy", 2, 0, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/0 failed for dec=" + aacDecName);
-                throw new RuntimeException(e);
-            }
+    private void runDecodeUsacDrcEffectTypeM4a(String aacDecName) throws Exception {
+        Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a running for dec=" + aacDecName);
+        // test DRC effectTypeID 1 "NIGHT"
+        // L -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
+        // R +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
+        try {
+            checkUsacDrcEffectType(1, 0.5011f, 1.9952f, "Night", 2, 0, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/0 failed for dec=" + aacDecName);
+            throw new RuntimeException(e);
+        } 
 
-            // test DRC effectTypeID 3 "LIMITED"
-            // L -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
-            // R +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
-            try {
-                checkUsacDrcEffectType(3, 0.2511f, 3.9810f, "Limited", 2, 0, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/0 failed for dec="
-                        + aacDecName);
-                throw new RuntimeException(e);
-            }
+        // test DRC effectTypeID 2 "NOISY"
+        // L +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f
+        // R -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
+        try {
+            checkUsacDrcEffectType(2, 1.9952f, 0.2511f, "Noisy", 2, 0, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/0 failed for dec=" + aacDecName);
+            throw new RuntimeException(e);
+        }
 
-            // test DRC effectTypeID 6 "GENERAL"
-            // L +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
-            // R -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
-            try {
-                checkUsacDrcEffectType(6, 3.9810f, 0.5011f, "General", 2, 0, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/0 failed for dec="
-                        + aacDecName);
-                throw new RuntimeException(e);
-            }
+        // test DRC effectTypeID 3 "LIMITED"
+        // L -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
+        // R +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
+        try {
+            checkUsacDrcEffectType(3, 0.2511f, 3.9810f, "Limited", 2, 0, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/0 failed for dec="
+                    + aacDecName);
+            throw new RuntimeException(e);
+        }
 
-            // test DRC effectTypeID 1 "NIGHT"
-            // L    -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
-            // R    +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
-            // mono -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
-            try {
-                checkUsacDrcEffectType(1, 0.2511f, 3.9810f, "Night", 2, 1, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
-                throw new RuntimeException(e);
-            }
-            try {
-                checkUsacDrcEffectType(1, 0.2511f, 0.0f, "Night", 1, 1, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/1/1 for dec=" + aacDecName);
-                throw new RuntimeException(e);
-            }
+        // test DRC effectTypeID 6 "GENERAL"
+        // L +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
+        // R -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f
+        try {
+            checkUsacDrcEffectType(6, 3.9810f, 0.5011f, "General", 2, 0, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/0 failed for dec="
+                    + aacDecName);
+            throw new RuntimeException(e);
+        }
 
-            // test DRC effectTypeID 2 "NOISY"
-            // L    +6dB -> normalization factor = 1/(10^( 6/10))   = 3.9810f
-            // R    -9dB -> normalization factor = 1/(10^(-9/10))  = 0.1258f
-            // mono +6dB -> normalization factor = 1/(10^( 6/10))   = 3.9810f
-            try {
-                checkUsacDrcEffectType(2, 3.9810f, 0.1258f, "Noisy", 2, 1, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/1 for dec=" + aacDecName);
-                throw new RuntimeException(e);
-            }
-            try {
-                checkUsacDrcEffectType(2, 3.9810f, 0.0f, "Noisy", 1, 1, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
-                throw new RuntimeException(e);
-            }
+        // test DRC effectTypeID 1 "NIGHT"
+        // L    -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
+        // R    +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f
+        // mono -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f
+        try {
+            checkUsacDrcEffectType(1, 0.2511f, 3.9810f, "Night", 2, 1, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
+            throw new RuntimeException(e);
+        }
+        try {
+            checkUsacDrcEffectType(1, 0.2511f, 0.0f, "Night", 1, 1, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/1/1 for dec=" + aacDecName);
+            throw new RuntimeException(e);
+        }
 
-            // test DRC effectTypeID 3 "LIMITED"
-            // L    -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
-            // R    +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
-            // mono -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
-            try {
-                checkUsacDrcEffectType(3, 0.1258f, 7.9432f, "Limited", 2, 1, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/1 for dec=" + aacDecName);
-                throw new RuntimeException(e);
-            }
-            try {
-                checkUsacDrcEffectType(3, 0.1258f, 0.0f, "Limited", 1, 1, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/1/1 for dec=" + aacDecName);
-                throw new RuntimeException(e);
-            }
+        // test DRC effectTypeID 2 "NOISY"
+        // L    +6dB -> normalization factor = 1/(10^( 6/10))   = 3.9810f
+        // R    -9dB -> normalization factor = 1/(10^(-9/10))  = 0.1258f
+        // mono +6dB -> normalization factor = 1/(10^( 6/10))   = 3.9810f
+        try {
+            checkUsacDrcEffectType(2, 3.9810f, 0.1258f, "Noisy", 2, 1, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/1 for dec=" + aacDecName);
+            throw new RuntimeException(e);
+        }
+        try {
+            checkUsacDrcEffectType(2, 3.9810f, 0.0f, "Noisy", 1, 1, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName);
+            throw new RuntimeException(e);
+        }
 
-            // test DRC effectTypeID 6 "GENERAL"
-            // L    +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
-            // R    -6dB -> normalization factor = 1/(10^(-6/10))  = 0.2511f
-            // mono +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
-            try {
-                checkUsacDrcEffectType(6, 7.9432f, 0.2511f, "General", 2, 1, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/1 for dec=" + aacDecName);
-                throw new RuntimeException(e);
-            }
-            try {
-                checkUsacDrcEffectType(6, 7.9432f, 0.0f, "General", 1, 1, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/1/1 for dec=" + aacDecName);
-                throw new RuntimeException(e);
-            }
+        // test DRC effectTypeID 3 "LIMITED"
+        // L    -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
+        // R    +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
+        // mono -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f
+        try {
+            checkUsacDrcEffectType(3, 0.1258f, 7.9432f, "Limited", 2, 1, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/1 for dec=" + aacDecName);
+            throw new RuntimeException(e);
+        }
+        try {
+            checkUsacDrcEffectType(3, 0.1258f, 0.0f, "Limited", 1, 1, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/1/1 for dec=" + aacDecName);
+            throw new RuntimeException(e);
+        }
+
+        // test DRC effectTypeID 6 "GENERAL"
+        // L    +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
+        // R    -6dB -> normalization factor = 1/(10^(-6/10))  = 0.2511f
+        // mono +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f
+        try {
+            checkUsacDrcEffectType(6, 7.9432f, 0.2511f, "General", 2, 1, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/1 for dec=" + aacDecName);
+            throw new RuntimeException(e);
+        }
+        try {
+            checkUsacDrcEffectType(6, 7.9432f, 0.0f, "General", 1, 1, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/1/1 for dec=" + aacDecName);
+            throw new RuntimeException(e);
         }
     }
 
@@ -218,52 +226,61 @@
         assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0);
 
         for (String aacDecName : sAacDecoderNames) {
-            // Stereo
-            // switch between SBR ratios and stereo modes
             try {
-                checkUsacStreamSwitching(2.5459829E12f, 2,
-                        R.raw.noise_2ch_44_1khz_aot42_19_lufs_config_change_mp4, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch sbr/stereo switch for "
-                        + aacDecName);
-                throw new RuntimeException(e);
-            }
-
-            // Mono
-            // switch between SBR ratios and stereo modes
-            try {
-                checkUsacStreamSwitching(2.24669126E12f, 1,
-                        R.raw.noise_1ch_38_4khz_aot42_19_lufs_config_change_mp4, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch sbr/stereo switch for "
-                        + aacDecName);
-                throw new RuntimeException(e);
-            }
-
-            // Stereo
-            // switch between USAC modes
-            try {
-                checkUsacStreamSwitching(2.1E12f, 2,
-                        R.raw.noise_2ch_35_28khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch USAC mode switch for "
-                        + aacDecName);
-                throw new RuntimeException(e);
-            }
-
-            // Mono
-            // switch between USAC modes
-            try {
-                checkUsacStreamSwitching(1.7E12f, 1,
-                        R.raw.noise_1ch_29_4khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch USAC mode switch for "
-                        + aacDecName);
-                throw new RuntimeException(e);
+                runDecodeUsacStreamSwitchingM4a(aacDecName);
+            } catch (Error err) {
+                throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
             }
         }
     }
 
+    private void runDecodeUsacStreamSwitchingM4a(String aacDecName) throws Exception {
+        // Stereo
+        // switch between SBR ratios and stereo modes
+        try {
+            checkUsacStreamSwitching(2.5459829E12f, 2,
+                    R.raw.noise_2ch_44_1khz_aot42_19_lufs_config_change_mp4, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch sbr/stereo switch for "
+                    + aacDecName);
+            throw new RuntimeException(e);
+        }
+
+        // Mono
+        // switch between SBR ratios and stereo modes
+        try {
+            checkUsacStreamSwitching(2.24669126E12f, 1,
+                    R.raw.noise_1ch_38_4khz_aot42_19_lufs_config_change_mp4, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch sbr/stereo switch for "
+                    + aacDecName);
+            throw new RuntimeException(e);
+        }
+
+        // Stereo
+        // switch between USAC modes
+        try {
+            checkUsacStreamSwitching(2.1E12f, 2,
+                    R.raw.noise_2ch_35_28khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch USAC mode switch for "
+                    + aacDecName);
+            throw new RuntimeException(e);
+        }
+
+        // Mono
+        // switch between USAC modes
+        try {
+            checkUsacStreamSwitching(1.7E12f, 1,
+                    R.raw.noise_1ch_29_4khz_aot42_19_lufs_drc_config_change_mp4, aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch USAC mode switch for "
+                    + aacDecName);
+            throw new RuntimeException(e);
+        }
+
+    }
+
     /**
      * Verify the correct decoding of USAC bitstreams with various sampling rates.
      */
@@ -275,20 +292,28 @@
 
         for (String aacDecName : sAacDecoderNames) {
             try {
-                checkUsacSamplingRate(R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, aacDecName);
-                checkUsacSamplingRate(R.raw.noise_2ch_12khz_aot42_19_lufs_mp4, aacDecName);
-                checkUsacSamplingRate(R.raw.noise_2ch_22_05khz_aot42_19_lufs_mp4, aacDecName);
-                checkUsacSamplingRate(R.raw.noise_2ch_64khz_aot42_19_lufs_mp4, aacDecName);
-                checkUsacSamplingRate(R.raw.noise_2ch_88_2khz_aot42_19_lufs_mp4, aacDecName);
-                checkUsacSamplingRateWoLoudness(R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4,
-                        aacDecName);
-            } catch (Exception e) {
-                Log.v(TAG, "testDecodeUsacSamplingRatesM4a for decoder" + aacDecName);
-                throw new RuntimeException(e);
+                runDecodeUsacSamplingRatesM4a(aacDecName);
+            } catch (Error err) {
+                throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err);
             }
         }
     }
 
+    private void runDecodeUsacSamplingRatesM4a(String aacDecName) throws Exception {
+        try {
+            checkUsacSamplingRate(R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, aacDecName);
+            checkUsacSamplingRate(R.raw.noise_2ch_12khz_aot42_19_lufs_mp4, aacDecName);
+            checkUsacSamplingRate(R.raw.noise_2ch_22_05khz_aot42_19_lufs_mp4, aacDecName);
+            checkUsacSamplingRate(R.raw.noise_2ch_64khz_aot42_19_lufs_mp4, aacDecName);
+            checkUsacSamplingRate(R.raw.noise_2ch_88_2khz_aot42_19_lufs_mp4, aacDecName);
+            checkUsacSamplingRateWoLoudness(R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4,
+                    aacDecName);
+        } catch (Exception e) {
+            Log.v(TAG, "testDecodeUsacSamplingRatesM4a for decoder" + aacDecName);
+            throw new RuntimeException(e);
+        }
+    }
+
 
     /**
      *  Internal utilities
@@ -440,7 +465,7 @@
     }
 
     /**
-     * Same as {@link #checkEnergyUSAC(short[], AudioParameter, int, int)} but with DRC effec type
+     * Same as {@link #checkEnergyUSAC(short[], AudioParameter, int, int)} but with DRC effect type
      * @param decSamples
      * @param decParams
      * @param encNch
diff --git a/tests/tests/notificationlegacy/AndroidManifest.xml b/tests/tests/notificationlegacy/AndroidManifest.xml
index 7b55bc8..dd96eac 100644
--- a/tests/tests/notificationlegacy/AndroidManifest.xml
+++ b/tests/tests/notificationlegacy/AndroidManifest.xml
@@ -17,6 +17,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.app.notification.legacy.cts">
+    <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
 
     <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="24" />
     <application>
@@ -30,6 +31,24 @@
                 <action android:name="android.service.notification.NotificationListenerService" />
             </intent-filter>
         </service>
+
+        <service android:name="android.app.notification.legacy.cts.LegacyConditionProviderService"
+                 android:exported="true"
+                 android:label="Legacy"
+                 android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.notification.ConditionProviderService" />
+            </intent-filter>
+        </service>
+
+        <service android:name="android.app.notification.legacy.cts.SecondaryConditionProviderService"
+                 android:exported="true"
+                 android:label="Secondary"
+                 android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.notification.ConditionProviderService" />
+            </intent-filter>
+        </service>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
new file mode 100644
index 0000000..7a172e5
--- /dev/null
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
@@ -0,0 +1,268 @@
+/*
+ * 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.app.notification.legacy.cts;
+
+import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
+import static android.service.notification.NotificationListenerService.INTERRUPTION_FILTER_PRIORITY;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import android.app.ActivityManager;
+import android.app.AutomaticZenRule;
+import android.app.Instrumentation;
+import android.app.NotificationManager;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+@RunWith(AndroidJUnit4.class)
+public class ConditionProviderServiceTest {
+    private static String TAG = "CpsTest";
+
+    private NotificationManager mNm;
+    private ActivityManager mActivityManager;
+    private Context mContext;
+    private ArraySet<String> ids = new ArraySet<>();
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+        toggleNotificationPolicyAccess(mContext.getPackageName(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        LegacyConditionProviderService.requestRebind(LegacyConditionProviderService.getId());
+        SecondaryConditionProviderService.requestRebind(SecondaryConditionProviderService.getId());
+        mNm = (NotificationManager) mContext.getSystemService(
+                Context.NOTIFICATION_SERVICE);
+        mNm.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        try {
+            for (String id : ids) {
+                if (id != null) {
+                    if (!mNm.removeAutomaticZenRule(id)) {
+                        throw new Exception("Could not remove rule " + id);
+                    }
+
+                    assertNull(mNm.getAutomaticZenRule(id));
+                }
+            }
+        } finally {
+            toggleNotificationPolicyAccess(mContext.getPackageName(),
+                    InstrumentationRegistry.getInstrumentation(), false);
+            pollForConnection(LegacyConditionProviderService.class, false);
+            pollForConnection(SecondaryConditionProviderService.class, false);
+        }
+    }
+
+    @Test
+    public void testUnboundCPSMaintainsCondition_addsNewRule() throws Exception {
+        if (mActivityManager.isLowRamDevice()) {
+            return;
+        }
+
+        // make sure service get bound
+        pollForConnection(SecondaryConditionProviderService.class, true);
+
+        final ComponentName cn = SecondaryConditionProviderService.getId();
+
+        // add rule
+        addRule(cn, INTERRUPTION_FILTER_ALARMS, true);
+        pollForSubscribe(SecondaryConditionProviderService.getInstance());
+        assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+        // unbind service
+        SecondaryConditionProviderService.getInstance().requestUnbind();
+
+        // verify that DND state doesn't change
+        assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+        // add a new rule
+        addRule(cn, INTERRUPTION_FILTER_NONE, true);
+
+        // verify that the unbound service maintains it's DND vote
+        assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+    }
+
+    @Test
+    public void testUnboundCPSMaintainsCondition_otherConditionChanges() throws Exception {
+        if (mActivityManager.isLowRamDevice()) {
+            return;
+        }
+
+        // make sure both services get bound
+        pollForConnection(LegacyConditionProviderService.class, true);
+        pollForConnection(SecondaryConditionProviderService.class, true);
+
+        // add rules for both
+        addRule(LegacyConditionProviderService.getId(), INTERRUPTION_FILTER_PRIORITY, true);
+        pollForSubscribe(LegacyConditionProviderService.getInstance());
+
+        addRule(SecondaryConditionProviderService.getId(), INTERRUPTION_FILTER_ALARMS, true);
+        pollForSubscribe(SecondaryConditionProviderService.getInstance());
+        assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+        // unbind one of the services
+        SecondaryConditionProviderService.getInstance().requestUnbind();
+
+        // verify that DND state doesn't change
+        assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+        // trigger a change in the bound service's condition
+        ((LegacyConditionProviderService) LegacyConditionProviderService.getInstance())
+                .toggleDND(false);
+
+        // verify that the unbound service maintains it's DND vote
+        assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+    }
+
+    @Test
+    public void testUnboundCPSMaintainsCondition_otherProviderRuleChanges() throws Exception {
+        if (mActivityManager.isLowRamDevice()) {
+            return;
+        }
+
+        // make sure both services get bound
+        pollForConnection(LegacyConditionProviderService.class, true);
+        pollForConnection(SecondaryConditionProviderService.class, true);
+
+        // add rules for both
+        addRule(LegacyConditionProviderService.getId(), INTERRUPTION_FILTER_PRIORITY, true);
+        pollForSubscribe(LegacyConditionProviderService.getInstance());
+
+        addRule(SecondaryConditionProviderService.getId(), INTERRUPTION_FILTER_ALARMS, true);
+        pollForSubscribe(SecondaryConditionProviderService.getInstance());
+        assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+        // unbind one of the services
+        SecondaryConditionProviderService.getInstance().requestUnbind();
+
+        // verify that DND state doesn't change
+        assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+
+        // trigger a change in the bound service's rule
+        addRule(SecondaryConditionProviderService.getId(), INTERRUPTION_FILTER_PRIORITY, false);
+
+        // verify that the unbound service maintains it's DND vote
+        assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
+    }
+
+    private void addRule(ComponentName cn, int filter, boolean enabled) {
+        String id = mNm.addAutomaticZenRule(new AutomaticZenRule("name",
+                cn, Uri.EMPTY, filter, enabled));
+        Log.d(TAG, "Created rule with id " + id);
+        ids.add(id);
+    }
+
+    private void toggleNotificationPolicyAccess(String packageName,
+            Instrumentation instrumentation, boolean on) throws IOException {
+
+        String command = " cmd notification " + (on ? "allow_dnd " : "disallow_dnd ") + packageName;
+
+        runCommand(command, instrumentation);
+
+        NotificationManager nm = mContext.getSystemService(NotificationManager.class);
+        Assert.assertEquals("Notification Policy Access Grant is " +
+                        nm.isNotificationPolicyAccessGranted() + " not " + on, on,
+                nm.isNotificationPolicyAccessGranted());
+    }
+
+    private void runCommand(String command, Instrumentation instrumentation) throws IOException {
+        UiAutomation uiAutomation = instrumentation.getUiAutomation();
+        // Execute command
+        try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
+            Assert.assertNotNull("Failed to execute shell command: " + command, fd);
+            // Wait for the command to finish by reading until EOF
+            try (InputStream in = new FileInputStream(fd.getFileDescriptor())) {
+                byte[] buffer = new byte[4096];
+                while (in.read(buffer) > 0) {}
+            } catch (IOException e) {
+                throw new IOException("Could not read stdout of command: " + command, e);
+            }
+        } finally {
+            uiAutomation.destroy();
+        }
+    }
+
+    private void pollForSubscribe(PollableConditionProviderService service)  throws Exception {
+        int tries = 30;
+        int delayMs = 200;
+
+        while (tries-- > 0 && !service.subscribed) {
+            try {
+                Thread.sleep(delayMs);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        if (!service.subscribed) {
+            Log.d(TAG, "not subscribed");
+            throw new Exception("Service never got onSubscribe()");
+        }
+    }
+
+    private void pollForConnection(Class<? extends PollableConditionProviderService> service,
+            boolean waitForConnection) throws Exception {
+        int tries = 100;
+        int delayMs = 200;
+
+        PollableConditionProviderService instance =
+                (PollableConditionProviderService) service.getMethod("getInstance").invoke(null);
+
+        while (tries-- > 0 && (waitForConnection ? instance == null : instance != null)) {
+            try {
+                Thread.sleep(delayMs);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            instance = (PollableConditionProviderService) service.getMethod("getInstance")
+                    .invoke(null);
+        }
+
+        if (waitForConnection && instance == null) {
+            Log.d(TAG, service.getName() + " not bound");
+            throw new Exception("CPS never bound");
+        } else if (!waitForConnection && instance != null) {
+            Log.d(TAG, service.getName() + " still bound");
+            throw new Exception("CPS still bound");
+        } else {
+            Log.d(TAG, service.getName() + " has a correct bind state");
+        }
+    }
+}
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java
new file mode 100644
index 0000000..72d5d3e
--- /dev/null
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java
@@ -0,0 +1,49 @@
+/*
+ * 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.app.notification.legacy.cts;
+
+import android.content.ComponentName;
+import android.service.notification.Condition;
+
+public class LegacyConditionProviderService extends PollableConditionProviderService {
+    private static PollableConditionProviderService sInstance = null;
+
+    public static ComponentName getId() {
+        return new ComponentName(LegacyConditionProviderService.class.getPackage().getName(),
+                LegacyConditionProviderService.class.getName());
+    }
+
+    public static PollableConditionProviderService getInstance() {
+        return sInstance;
+    }
+
+    @Override
+    public void onConnected() {
+        super.onConnected();
+        sInstance = this;
+    }
+
+    @Override
+    public void onDestroy() {
+        sInstance = null;
+        super.onDestroy();
+    }
+
+    public void toggleDND(boolean on) {
+        notifyCondition(
+                new Condition(conditionId, "", on ? Condition.STATE_TRUE : Condition.STATE_FALSE));
+    }
+}
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
index 69103c8..528d66f 100644
--- a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
@@ -46,6 +46,7 @@
 
 import junit.framework.Assert;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -79,6 +80,12 @@
         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        toggleListenerAccess(MockNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), false);
+    }
+
     @Test
     public void testPrePCannotToggleAlarmsAndMediaTest() throws Exception {
         if (mActivityManager.isLowRamDevice()) {
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/PollableConditionProviderService.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/PollableConditionProviderService.java
new file mode 100644
index 0000000..226c96f
--- /dev/null
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/PollableConditionProviderService.java
@@ -0,0 +1,57 @@
+/*
+ * 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.app.notification.legacy.cts;
+
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
+import android.util.Log;
+
+public abstract class PollableConditionProviderService extends ConditionProviderService {
+    final static String TAG = "CtsCps";
+
+    boolean isConnected;
+    boolean subscribed;
+    Uri conditionId;
+
+    @Override
+    public void onConnected() {
+        Log.d(TAG, getClass().getName() + " Connected");
+        isConnected = true;
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(TAG, getClass().getName() + " Destroyed");
+        isConnected = false;
+        super.onDestroy();
+    }
+
+    @Override
+    public void onSubscribe(Uri conditionId) {
+        Log.d(TAG, getClass().getName() + " got subscribe");
+        subscribed = true;
+        this.conditionId = conditionId;
+        notifyCondition(new Condition(conditionId, "", Condition.STATE_TRUE));
+    }
+
+    @Override
+    public void onUnsubscribe(Uri conditionId) {
+        Log.d(TAG, getClass().getName() + " got unsubscribe");
+        subscribed = false;
+        this.conditionId = null;
+    }
+}
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java
new file mode 100644
index 0000000..2310a30
--- /dev/null
+++ b/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java
@@ -0,0 +1,44 @@
+/*
+ * 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.app.notification.legacy.cts;
+
+import android.content.ComponentName;
+
+public class SecondaryConditionProviderService extends PollableConditionProviderService {
+    private static PollableConditionProviderService sInstance = null;
+
+    public static ComponentName getId() {
+        return new ComponentName(SecondaryConditionProviderService.class.getPackage().getName(),
+                SecondaryConditionProviderService.class.getName());
+    }
+
+    public static PollableConditionProviderService getInstance() {
+        return sInstance;
+    }
+
+    @Override
+    public void onConnected() {
+        super.onConnected();
+        sInstance = this;
+    }
+
+    @Override
+    public void onDestroy() {
+        sInstance = null;
+        super.onDestroy();
+    }
+
+}
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowPortraitTest.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowPortraitTest.java
index 1caed6f..6b484bd 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowPortraitTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceActivityFlowPortraitTest.java
@@ -16,7 +16,11 @@
 
 package android.preference2.cts;
 
+import static android.content.pm.PackageManager.FEATURE_LEANBACK;
+import static org.junit.Assume.assumeFalse;
+
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
@@ -40,6 +44,9 @@
 
     @Before
     public void setup() {
+        PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
+        // Ignore this test on Leanback since Leanback doesn't support portrait orientation
+        assumeFalse(pm.hasSystemFeature(FEATURE_LEANBACK));
         mTestUtils = new TestUtils();
     }
 
diff --git a/tests/tests/security/res/raw/bug_110435401.mid b/tests/tests/security/res/raw/bug_110435401.mid
new file mode 100644
index 0000000..184ab1f
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_110435401.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_65484460.mp4 b/tests/tests/security/res/raw/bug_65484460.mp4
new file mode 100644
index 0000000..13b37e9
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_65484460.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_68664359.mid b/tests/tests/security/res/raw/bug_68664359.mid
new file mode 100644
index 0000000..f816d82
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_68664359.mid
@@ -0,0 +1 @@
+DK:@~kkkkk
\ No newline at end of file
diff --git a/tests/tests/security/res/raw/cve_2016_3879.mp3 b/tests/tests/security/res/raw/cve_2016_3879.mp3
new file mode 100644
index 0000000..23ca4c3
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2016_3879.mp3
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_18155.mp4 b/tests/tests/security/res/raw/cve_2017_18155.mp4
new file mode 100644
index 0000000..5765dbb
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_18155.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_9423.mp4 b/tests/tests/security/res/raw/cve_2018_9423.mp4
new file mode 100755
index 0000000..08e2387
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_9423.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
new file mode 100644
index 0000000..6a4990f
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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 org.junit.Test;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.platform.test.annotations.SecurityTest;
+import android.test.AndroidTestCase;
+
+@SecurityTest
+public class BluetoothIntentsTest extends AndroidTestCase {
+  /**
+   * b/35258579
+   */
+  @SecurityTest
+  public void testAcceptIntent() {
+    genericIntentTest("ACCEPT");
+  }
+
+  /**
+   * b/35258579
+   */
+  @SecurityTest
+  public void testDeclineIntent() {
+      genericIntentTest("DECLINE");
+  }
+
+  private static final String prefix = "android.btopp.intent.action.";
+  private void genericIntentTest(String action) throws SecurityException {
+    try {
+      Intent should_be_protected_broadcast = new Intent();
+      should_be_protected_broadcast.setComponent(
+          new ComponentName("com.android.bluetooth",
+            "com.android.bluetooth.opp.BluetoothOppReceiver"));
+      should_be_protected_broadcast.setAction(prefix + action);
+      mContext.sendBroadcast(should_be_protected_broadcast);
+    }
+    catch (SecurityException e) {
+      return;
+    }
+
+    throw new SecurityException("An " + prefix + action +
+        " intent should not be broadcastable except by the system (declare " +
+        " as protected-broadcast in manifest)");
+  }
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 4e128bc..559d01a 100755
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -827,6 +827,16 @@
      ***********************************************************/
 
     @SecurityTest
+    public void testStagefright_bug_68664359() throws Exception {
+        doStagefrightTest(R.raw.bug_68664359, 60000);
+    }
+
+    @SecurityTest
+    public void testStagefright_bug_110435401() throws Exception {
+        doStagefrightTest(R.raw.bug_110435401, 60000);
+    }
+
+    @SecurityTest
     public void testStagefright_cve_2017_0474() throws Exception {
         doStagefrightTest(R.raw.cve_2017_0474, 120000);
     }
@@ -919,6 +929,26 @@
         doStagefrightTest(R.raw.cve_2016_6699);
     }
 
+    @SecurityTest
+    public void testStagefright_bug_65484460() throws Exception {
+        doStagefrightTest(R.raw.bug_65484460);
+    }
+
+    @SecurityTest
+    public void testStagefright_cve_2017_18155() throws Exception {
+        doStagefrightTest(R.raw.cve_2017_18155);
+    }
+
+    @SecurityTest
+    public void testStagefright_cve_2018_9423() throws Exception {
+        doStagefrightTest(R.raw.cve_2018_9423);
+    }
+
+    @SecurityTest
+    public void testStagefright_cve_2016_3879() throws Exception {
+        doStagefrightTest(R.raw.cve_2016_3879);
+    }
+
     private void doStagefrightTest(final int rid) throws Exception {
         doStagefrightTestMediaPlayer(rid);
         doStagefrightTestMediaCodec(rid);
diff --git a/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml b/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml
index d2cc04a..cd30602 100755
--- a/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml
+++ b/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml
@@ -23,6 +23,14 @@
 
         <activity android:name="Launcher" android:enabled="true" android:exported="false">
         </activity>
+
+        <activity-alias android:name="HomeActivity"
+            android:targetActivity="Launcher">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity-alias>
     </application>
 </manifest>
 
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
index 904f0cf..f2b9fc4 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
@@ -129,6 +129,8 @@
         assertExpectException(NullPointerException.class, "action must be set",
                 () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
 
+        setCurrentCaller(getTestContext());
+
         assertExpectException(
                 IllegalArgumentException.class, "Short label must be provided", () -> {
                     ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerFakingPublisherTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerFakingPublisherTest.java
new file mode 100644
index 0000000..baa47b0
--- /dev/null
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerFakingPublisherTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.content.pm.cts.shortcutmanager;
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.runCommand;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ShortcutInfo;
+import android.platform.test.annotations.SecurityTest;
+import android.support.test.InstrumentationRegistry;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Assume;
+
+/**
+ * CTS for b/109824443.
+ */
+@SmallTest
+@SecurityTest
+public class ShortcutManagerFakingPublisherTest extends ShortcutManagerCtsTestsBase {
+    private static final String ANOTHER_PACKAGE =
+            "android.content.pm.cts.shortcutmanager.packages.package4";
+
+    private static final ComponentName ANOTHER_HOME_ACTIVITY = new ComponentName(
+            ANOTHER_PACKAGE, "android.content.pm.cts.shortcutmanager.packages.HomeActivity");
+
+    private static final String INVALID_ID =
+            "[ShortcutManagerFakingPublisherTest.shortcut_that_should_not_be_created]";
+
+    @Override
+    protected String getOverrideConfig() {
+        return "reset_interval_sec=999999,"
+                + "max_updates_per_interval=999999,"
+                + "max_shortcuts=10"
+                + "max_icon_dimension_dp=96,"
+                + "max_icon_dimension_dp_lowram=96,"
+                + "icon_format=PNG,"
+                + "icon_quality=100";
+    }
+
+    public void testSpoofingPublisher() {
+        final Context myContext = getTestContext();
+        final Context anotherContext;
+        try {
+            anotherContext = getTestContext().createPackageContext(ANOTHER_PACKAGE, 0);
+        } catch (NameNotFoundException e) {
+            fail("Unable to create package context for " + ANOTHER_PACKAGE);
+            return;
+        }
+        final ShortcutInfo invalid = new ShortcutInfo.Builder(anotherContext, INVALID_ID)
+                .setShortLabel(INVALID_ID)
+                .setIntent(new Intent(Intent.ACTION_VIEW))
+                .setActivity(ANOTHER_HOME_ACTIVITY)
+                .build();
+
+        // Check set.
+        runWithCaller(mPackageContext1, () -> {
+            getManager().removeAllDynamicShortcuts();
+
+            assertShortcutPackageMismatch("setDynamicShortcuts1", mPackageContext1, () -> {
+                getManager().setDynamicShortcuts(list(
+                        invalid));
+            });
+            assertInvalidShortcutNotCreated();
+            assertShortcutPackageMismatch("setDynamicShortcuts2A", mPackageContext1, () -> {
+                getManager().setDynamicShortcuts(list(
+                        invalid,
+                        makeShortcut("s1", "title1")));
+            });
+            assertInvalidShortcutNotCreated();
+            assertShortcutPackageMismatch("setDynamicShortcuts2B", mPackageContext1, () -> {
+                getManager().setDynamicShortcuts(list(
+                        makeShortcut("s1", "title1"),
+                        invalid));
+            });
+            assertInvalidShortcutNotCreated();
+        });
+
+        // Check add.
+        runWithCaller(mPackageContext1, () -> {
+            getManager().removeAllDynamicShortcuts();
+
+            assertShortcutPackageMismatch("addDynamicShortcuts1", mPackageContext1, () -> {
+                getManager().addDynamicShortcuts(list(
+                        invalid));
+            });
+            assertInvalidShortcutNotCreated();
+            assertShortcutPackageMismatch("addDynamicShortcuts2A", mPackageContext1, () -> {
+                getManager().addDynamicShortcuts(list(
+                        invalid,
+                        makeShortcut("s1", "title1")));
+            });
+            assertInvalidShortcutNotCreated();
+            assertShortcutPackageMismatch("addDynamicShortcuts2B", mPackageContext1, () -> {
+                getManager().addDynamicShortcuts(list(
+                        makeShortcut("s1", "title1"),
+                        invalid));
+            });
+            assertInvalidShortcutNotCreated();
+        });
+
+        // Check update.
+        runWithCaller(mPackageContext1, () -> {
+            getManager().removeAllDynamicShortcuts();
+
+            assertShortcutPackageMismatch("updateShortcuts1", mPackageContext1, () -> {
+                getManager().updateShortcuts(list(
+                        invalid));
+            });
+            assertInvalidShortcutNotCreated();
+            assertShortcutPackageMismatch("updateShortcuts2A", mPackageContext1, () -> {
+                getManager().updateShortcuts(list(
+                        invalid,
+                        makeShortcut("s1", "title1")));
+            });
+            assertInvalidShortcutNotCreated();
+            assertShortcutPackageMismatch("updateShortcuts2B", mPackageContext1, () -> {
+                getManager().updateShortcuts(list(
+                        makeShortcut("s1", "title1"),
+                        invalid));
+            });
+            assertInvalidShortcutNotCreated();
+        });
+
+        // requestPin (API26 and above)
+        runWithCaller(mPackageContext1, () -> {
+            getManager().removeAllDynamicShortcuts();
+
+            assertShortcutPackageMismatch("requestPinShortcut", mPackageContext1, () -> {
+                getManager().requestPinShortcut(invalid, null);
+            });
+            assertInvalidShortcutNotCreated();
+        });
+
+        // createShortcutResultIntent (API26 and above)
+        runWithCaller(mPackageContext1, () -> {
+            getManager().removeAllDynamicShortcuts();
+
+            assertShortcutPackageMismatch("createShortcutResultIntent", mPackageContext1, () -> {
+                getManager().createShortcutResultIntent(invalid);
+            });
+            assertInvalidShortcutNotCreated();
+        });
+    }
+
+    private void assertInvalidShortcutNotCreated() {
+        for (String s : runCommand(InstrumentationRegistry.getInstrumentation(),
+                "dumpsys shortcut")) {
+            assertFalse("dumpsys shortcut contained invalid ID", s.contains(INVALID_ID));
+        }
+    }
+
+    private void assertShortcutPackageMismatch(String method, Context callerContext, Runnable r) {
+        assertExpectException(
+                "Caller=" + callerContext.getPackageName() + ", method=" + method,
+                SecurityException.class, "Shortcut package name mismatch",
+                () -> runWithCaller(callerContext, () -> r.run())
+        );
+    }
+}