Merge "[CTS] LauncherApps lockdown fix" into pi-dev
diff --git a/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
new file mode 100644
index 0000000..920d40c
--- /dev/null
+++ b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
@@ -0,0 +1,229 @@
+# Copyright 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.
+
+import math
+import os.path
+import re
+import sys
+import cv2
+
+import its.caps
+import its.device
+import its.image
+import its.objects
+
+import numpy as np
+
+ALIGN_THRESH = 0.005
+CHART_DISTANCE_CM = 22  # cm
+NAME = os.path.basename(__file__).split('.')[0]
+ROTATE_REF_MATRIX = np.array([0, 0, 0, 1])
+TRANS_REF_MATRIX = np.array([0, 0, 0])
+
+
+def rotation_matrix(rotation):
+    """Convert the rotation parameters to 3-axis data.
+
+    Args:
+        rotation:   android.lens.Rotation vector
+    Returns:
+        3x3 matrix w/ rotation parameters
+    """
+    x = rotation[0]
+    y = rotation[1]
+    z = rotation[2]
+    w = rotation[3]
+    return np.array([[1-2*y**2-2*z**2, 2*x*y-2*z*w, 2*x*z+2*y*w],
+                     [2*x*y+2*z*w, 1-2*x**2-2*z**2, 2*y*z-2*x*w],
+                     [2*x*z-2*y*w, 2*y*z+2*x*w, 1-2*x**2-2*y**2]])
+
+
+def find_circle(gray, name):
+    """Find the circle in the image.
+
+    Args:
+        gray:           gray scale image array [0,255]
+        name:           string of file name
+    Returns:
+        center:         circle center location (x, y)
+    """
+
+    cv2_version = cv2.__version__
+    try:
+        if cv2_version.startswith('2.4.'):
+            center = cv2.HoughCircles(gray, cv2.cv.CV_HOUGH_GRADIENT,
+                                      1, 20)[0][0]
+        elif cv2_version.startswith('3.2.'):
+            center = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT,
+                                      1, 20)[0][0]
+    except TypeError:
+        center = None
+        its.image.write_image(gray[..., np.newaxis]/255.0, name)
+    assert center is not None, 'No circle found!'
+    return center
+
+
+def main():
+    """Test the multi camera system parameters related to camera spacing."""
+    chart_distance = CHART_DISTANCE_CM
+    for s in sys.argv[1:]:
+        if s[:5] == 'dist=' and len(s) > 5:
+            chart_distance = float(re.sub('cm', '', s[5:]))
+            print 'Using chart distance: %.1fcm' % chart_distance
+
+    with its.device.ItsSession() as cam:
+        props = cam.get_camera_properties()
+        its.caps.skip_unless(its.caps.compute_target_exposure(props) and
+                             its.caps.per_frame_control(props) and
+                             its.caps.logical_multi_camera(props) and
+                             its.caps.raw16(props) and
+                             its.caps.manual_sensor(props))
+        props = cam.get_camera_properties()
+        debug = its.caps.debug_mode()
+
+        max_raw_size = its.objects.get_available_output_sizes('raw', props)[0]
+        w, h = its.objects.get_available_output_sizes(
+                'yuv', props, match_ar_size=max_raw_size)[0]
+
+        # Do 3A and get the values
+        s, e, _, _, fd = cam.do_3a(get_results=True,
+                                   lock_ae=True, lock_awb=True)
+        e *= 2  # TODO: remove when RAW images bright enough
+        req = its.objects.manual_capture_request(s, e, fd, True, props)
+
+        # get physical camera properties
+        ids = its.caps.logical_multi_camera_physical_ids(props)
+        props_physical = {}
+        for i in ids:
+            props_physical[i] = cam.get_camera_properties_by_id(i)
+
+        # capture RAWs of 1st 2 cameras
+        cap_raw = {}
+        out_surfaces = [{'format': 'yuv', 'width': w, 'height': h},
+                        {'format': 'raw', 'physicalCamera': ids[0]},
+                        {'format': 'raw', 'physicalCamera': ids[1]}]
+        _, cap_raw[ids[0]], cap_raw[ids[1]] = cam.do_capture(req, out_surfaces)
+
+    size_raw = {}
+    k = {}
+    reference = {}
+    rotation = {}
+    trans = {}
+    circle = {}
+    point = {}
+    for i in ids:
+        print 'Starting camera %s' % i
+        # process image
+        img_raw = its.image.convert_capture_to_rgb_image(
+                cap_raw[i], props=props)
+        size_raw[i] = (cap_raw[i]['width'], cap_raw[i]['height'])
+
+        # save images if debug
+        if debug:
+            its.image.write_image(img_raw, '%s_raw_%s.jpg' % (NAME, i))
+
+        # convert to [0, 255] images
+        img_raw *= 255
+
+        # rotate images and scale to match calibration data
+        # TODO remove rotation when not needed w/ EVT2
+        img_rot = np.rot90(cv2.resize(img_raw.astype(np.uint8), None,
+                                      fx=2, fy=2), k=2)
+
+        # load parameters for each physical camera
+        ical = props_physical[i]['android.lens.intrinsicCalibration']
+        assert len(ical) == 5, 'android.lens.instrisicCalibration incorrect.'
+        k[i] = np.array([[ical[0], ical[4], ical[2]],
+                         [0, ical[1], ical[3]],
+                         [0, 0, 1]])
+        print ' k:', k[i]
+
+        rotation[i] = np.array(props_physical[i]['android.lens.poseRotation'])
+        print ' rotation:', rotation[i]
+        assert len(rotation[i]) == 4, 'poseRotation has wrong # of params.'
+        trans[i] = np.array(
+                props_physical[i]['android.lens.poseTranslation'])
+        print ' translation:', trans[i]
+        assert len(trans[i]) == 3, 'poseTranslation has wrong # of params.'
+        if ((rotation[i] == ROTATE_REF_MATRIX).all() and
+                    (trans[i] == TRANS_REF_MATRIX).all()):
+            reference[i] = True
+        else:
+            reference[i] = False
+        # TODO: change below to android.lens.distortion when builds working
+        rad_dist = np.array(
+                props_physical[i]['android.lens.radialDistortion'])
+        assert len(rad_dist) == 6, 'radialDistortion has wrong # of params.'
+
+        # Apply correction to image (if available)
+        if its.caps.distortion_correction(props):
+            cv2_distort = np.array([rad_dist[1], rad_dist[2],
+                                    rad_dist[4], rad_dist[5],
+                                    rad_dist[3]])
+            img_rot = cv2.undistort(img_rot, k[i], cv2_distort)
+            its.image.write_image(img_rot/255.0, '%s_correct_%s.jpg' % (
+                    NAME, i))
+
+        # Find the circles in grayscale image
+        circle[i] = find_circle(cv2.cvtColor(img_rot, cv2.COLOR_BGR2GRAY),
+                                '%s_gray%s.jpg' % (NAME, i))
+
+        # Find 3D location of circle centers
+        point[i] = np.dot(np.linalg.inv(k[i]),
+                          np.array([circle[i][0],
+                                    circle[i][1], 1])) * chart_distance * 1.0E-2
+
+    ref_index = (e for e in reference if e).next()
+    print 'reference camera id:', ref_index
+    ref_rotation = rotation[ref_index]
+    ref_rotation = ref_rotation.astype(np.float32)
+    print 'rotation reference:', ref_rotation
+    r = rotation_matrix(ref_rotation)
+    if debug:
+        print 'r:', r
+    t = -1 * trans[ref_index]
+    print 't:', t
+
+    # estimation ids[0] circle center from ids[1] & params
+    estimated_0 = cv2.projectPoints(point[ids[1]].reshape(1, 3),
+                                    r, t, k[ids[0]], None)[0][0][0]
+    err_0 = np.linalg.norm(estimated_0 - circle[ids[0]][:2])
+    print 'Circle centers [%s]' % ids[0]
+    print 'Measured:      %.1f, %.1f' % (circle[ids[0]][1], circle[ids[0]][0])
+    print 'Calculated:    %.1f, %.1f' % (estimated_0[1],
+                                         estimated_0[0])
+    print 'Error(pixels): %.1f' % err_0
+
+    # estimation ids[0] circle center from ids[1] & params
+    estimated_1 = cv2.projectPoints(point[ids[0]].reshape(1, 3),
+                                    r.T, -np.dot(r, t), k[ids[1]],
+                                    None)[0][0][0]
+    err_1 = np.linalg.norm(estimated_1 - circle[ids[1]][:2])
+    print 'Circle centers [%s]' % ids[1]
+    print 'Measured:      %.1f, %.1f' % (circle[ids[1]][1], circle[ids[1]][0])
+    print 'Calculated:    %.1f, %.1f' % (estimated_1[1], estimated_1[0])
+    print 'Error(pixels): %.1f' % err_1
+
+    err_0 /= math.sqrt(size_raw[ids[0]][0]**2 + size_raw[ids[0]][1]**2)
+    err_1 /= math.sqrt(size_raw[ids[1]][0]**2 + size_raw[ids[1]][1]**2)
+    msg = '%s -> %s center error too large! val=%.1f%%, THRESH=%.f%%' % (
+            ids[1], ids[0], err_0*100, ALIGN_THRESH*100)
+    assert err_0 < ALIGN_THRESH, msg
+    msg = '%s -> %s center error too large! val=%.1f%%, THRESH=%.f%%' % (
+            ids[0], ids[1], err_1*100, ALIGN_THRESH*100)
+    assert err_1 < ALIGN_THRESH, msg
+
+
+if __name__ == '__main__':
+    main()
diff --git a/apps/CameraITS/tools/load_scene.py b/apps/CameraITS/tools/load_scene.py
index b46a311..330b32f 100644
--- a/apps/CameraITS/tools/load_scene.py
+++ b/apps/CameraITS/tools/load_scene.py
@@ -18,6 +18,8 @@
 import sys
 import time
 
+import numpy as np
+
 
 def main():
     """Load charts on device and display."""
@@ -47,7 +49,7 @@
     remote_scene_file = '/sdcard/Download/%s.pdf' % scene
     local_scene_file = os.path.join(os.environ['CAMERA_ITS_TOP'], 'tests',
                                     scene)
-    if chart_distance == 20 and camera_fov < 90:
+    if np.isclose(chart_distance, 20, rtol=0.1) and camera_fov < 90:
         local_scene_file = os.path.join(local_scene_file,
                                         scene+'_0.67_scaled.pdf')
     else:
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index e4c20a8..b8230a8 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -28,6 +28,8 @@
 from its.device import ItsSession
 import its.image
 
+import numpy as np
+
 CHART_DELAY = 1  # seconds
 CHART_DISTANCE = 30.0  # cm
 CHART_HEIGHT = 13.5  # cm
@@ -173,7 +175,6 @@
     skip_scene_validation = False
     chart_distance = CHART_DISTANCE
     chart_height = CHART_HEIGHT
-    approx_equal = lambda a, b, t: abs(a - b) < t
 
     for s in sys.argv[1:]:
         if s[:7] == "camera=" and len(s) > 7:
@@ -194,6 +195,7 @@
         elif s[:5] == 'dist=' and len(s) > 5:
             chart_distance = float(re.sub('cm', '', s[5:]))
 
+    chart_dist_arg = 'dist= ' + str(chart_distance)
     auto_scene_switch = chart_host_id is not None
     merge_result_switch = result_device_id is not None
 
@@ -319,7 +321,6 @@
                     if (not merge_result_switch or
                             (merge_result_switch and camera_ids[0] == '0')):
                         scene_arg = 'scene=' + scene
-                        chart_dist_arg = 'dist= ' + str(chart_distance)
                         fov_arg = 'fov=' + camera_fov
                         cmd = ['python',
                                os.path.join(os.getcwd(), 'tools/load_scene.py'),
@@ -343,8 +344,8 @@
             # Extract chart from scene for scene3 once up front
             chart_loc_arg = ''
             if scene == 'scene3':
-                if float(camera_fov) < 90 and approx_equal(chart_distance, 20,
-                                                           1E-6):
+                if float(camera_fov) < 90 and np.isclose(chart_distance, 20,
+                                                         rtol=0.1):
                     chart_height *= 0.67
                 chart = its.cv2image.Chart(SCENE3_FILE, chart_height,
                                            chart_distance, CHART_SCALE_START,
@@ -384,6 +385,7 @@
                     if skip_code is not SKIP_RET_CODE:
                         cmd = ['python', os.path.join(os.getcwd(), testpath)]
                         cmd += sys.argv[1:] + [camera_id_arg] + [chart_loc_arg]
+                        cmd += [chart_dist_arg]
                         with open(outpath, 'w') as fout, open(errpath, 'w') as ferr:
                             test_code = subprocess.call(
                                 cmd, stderr=ferr, stdout=fout, cwd=outdir)
diff --git a/apps/CtsVerifier/res/layout/voicemail_hide_in_call_settings.xml b/apps/CtsVerifier/res/layout/voicemail_hide_in_call_settings.xml
index eb8b81a..4d7803b 100644
--- a/apps/CtsVerifier/res/layout/voicemail_hide_in_call_settings.xml
+++ b/apps/CtsVerifier/res/layout/voicemail_hide_in_call_settings.xml
@@ -46,6 +46,12 @@
     </LinearLayout>
 
     <Button
+        android:id="@+id/call_settings_check_not_applicable"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/visual_voicemail_service_remove_sim_not_applicable"/>
+
+      <Button
         android:id="@+id/set_default_dialer"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/apps/CtsVerifier/res/layout/voicemail_hide_ringtone_settings.xml b/apps/CtsVerifier/res/layout/voicemail_hide_ringtone_settings.xml
index ea11314..9ccd909 100644
--- a/apps/CtsVerifier/res/layout/voicemail_hide_ringtone_settings.xml
+++ b/apps/CtsVerifier/res/layout/voicemail_hide_ringtone_settings.xml
@@ -32,11 +32,18 @@
         android:layout_height="wrap_content"
         android:text="@string/open_voicemail_settings_explanation"
         android:textSize="16dp"/>
+
     <Button
-        android:id="@+id/open_voicemail_settings"
+        android:id="@+id/voicemail_hide_ringtone_settings_not_applicable"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:text="@string/open_voicemail_settings"/>
+        android:text="@string/visual_voicemail_service_remove_sim_not_applicable"/>
+
+    <Button
+      android:id="@+id/open_voicemail_settings"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/open_voicemail_settings"/>
 
     <LinearLayout
         android:layout_width="wrap_content"
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/CallSettingsCheckActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/CallSettingsCheckActivity.java
index ac0f060..e2e4d30 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/CallSettingsCheckActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/CallSettingsCheckActivity.java
@@ -21,6 +21,8 @@
 import android.telecom.TelecomManager;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
 
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
@@ -32,6 +34,10 @@
 
     private DefaultDialerChanger mDefaultDialerChanger;
 
+    private Button mSetDefaultDialerButton;
+    private Button mNotApplicableButton;
+    private ImageView mRestoreDefaultDialerImage;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -44,6 +50,22 @@
 
         mDefaultDialerChanger = new DefaultDialerChanger(this);
 
+        mSetDefaultDialerButton = findViewById(R.id.set_default_dialer);
+        mNotApplicableButton = findViewById(R.id.call_settings_check_not_applicable);
+        mRestoreDefaultDialerImage = findViewById(R.id.restore_default_dialer_image);
+
+        mNotApplicableButton.setOnClickListener(
+                new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        getPassButton().setEnabled(true);
+                        mSetDefaultDialerButton.setEnabled(false);
+
+                        mRestoreDefaultDialerImage.setImageDrawable(getDrawable(R.drawable.fs_warning));
+                    }
+                }
+        );
+
         findViewById(R.id.open_call_settings).setOnClickListener(
                 new OnClickListener() {
                     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailSettingsCheckActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailSettingsCheckActivity.java
index d4ac0db..f2a7345 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailSettingsCheckActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailSettingsCheckActivity.java
@@ -21,6 +21,8 @@
 import android.telephony.TelephonyManager;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
 
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
@@ -30,6 +32,13 @@
  */
 public class VoicemailSettingsCheckActivity extends PassFailButtons.Activity {
 
+    private Button mNotApplicableButton;
+    private Button mOpenVoiceMailSettingsButton;
+    private Button mRingtoneSettingsDoesNotExistButton;
+    private Button mRingtoneSettingsExistsButton;
+
+    private ImageView mRestoreDefaultDialerImage;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -40,7 +49,30 @@
         setPassFailButtonClickListeners();
         getPassButton().setEnabled(false);
 
-        findViewById(R.id.open_voicemail_settings).setOnClickListener(
+
+        mNotApplicableButton = findViewById(R.id.voicemail_hide_ringtone_settings_not_applicable);
+        mOpenVoiceMailSettingsButton = findViewById(R.id.open_voicemail_settings);
+        mRingtoneSettingsDoesNotExistButton = findViewById(R.id.settings_hidden);
+        mRingtoneSettingsExistsButton = findViewById(R.id.settings_not_hidden);
+
+        mRestoreDefaultDialerImage = findViewById(R.id.restore_default_dialer_image);
+
+        mNotApplicableButton.setOnClickListener(
+                new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        getPassButton().setEnabled(true);
+
+                        mOpenVoiceMailSettingsButton.setEnabled(false);
+                        mRingtoneSettingsDoesNotExistButton.setEnabled(false);
+                        mRingtoneSettingsExistsButton.setEnabled(false);
+
+                        mRestoreDefaultDialerImage.setImageDrawable(getDrawable(R.drawable.fs_warning));
+                    }
+                }
+        );
+
+        mOpenVoiceMailSettingsButton.setOnClickListener(
                 new OnClickListener() {
                     @Override
                     public void onClick(View v) {
@@ -50,7 +82,7 @@
                 }
         );
 
-        findViewById(R.id.settings_hidden).setOnClickListener(
+        mRingtoneSettingsDoesNotExistButton.setOnClickListener(
                 new OnClickListener() {
                     @Override
                     public void onClick(View v) {
@@ -60,7 +92,7 @@
                 }
         );
 
-        findViewById(R.id.settings_not_hidden).setOnClickListener(
+        mRingtoneSettingsExistsButton.setOnClickListener(
                 new OnClickListener() {
                     @Override
                     public void onClick(View v) {
@@ -68,6 +100,5 @@
                     }
                 }
         );
-
     }
 }
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java
index fd05398..d12caa8 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicConditionalTestCase.java
@@ -26,7 +26,7 @@
     @Override
     @Before
     public void handleBusinessLogic() {
-        super.loadBuisnessLogic();
+        super.loadBusinessLogic();
         ensureAuthenticated();
         super.executeBusinessLogic();
     }
@@ -51,4 +51,4 @@
         // Fail test since request was not authorized.
         failTest(String.format("Unable to execute because %s.", message));
     }
-}
\ No newline at end of file
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
index ec940ce..130bf69 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
@@ -17,6 +17,7 @@
 package com.android.compatibility.common.util;
 
 import android.content.Context;
+import android.util.Log;
 
 import java.lang.reflect.Method;
 import java.util.Arrays;
@@ -47,6 +48,14 @@
      * {@inheritDoc}
      */
     @Override
+    public void logInfo(String format, Object... args) {
+        Log.i(LOG_TAG, String.format(format, args));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     protected ResolvedMethod getResolvedMethod(Class cls, String methodName, String... args)
             throws ClassNotFoundException {
         List<Method> nameMatches = getMethodsWithName(cls, methodName);
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
index 45f979a..671d33b 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
@@ -50,7 +50,7 @@
 
     @Before
     public void handleBusinessLogic() {
-        loadBuisnessLogic();
+        loadBusinessLogic();
         executeBusinessLogic();
     }
 
@@ -70,7 +70,7 @@
         }
     }
 
-    protected void loadBuisnessLogic() {
+    protected void loadBusinessLogic() {
         File businessLogicFile = new File(BusinessLogic.DEVICE_FILE);
         if (businessLogicFile.canRead()) {
             mBusinessLogic = BusinessLogicFactory.createFromFile(businessLogicFile);
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
index 4986b73..2216b2a 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
@@ -23,7 +23,6 @@
 import com.android.tradefed.build.IBuildProvider;
 import com.android.tradefed.build.IDeviceBuildInfo;
 import com.android.tradefed.build.IDeviceBuildProvider;
-import com.android.tradefed.build.VersionedFile;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.config.Option.Importance;
 import com.android.tradefed.config.OptionClass;
@@ -37,8 +36,10 @@
 import java.io.File;
 import java.io.IOException;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
 /**
@@ -206,12 +207,10 @@
     public void cleanUp(IBuildInfo info) {
         // Everything should have been copied properly to result folder, we clean up
         if (info instanceof IDeviceBuildInfo) {
-            for (VersionedFile f : info.getFiles()) {
-                // do not delete the testsdir since it's the real CTS folder.
-                if (!f.getFile().equals(((IDeviceBuildInfo) info).getTestsDir())) {
-                    FileUtil.recursiveDelete(f.getFile());
-                }
-            }
+            List<File> doNotDelete = new ArrayList<>();
+            // Clean up everything except the tests dir
+            doNotDelete.add(((IDeviceBuildInfo) info).getTestsDir());
+            info.cleanUp(doNotDelete);
         } else {
             info.cleanUp();
         }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java
index 7f527db..cebac97 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java
@@ -101,6 +101,10 @@
      */
     public void validateBuildFingerprint(ITestDevice device) throws DeviceNotAvailableException {
         String oldBuildFingerprint = new LightInvocationResult(getResult()).getBuildFingerprint();
+        if (oldBuildFingerprint == null) {
+            throw new IllegalArgumentException(
+                    "Could not find the build_fingerprint field in the result xml.");
+        }
         String currentBuildFingerprint = device.getProperty("ro.build.fingerprint");
         if (!oldBuildFingerprint.equals(currentBuildFingerprint)) {
             throw new IllegalArgumentException(String.format(
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java
index f7116d7..e2eefa4 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java
@@ -52,6 +52,10 @@
             String getRootDirPath() {
                 return mRootDir.getAbsolutePath();
             }
+            @Override
+            protected String getSuiteInfoName() {
+                return "CTS";
+            }
         };
     }
 
@@ -79,6 +83,8 @@
      */
     @Test
     public void testBaseGetBuild_withDevice() throws Exception {
+        // Create real testcases dir
+        new File(mRootDir, "android-cts/testcases").mkdirs();
         OptionSetter setter = new OptionSetter(mProvider);
         setter.setOptionValue("use-device-build-info", "true");
         setter.setOptionValue("branch", "build_branch");
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/CertificationChecksumHelperTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/CertificationChecksumHelperTest.java
index e36c898..3efb90d 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/CertificationChecksumHelperTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/CertificationChecksumHelperTest.java
@@ -93,9 +93,9 @@
         for (int i = 0; i < testCount; i++) {
             TestDescription test = new TestDescription("com.class.path", "testMethod" + i);
             results.testStarted(test);
-            results.testEnded(test, new HashMap<>());
+            results.testEnded(test, new HashMap<String, String>());
         }
-        results.testRunEnded(500L, new HashMap<>());
+        results.testRunEnded(500L, new HashMap<String, String>());
         return results;
     }
 }
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTestTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTestTest.java
index 1f2c544..b682cbf 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTestTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTestTest.java
@@ -31,6 +31,7 @@
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.invoker.IInvocationContext;
 import com.android.tradefed.invoker.InvocationContext;
+import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
 import com.android.tradefed.result.ITestInvocationListener;
 import com.android.tradefed.suite.checker.ISystemStatusChecker;
 import com.android.tradefed.testtype.IRemoteTest;
@@ -44,9 +45,9 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Unit tests for {@link RetryFactoryTest}.
@@ -183,7 +184,8 @@
 
         mMockListener.testModuleStarted(EasyMock.anyObject());
         mMockListener.testRunStarted("module1", 0);
-        mMockListener.testRunEnded(EasyMock.anyLong(), (Map<String, String>) EasyMock.anyObject());
+        mMockListener.testRunEnded(EasyMock.anyLong(),
+                (HashMap<String, Metric>) EasyMock.anyObject());
         mMockListener.testModuleEnded();
 
         EasyMock.replay(mMockListener, mMockInfo, mMockDevice);
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/BusinessLogicHostExecutor.java b/common/host-side/util/src/com/android/compatibility/common/util/BusinessLogicHostExecutor.java
index 43bdea1..7438959 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/BusinessLogicHostExecutor.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/BusinessLogicHostExecutor.java
@@ -16,8 +16,10 @@
 
 package com.android.compatibility.common.util;
 
+import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
 
 import java.lang.reflect.Method;
 import java.util.Arrays;
@@ -50,6 +52,14 @@
      * {@inheritDoc}
      */
     @Override
+    public void logInfo(String format, Object... args) {
+        LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG, String.format(format, args));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     protected ResolvedMethod getResolvedMethod(Class cls, String methodName, String... args)
             throws ClassNotFoundException {
         List<Method> nameMatches = getMethodsWithName(cls, methodName);
diff --git a/common/util/src/com/android/compatibility/common/util/BusinessLogic.java b/common/util/src/com/android/compatibility/common/util/BusinessLogic.java
index b87a250..2e0be41 100644
--- a/common/util/src/com/android/compatibility/common/util/BusinessLogic.java
+++ b/common/util/src/com/android/compatibility/common/util/BusinessLogic.java
@@ -16,8 +16,14 @@
 
 package com.android.compatibility.common.util;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+
+import org.junit.AssumptionViolatedException;
 
 /**
  * Helper and constants accessible to host and device components that enable Business Logic
@@ -29,7 +35,7 @@
     public static final String DEVICE_FILE = "/sdcard/bl";
 
     /* A map from testcase name to the business logic rules for the test case */
-    protected Map<String, List<BusinessLogicRule>> mRules;
+    protected Map<String, List<BusinessLogicRulesList>> mRules;
     /* Feature flag determining if device specific tests are executed. */
     public boolean mConditionalTestsEnabled;
     private AuthenticationStatusEnum mAuthenticationStatus = AuthenticationStatusEnum.UNKNOWN;
@@ -41,8 +47,16 @@
      * @return whether business logic exists for this test for this suite
      */
     public boolean hasLogicFor(String testName) {
-        List<BusinessLogicRule> rules = mRules.get(testName);
-        return rules != null && !rules.isEmpty();
+        List<BusinessLogicRulesList> rulesLists = mRules.get(testName);
+        return rulesLists != null && !rulesLists.isEmpty();
+    }
+
+    /**
+     * Return whether multiple rule lists exist in the BusinessLogic for this test name.
+     */
+    private boolean hasLogicsFor(String testName) {
+        List<BusinessLogicRulesList> rulesLists = mRules.get(testName);
+        return rulesLists != null && rulesLists.size() > 1;
     }
 
     /**
@@ -52,16 +66,93 @@
      * @param executor a {@link BusinessLogicExecutor}
      */
     public void applyLogicFor(String testName, BusinessLogicExecutor executor) {
-        List<BusinessLogicRule> rules = mRules.get(testName);
-        if (rules == null || rules.isEmpty()) {
+        if (!hasLogicFor(testName)) {
             return;
         }
-        for (BusinessLogicRule rule : rules) {
-            // Check conditions
-            if (rule.invokeConditions(executor)) {
-                rule.invokeActions(executor);
+        if (hasLogicsFor(testName)) {
+            applyLogicsFor(testName, executor); // handle this special case separately
+            return;
+        }
+        // expecting exactly one rules list at this point
+        BusinessLogicRulesList rulesList = mRules.get(testName).get(0);
+        rulesList.invokeRules(executor);
+    }
+
+    /**
+     * Handle special case in which multiple rule lists exist for the test name provided.
+     * Execute each rule list in a sandbox and store an exception for each rule list that
+     * triggers failure or skipping for the test.
+     * If all rule lists trigger skipping, rethrow AssumptionViolatedException to report a 'skip'
+     * for the test as a whole.
+     * If one or more rule lists trigger failure, rethrow RuntimeException with a list containing
+     * each failure.
+     */
+    private void applyLogicsFor(String testName, BusinessLogicExecutor executor) {
+        Map<String, RuntimeException> failedMap = new HashMap<>();
+        Map<String, RuntimeException> skippedMap = new HashMap<>();
+        List<BusinessLogicRulesList> rulesLists = mRules.get(testName);
+        for (int index = 0; index < rulesLists.size(); index++) {
+            BusinessLogicRulesList rulesList = rulesLists.get(index);
+            String description = cleanDescription(rulesList.getDescription(), index);
+            try {
+                rulesList.invokeRules(executor);
+            } catch (RuntimeException re) {
+                if (AssumptionViolatedException.class.isInstance(re)) {
+                    skippedMap.put(description, re);
+                    executor.logInfo("Test %s (%s) skipped for reason: %s", testName, description,
+                            re.getMessage());
+                } else {
+                    failedMap.put(description, re);
+                }
             }
         }
+        if (skippedMap.size() == rulesLists.size()) {
+            throwAggregatedException(skippedMap, false);
+        } else if (failedMap.size() > 0) {
+            throwAggregatedException(failedMap, true);
+        } // else this test should be reported as a pure pass
+    }
+
+    /**
+     * Helper to aggregate the messages of many {@link RuntimeException}s, and optionally their
+     * stack traces, before throwing an exception.
+     * @param exceptions a map from description strings to exceptions. The descriptive keySet is
+     * used to differentiate which BusinessLogicRulesList caused which exception
+     * @param failed whether to trigger failure. When false, throws assumption failure instead, and
+     * excludes stack traces from the exception message.
+     */
+    private static void throwAggregatedException(Map<String, RuntimeException> exceptions,
+            boolean failed) {
+        Set<String> keySet = exceptions.keySet();
+        String[] descriptions = keySet.toArray(new String[keySet.size()]);
+        StringBuilder msg = new StringBuilder("");
+        msg.append(String.format("Test %s for cases: ", (failed) ? "failed" : "skipped"));
+        msg.append(String.join(", ", descriptions));
+        msg.append("\nReasons include:");
+        for (String description : descriptions) {
+            RuntimeException re = exceptions.get(description);
+            msg.append(String.format("\nMessage [%s]: %s", description, re.getMessage()));
+            if (failed) {
+                StringWriter sw = new StringWriter();
+                re.printStackTrace(new PrintWriter(sw));
+                msg.append(String.format("\nStack Trace: %s", sw.toString()));
+            }
+        }
+        if (failed) {
+            throw new RuntimeException(msg.toString());
+        } else {
+            throw new AssumptionViolatedException(msg.toString());
+        }
+    }
+
+    /**
+     * Helper method to generate a meaningful description in case the provided description is null
+     * or empty. In this case, returns a string representation of the index provided.
+     */
+    private String cleanDescription(String description, int index) {
+        return (description == null || description.length() == 0)
+                ? Integer.toString(index)
+                : description;
     }
 
     public void setAuthenticationStatus(String authenticationStatus) {
@@ -99,6 +190,43 @@
     }
 
     /**
+     * A list of BusinessLogicRules, wrapped with an optional description to differentiate rule
+     * lists that apply to the same test.
+     */
+    protected static class BusinessLogicRulesList {
+
+        /* Stored description and rules */
+        protected List<BusinessLogicRule> mRulesList;
+        protected String mDescription;
+
+        public BusinessLogicRulesList(List<BusinessLogicRule> rulesList) {
+            mRulesList = rulesList;
+        }
+
+        public BusinessLogicRulesList(List<BusinessLogicRule> rulesList, String description) {
+            mRulesList = rulesList;
+            mDescription = description;
+        }
+
+        public String getDescription() {
+            return mDescription;
+        }
+
+        public List<BusinessLogicRule> getRules() {
+            return mRulesList;
+        }
+
+        public void invokeRules(BusinessLogicExecutor executor) {
+            for (BusinessLogicRule rule : mRulesList) {
+                // Check conditions
+                if (rule.invokeConditions(executor)) {
+                    rule.invokeActions(executor);
+                }
+            }
+        }
+    }
+
+    /**
      * Nested class representing an Business Logic Rule. Stores a collection of conditions
      * and actions for later invokation.
      */
diff --git a/common/util/src/com/android/compatibility/common/util/BusinessLogicExecutor.java b/common/util/src/com/android/compatibility/common/util/BusinessLogicExecutor.java
index 5c42858..4709395 100644
--- a/common/util/src/com/android/compatibility/common/util/BusinessLogicExecutor.java
+++ b/common/util/src/com/android/compatibility/common/util/BusinessLogicExecutor.java
@@ -29,6 +29,8 @@
  */
 public abstract class BusinessLogicExecutor {
 
+    protected static final String LOG_TAG = "BusinessLogicExecutor";
+
     /** String representations of the String class and String[] class */
     protected static final String STRING_CLASS = "java.lang.String";
     protected static final String STRING_ARRAY_CLASS = "[Ljava.lang.String;";
@@ -115,6 +117,13 @@
     }
 
     /**
+     * Log information with whichever logging mechanism is available to the instance. This varies
+     * from host-side to device-side, so implementations are left to subclasses.
+     * See {@link String.format(String, Object...)} for parameter information.
+     */
+    public abstract void logInfo(String format, Object... args);
+
+    /**
      * Get the test object. This method is left abstract, since non-abstract subclasses will set
      * the test object in the constructor.
      * @return the test case instance
diff --git a/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java b/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java
index 4a0087e..a0747bc 100644
--- a/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java
+++ b/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java
@@ -23,6 +23,7 @@
 import com.android.compatibility.common.util.BusinessLogic.BusinessLogicRule;
 import com.android.compatibility.common.util.BusinessLogic.BusinessLogicRuleAction;
 import com.android.compatibility.common.util.BusinessLogic.BusinessLogicRuleCondition;
+import com.android.compatibility.common.util.BusinessLogic.BusinessLogicRulesList;
 
 import java.io.File;
 import java.io.IOException;
@@ -47,6 +48,8 @@
     private static final String RULE_CONDITIONS = "ruleConditions";
     // Name of rule actions array
     private static final String RULE_ACTIONS = "ruleActions";
+    // Description of a rule list object
+    private static final String RULES_LIST_DESCRIPTION = "description";
     // Name of method name string
     private static final String METHOD_NAME = "methodName";
     // Name of method args array of strings
@@ -62,12 +65,12 @@
      */
     public static BusinessLogic createFromFile(File f) {
         // Populate the map from testname to business rules for this new BusinessLogic instance
-        Map<String, List<BusinessLogicRule>> rulesMap = new HashMap<>();
+        Map<String, List<BusinessLogicRulesList>> rulesMap = new HashMap<>();
         BusinessLogic bl = new BusinessLogic();
         try {
             String businessLogicString = readFile(f);
             JSONObject root = new JSONObject(businessLogicString);
-            JSONArray rulesLists = null;
+            JSONArray jsonRulesLists = null;
             if (root.has(AUTHENTICATION_STATUS)){
                 String authStatus = root.getString(AUTHENTICATION_STATUS);
                 bl.setAuthenticationStatus(authStatus);
@@ -77,34 +80,20 @@
                 bl.mConditionalTestsEnabled = enabled;
             }
             try {
-                rulesLists = root.getJSONArray(BUSINESS_LOGIC_RULES_LISTS);
+                jsonRulesLists = root.getJSONArray(BUSINESS_LOGIC_RULES_LISTS);
             } catch (JSONException e) {
                 bl.mRules = rulesMap;
                 return bl; // no rules defined for this suite, leave internal map empty
             }
-            for (int i = 0; i < rulesLists.length(); i++) {
-                JSONObject rulesList = rulesLists.getJSONObject(i);
-                String testName = rulesList.getString(TEST_NAME);
-                List<BusinessLogicRule> rules = new ArrayList<>();
-                JSONArray rulesJSONArray = null;
-                try {
-                    rulesJSONArray = rulesList.getJSONArray(BUSINESS_LOGIC_RULES);
-                } catch (JSONException e) {
-                    // no rules defined for this test case
-                    rulesMap.put(testName, rules); // add empty rule list to internal map
-                    continue; // advance to next test case
+            for (int i = 0; i < jsonRulesLists.length(); i++) {
+                JSONObject jsonRulesList = jsonRulesLists.getJSONObject(i);
+                String testName = jsonRulesList.getString(TEST_NAME);
+                List<BusinessLogicRulesList> testRulesLists = rulesMap.get(testName);
+                if (testRulesLists == null) {
+                    testRulesLists = new ArrayList<>();
                 }
-                for (int j = 0; j < rulesJSONArray.length(); j++) {
-                    JSONObject ruleJSONObject = rulesJSONArray.getJSONObject(j);
-                    // Build conditions list
-                    List<BusinessLogicRuleCondition> ruleConditions =
-                            extractRuleConditionList(ruleJSONObject);
-                    // Build actions list
-                    List<BusinessLogicRuleAction> ruleActions =
-                            extractRuleActionList(ruleJSONObject);
-                    rules.add(new BusinessLogicRule(ruleConditions, ruleActions));
-                }
-                rulesMap.put(testName, rules);
+                testRulesLists.add(extractRulesList(jsonRulesList));
+                rulesMap.put(testName, testRulesLists);
             }
         } catch (IOException | JSONException e) {
             throw new RuntimeException("Business Logic failed", e);
@@ -114,6 +103,37 @@
         return bl;
     }
 
+    /* Extract a BusinessLogicRulesList from the representative JSON object */
+    private static BusinessLogicRulesList extractRulesList(JSONObject rulesListJSONObject)
+            throws JSONException {
+        // First, parse the description for this rule list object, if one exists
+        String description = null;
+        try {
+            description = rulesListJSONObject.getString(RULES_LIST_DESCRIPTION);
+        } catch (JSONException e) { /* no description set, leave null */}
+
+        // Next, get the list of rules
+        List<BusinessLogicRule> rules = new ArrayList<>();
+        JSONArray rulesJSONArray = null;
+        try {
+            rulesJSONArray = rulesListJSONObject.getJSONArray(BUSINESS_LOGIC_RULES);
+        } catch (JSONException e) {
+            // no rules defined for this test case, return new, rule-less BusinessLogicRulesList
+            return new BusinessLogicRulesList(rules, description);
+        }
+        for (int j = 0; j < rulesJSONArray.length(); j++) {
+            JSONObject ruleJSONObject = rulesJSONArray.getJSONObject(j);
+            // Build conditions list
+            List<BusinessLogicRuleCondition> ruleConditions =
+                    extractRuleConditionList(ruleJSONObject);
+            // Build actions list
+            List<BusinessLogicRuleAction> ruleActions =
+                    extractRuleActionList(ruleJSONObject);
+            rules.add(new BusinessLogicRule(ruleConditions, ruleActions));
+        }
+        return new BusinessLogicRulesList(rules, description);
+    }
+
     /* Extract all BusinessLogicRuleConditions from a JSON business logic rule */
     private static List<BusinessLogicRuleCondition> extractRuleConditionList(
             JSONObject ruleJSONObject) throws JSONException {
diff --git a/common/util/tests/src/com/android/compatibility/common/util/BusinessLogicTest.java b/common/util/tests/src/com/android/compatibility/common/util/BusinessLogicTest.java
index 99b5239..23e9da3 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/BusinessLogicTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/BusinessLogicTest.java
@@ -46,6 +46,7 @@
             "  \"businessLogicRulesLists\": [\n" +
             "    {\n" +
             "      \"testName\": \"testCaseName1\",\n" +
+            "      \"description\": \"first test\",\n" +
             "      \"businessLogicRules\": [\n" +
             "        {\n" +
             "          \"ruleConditions\": [\n" +
@@ -132,10 +133,11 @@
         try {
             BusinessLogic bl = BusinessLogicFactory.createFromFile(file);
             assertEquals("Wrong number of business logic rule lists", 3, bl.mRules.size());
-
-            List<BusinessLogicRule> ruleList1 = bl.mRules.get("testCaseName1");
-            assertEquals("Wrong number of rules in first rule list", 1, ruleList1.size());
-            BusinessLogicRule rule1 = ruleList1.get(0);
+            String description = bl.mRules.get("testCaseName1").get(0).getDescription();
+            assertEquals("Wrong or missing rule list description", "first test", description);
+            List<BusinessLogicRule> rulesList1 = bl.mRules.get("testCaseName1").get(0).getRules();
+            assertEquals("Wrong number of rules in first rule list", 1, rulesList1.size());
+            BusinessLogicRule rule1 = rulesList1.get(0);
             List<BusinessLogicRuleCondition> rule1Conditions = rule1.mConditions;
             assertEquals("Wrong number of conditions", 1, rule1Conditions.size());
             BusinessLogicRuleCondition rule1Condition = rule1Conditions.get(0);
@@ -159,9 +161,9 @@
             assertEquals("Wrong arg for business logic rule action", "arg2",
                     rule1Action.mMethodArgs.get(1));
 
-            List<BusinessLogicRule> ruleList2 = bl.mRules.get("testCaseName2");
-            assertEquals("Wrong number of rules in second rule list", 2, ruleList2.size());
-            BusinessLogicRule rule2 = ruleList2.get(0);
+            List<BusinessLogicRule> rulesList2 = bl.mRules.get("testCaseName2").get(0).getRules();
+            assertEquals("Wrong number of rules in second rule list", 2, rulesList2.size());
+            BusinessLogicRule rule2 = rulesList2.get(0);
             List<BusinessLogicRuleCondition> rule2Conditions = rule2.mConditions;
             assertEquals("Wrong number of conditions", 1, rule2Conditions.size());
             BusinessLogicRuleCondition rule2Condition = rule2Conditions.get(0);
@@ -184,7 +186,7 @@
                     rule2Action.mMethodArgs.get(0));
             assertEquals("Wrong arg for business logic rule action", "arg2",
                     rule2Action.mMethodArgs.get(1));
-            BusinessLogicRule rule3 = ruleList2.get(1);
+            BusinessLogicRule rule3 = rulesList2.get(1);
             List<BusinessLogicRuleCondition> rule3Conditions = rule3.mConditions;
             assertEquals("Wrong number of conditions", 2, rule3Conditions.size());
             BusinessLogicRuleCondition rule3Condition1 = rule3Conditions.get(0);
@@ -222,8 +224,8 @@
             assertEquals("Wrong arg string count for business logic rule action", 0,
                     rule3Action2.mMethodArgs.size());
 
-            List<BusinessLogicRule> ruleList3 = bl.mRules.get("testCaseName3");
-            assertEquals("Wrong number of rules in third rule list", 0, ruleList3.size());
+            List<BusinessLogicRule> rulesList3 = bl.mRules.get("testCaseName3").get(0).getRules();
+            assertEquals("Wrong number of rules in third rule list", 0, rulesList3.size());
         } finally {
             FileUtil.deleteFile(file);
         }
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
index 207e3a6..466dabf 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
@@ -335,7 +335,10 @@
         if (!supportedHardwareForScopedDirectoryAccess()) return;
 
         final StorageVolume volume = getPrimaryVolume();
-        final String dir = DIRECTORY_PICTURES;
+        // TODO: ideally it should test all directories, but that would be too slow, and would
+        // require a more sophisticated way to get the toggle object (for example, it might require
+        // scrolling on devices with small screens)
+        final String dir = DIRECTORY_DOCUMENTS;
 
         // First, triggers it.
         deniesOnceForAllTest(volume, dir);
@@ -372,10 +375,13 @@
         if (!supportedHardwareForScopedDirectoryAccess()) return;
 
         final StorageVolume volume = getPrimaryVolume();
-        final String dir = DIRECTORY_PICTURES;
+        // TODO: ideally it should test all directories, but that would be too slow, and would
+        // require a more sophisticated way to get the toggle object (for example, it might require
+        // scrolling on devices with small screens)
+        final String dir = DIRECTORY_DOCUMENTS;
 
         // First, grants it
-        userAcceptsTest(volume, DIRECTORY_PICTURES);
+        userAcceptsTest(volume, dir);
 
         // Then revoke it using settings.
 
diff --git a/hostsidetests/seccomp/app/assets/syscalls.json b/hostsidetests/seccomp/app/assets/syscalls.json
deleted file mode 100644
index 527405f..0000000
--- a/hostsidetests/seccomp/app/assets/syscalls.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
-  "arm": {
-    "add_key": 309,
-    "inotify_init": 316,
-    "keyctl": 311,
-    "openat": 322,
-    "swapoff": 115,
-    "swapon": 87,
-    "syncfs": 373
-  },
-  "arm64": {
-    "add_key": 217,
-    "keyctl": 219,
-    "openat": 56,
-    "swapoff": 225,
-    "swapon": 224,
-    "syncfs": 267
-  },
-  "mips": {
-    "add_key": 4280,
-    "inotify_init": 4284,
-    "keyctl": 4282,
-    "openat": 4288,
-    "swapoff": 4115,
-    "swapon": 4087,
-    "syncfs": 4342
-  },
-  "mips64": {
-    "add_key": 5239,
-    "keyctl": 5241,
-    "openat": 5247,
-    "swapoff": 5163,
-    "swapon": 5162,
-    "syncfs": 5301
-  },
-  "x86": {
-    "add_key": 286,
-    "inotify_init": 291,
-    "keyctl": 288,
-    "openat": 295,
-    "swapoff": 115,
-    "swapon": 87,
-    "syncfs": 344
-  },
-  "x86_64": {
-    "add_key": 248,
-    "keyctl": 250,
-    "openat": 257,
-    "swapoff": 168,
-    "swapon": 167,
-    "syncfs": 306
-  }
-}
diff --git a/hostsidetests/seccomp/app/assets/syscalls_allowed.json b/hostsidetests/seccomp/app/assets/syscalls_allowed.json
new file mode 100644
index 0000000..03ce72b
--- /dev/null
+++ b/hostsidetests/seccomp/app/assets/syscalls_allowed.json
@@ -0,0 +1,24 @@
+# DO NOT MODIFY.  CHANGE gen_blacklist.py INSTEAD.
+{
+  "arm": {
+    "inotify_init": 316,
+    "openat": 322,
+    "syncfs": 373
+  },
+  "arm64": {
+    "openat": 56,
+    "syncfs": 267
+  },
+  "mips": {
+    "openat": 4288
+  },
+  "mips64": {
+    "openat": 5247
+  },
+  "x86": {
+    "openat": 295
+  },
+  "x86_64": {
+    "openat": 257
+  }
+}
\ No newline at end of file
diff --git a/hostsidetests/seccomp/app/assets/syscalls_blocked.json b/hostsidetests/seccomp/app/assets/syscalls_blocked.json
new file mode 100644
index 0000000..441c8da
--- /dev/null
+++ b/hostsidetests/seccomp/app/assets/syscalls_blocked.json
@@ -0,0 +1,123 @@
+# DO NOT MODIFY.  CHANGE gen_blacklist.py INSTEAD.
+{
+  "arm": {
+    "acct": 51,
+    "add_key": 309,
+    "adjtimex": 124,
+    "chroot": 61,
+    "clock_adjtime": 372,
+    "clock_settime": 262,
+    "delete_module": 129,
+    "init_module": 128,
+    "keyctl": 311,
+    "mount": 21,
+    "reboot": 88,
+    "setdomainname": 121,
+    "sethostname": 74,
+    "settimeofday": 79,
+    "swapoff": 115,
+    "swapon": 87,
+    "syslog": 103,
+    "umount2": 52
+  },
+  "arm64": {
+    "acct": 89,
+    "add_key": 217,
+    "adjtimex": 171,
+    "chroot": 51,
+    "clock_adjtime": 266,
+    "clock_settime": 112,
+    "delete_module": 106,
+    "init_module": 105,
+    "keyctl": 219,
+    "mount": 40,
+    "reboot": 142,
+    "setdomainname": 162,
+    "sethostname": 161,
+    "settimeofday": 170,
+    "swapoff": 225,
+    "swapon": 224,
+    "syslog": 116,
+    "umount2": 39
+  },
+  "mips": {
+    "acct": 4051,
+    "add_key": 4280,
+    "adjtimex": 4124,
+    "chroot": 4061,
+    "clock_adjtime": 4341,
+    "clock_settime": 4262,
+    "delete_module": 4129,
+    "init_module": 4128,
+    "keyctl": 4282,
+    "mount": 4021,
+    "reboot": 4088,
+    "setdomainname": 4121,
+    "sethostname": 4074,
+    "settimeofday": 4079,
+    "swapoff": 4115,
+    "swapon": 4087,
+    "syslog": 4103,
+    "umount2": 4052
+  },
+  "mips64": {
+    "acct": 5158,
+    "add_key": 5239,
+    "adjtimex": 5154,
+    "chroot": 5156,
+    "clock_adjtime": 5300,
+    "clock_settime": 5221,
+    "delete_module": 5169,
+    "init_module": 5168,
+    "keyctl": 5241,
+    "mount": 5160,
+    "reboot": 5164,
+    "setdomainname": 5166,
+    "sethostname": 5165,
+    "settimeofday": 5159,
+    "swapoff": 5163,
+    "swapon": 5162,
+    "syslog": 5101,
+    "umount2": 5161
+  },
+  "x86": {
+    "acct": 51,
+    "add_key": 286,
+    "adjtimex": 124,
+    "chroot": 61,
+    "clock_adjtime": 343,
+    "clock_settime": 264,
+    "delete_module": 129,
+    "init_module": 128,
+    "keyctl": 288,
+    "mount": 21,
+    "reboot": 88,
+    "setdomainname": 121,
+    "sethostname": 74,
+    "settimeofday": 79,
+    "swapoff": 115,
+    "swapon": 87,
+    "syslog": 103,
+    "umount2": 52
+  },
+  "x86_64": {
+    "acct": 163,
+    "add_key": 248,
+    "adjtimex": 159,
+    "chroot": 161,
+    "clock_adjtime": 305,
+    "clock_settime": 227,
+    "delete_module": 176,
+    "init_module": 175,
+    "keyctl": 250,
+    "mount": 165,
+    "reboot": 169,
+    "setdomainname": 171,
+    "sethostname": 170,
+    "settimeofday": 164,
+    "swapoff": 168,
+    "swapon": 167,
+    "syslog": 103,
+    "umount2": 166
+  }
+}
\ No newline at end of file
diff --git a/hostsidetests/seccomp/app/gen_blacklist.py b/hostsidetests/seccomp/app/gen_blacklist.py
index a104394..cf36d11 100755
--- a/hostsidetests/seccomp/app/gen_blacklist.py
+++ b/hostsidetests/seccomp/app/gen_blacklist.py
@@ -3,10 +3,15 @@
 # This script generates syscall name to number mapping for supported
 # architectures.  To update the output, runs:
 #
-#  $ app/gen_blacklist.py > app/assets/syscalls.json
+#  $ app/gen_blacklist.py --allowed app/assets/syscalls_allowed.json \
+#      --blocked app/assets/syscalls_blocked.json
+#
+# Note that these are just syscalls that explicitly allowed and blocked in CTS
+# currently.
 #
 # TODO: Consider generating it in Android.mk/bp.
 
+import argparse
 import glob
 import json
 import os
@@ -14,14 +19,39 @@
 
 _SUPPORTED_ARCHS = ['arm', 'arm64', 'x86', 'x86_64', 'mips', 'mips64']
 
-_INTERESTED_SYSCALLS = {
-    'swapon': 'all',
-    'swapoff': 'all',
-    'add_key': 'all',
-    'keyctl': 'all',
+# Syscalls that are currently explicitly allowed in CTS
+_SYSCALLS_ALLOWED_IN_CTS = {
     'openat': 'all',
-    'syncfs': 'all',
-    'inotify_init': 'arm,x86,mips',
+
+    # b/35034743 - do not remove test without reading bug.
+    'syncfs': 'arm64',
+
+    # b/35906875 - do not remove test without reading bug
+    'inotify_init': 'arm',
+}
+
+# Syscalls that are currently explicitly blocked in CTS
+_SYSCALLS_BLOCKED_IN_CTS = {
+    'acct': 'all',
+    'add_key': 'all',
+    'adjtimex': 'all',
+    'chroot': 'all',
+    'clock_adjtime': 'all',
+    'clock_settime': 'all',
+    'delete_module': 'all',
+    'init_module': 'all',
+    'keyctl': 'all',
+    'mount': 'all',
+    'reboot': 'all',
+    'setdomainname': 'all',
+    'sethostname': 'all',
+    'settimeofday': 'all',
+    'swapoff': 'all',
+    'swapoff': 'all',
+    'swapon': 'all',
+    'swapon': 'all',
+    'syslog': 'all',
+    'umount2': 'all',
 }
 
 def create_syscall_name_to_number_map(arch, names):
@@ -108,17 +138,38 @@
       return clang_exe
   raise FileNotFoundError('Cannot locate clang executable')
 
-def main():
-  dictionary = {}
-  for arch in _SUPPORTED_ARCHS:
-    syscall_names = []
-    for syscall in _INTERESTED_SYSCALLS.keys():
-      if (arch in _INTERESTED_SYSCALLS[syscall] or
-          'all' == _INTERESTED_SYSCALLS[syscall]):
-        syscall_names.append(syscall)
-    dictionary[arch] = create_syscall_name_to_number_map(arch, syscall_names)
+def collect_syscall_names_for_arch(syscall_map, arch):
+  syscall_names = []
+  for syscall in syscall_map.keys():
+    if (arch in syscall_map[syscall] or
+        'all' == syscall_map[syscall]):
+      syscall_names.append(syscall)
+  return syscall_names
 
-  print(json.dumps(dictionary, sort_keys=True, indent=2))
+def main():
+  parser = argparse.ArgumentParser('syscall name to number generator')
+  parser.add_argument('--allowed', metavar='path/to/json', type=str)
+  parser.add_argument('--blocked', metavar='path/to/json', type=str)
+  args = parser.parse_args()
+
+  allowed = {}
+  blocked = {}
+  for arch in _SUPPORTED_ARCHS:
+    blocked[arch] = create_syscall_name_to_number_map(
+        arch,
+        collect_syscall_names_for_arch(_SYSCALLS_BLOCKED_IN_CTS, arch))
+    allowed[arch] = create_syscall_name_to_number_map(
+        arch,
+        collect_syscall_names_for_arch(_SYSCALLS_ALLOWED_IN_CTS, arch))
+
+  msg_do_not_modify = '# DO NOT MODIFY.  CHANGE gen_blacklist.py INSTEAD.'
+  with open(args.allowed, 'w') as f:
+    print(msg_do_not_modify, file=f)
+    json.dump(allowed, f, sort_keys=True, indent=2)
+
+  with open(args.blocked, 'w') as f:
+    print(msg_do_not_modify, file=f)
+    json.dump(blocked, f, sort_keys=True, indent=2)
 
 if __name__ == '__main__':
   main()
diff --git a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
index 0f85146..724d235 100644
--- a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
+++ b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
@@ -18,6 +18,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Iterator;
 
 import android.content.Context;
 import android.content.res.AssetManager;
@@ -43,49 +44,41 @@
         System.loadLibrary("ctsseccomp_jni");
     }
 
-    private JSONObject mSyscallMap;
+    private JSONObject mAllowedSyscallMap;
+    private JSONObject mBlockedSyscallMap;
 
     @Before
     public void initializeSyscallMap() throws IOException, JSONException {
         final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
         AssetManager manager = context.getAssets();
-        String json = null;
-        try (InputStream is = manager.open("syscalls.json")) {
-            json = readInputStreamFully(is);
+        try (InputStream is = manager.open("syscalls_allowed.json")) {
+            mAllowedSyscallMap = new JSONObject(readInputStreamFully(is));
         }
-        mSyscallMap = new JSONObject(json);
+        try (InputStream is = manager.open("syscalls_blocked.json")) {
+            mBlockedSyscallMap = new JSONObject(readInputStreamFully(is));
+        }
+    }
+
+    @Test
+    public void testCTSSyscallAllowed() throws JSONException {
+        JSONObject map = mAllowedSyscallMap.getJSONObject(getCurrentArch());
+        Iterator<String> iter = map.keys();
+        while (iter.hasNext()) {
+            String syscallName = iter.next();
+            testAllowed(map.getInt(syscallName));
+        }
     }
 
     @Test
     public void testCTSSyscallBlocked() throws JSONException {
-        String arch = getCurrentArch();
-
-        testBlocked(getSyscallNumber(arch, "add_key"));
-        testBlocked(getSyscallNumber(arch, "keyctl"));
-        testAllowed(getSyscallNumber(arch, "openat"));
-
-        if (CpuFeatures.isArm64Cpu()) {
-            // b/35034743 - do not remove test without reading bug.
-            testAllowed(getSyscallNumber(arch, "syncfs"));
-        } else if (CpuFeatures.isArmCpu()) {
-            // b/35906875 - do not remove test without reading bug
-            testAllowed(getSyscallNumber(arch, "inotify_init"));
+        JSONObject map = mBlockedSyscallMap.getJSONObject(getCurrentArch());
+        Iterator<String> iter = map.keys();
+        while (iter.hasNext()) {
+            String syscallName = iter.next();
+            testBlocked(map.getInt(syscallName));
         }
     }
 
-    @Test
-    public void testCTSSwapOnOffBlocked() throws JSONException {
-        String arch = getCurrentArch();
-
-        testBlocked(getSyscallNumber(arch, "swapon"));
-        testBlocked(getSyscallNumber(arch, "swapoff"));
-    }
-
-    private int getSyscallNumber(String arch, String name) throws JSONException {
-        JSONObject perArchMap = mSyscallMap.getJSONObject(arch);
-        return perArchMap.getInt(name);
-    }
-
     private static String getCurrentArch() {
         if (CpuFeatures.isArm64Cpu()) {
             return "arm64";
diff --git a/hostsidetests/seccomp/src/android/seccomp/cts/SeccompHostJUnit4DeviceTest.java b/hostsidetests/seccomp/src/android/seccomp/cts/SeccompHostJUnit4DeviceTest.java
index 63258e3..2a7242b 100644
--- a/hostsidetests/seccomp/src/android/seccomp/cts/SeccompHostJUnit4DeviceTest.java
+++ b/hostsidetests/seccomp/src/android/seccomp/cts/SeccompHostJUnit4DeviceTest.java
@@ -40,7 +40,7 @@
     private static final String TEST_APP = "CtsSeccompDeviceApp.apk";
 
     private static final String TEST_CTS_SYSCALL_BLOCKED = "testCTSSyscallBlocked";
-    private static final String TEST_CTS_SWAP_ON_OFF_BLOCKED = "testCTSSwapOnOffBlocked";
+    private static final String TEST_CTS_SYSCALL_ALLOWED = "testCTSSyscallAllowed";
 
     @Before
     public void setUp() throws Exception {
@@ -53,8 +53,8 @@
     }
 
     @Test
-    public void testCTSSwapOnOffBlocked() throws Exception {
-        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, TEST_CTS_SWAP_ON_OFF_BLOCKED));
+    public void testCTSSyscallAllowed() throws Exception {
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, TEST_CTS_SYSCALL_ALLOWED));
     }
 
     @After
diff --git a/hostsidetests/security/AndroidTest.xml b/hostsidetests/security/AndroidTest.xml
index 52c47cc..73d906d 100755
--- a/hostsidetests/security/AndroidTest.xml
+++ b/hostsidetests/security/AndroidTest.xml
@@ -102,6 +102,28 @@
         <!-- Bulletin 2017-11 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
 
+        <!--__________________-->
+        <!-- Bulletin 2017-12 -->
+        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+        <!--__________________-->
+        <!-- Bulletin 2018-01 -->
+        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+        <!--__________________-->
+        <!-- Bulletin 2018-02 -->
+        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+
+        <!--__________________-->
+        <!-- Bulletin 2018-03 -->
+        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2017-13253->/data/local/tmp/CVE-2017-13253" />
+
+
+
+
+
+
         <option name="append-bitness" value="true" />
     </target_preparer>
 
diff --git a/hostsidetests/security/securityPatch/CVE-2017-13253/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-13253/Android.mk
new file mode 100644
index 0000000..afbb0fe
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-13253/Android.mk
@@ -0,0 +1,34 @@
+# 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-2017-13253
+LOCAL_SRC_FILES := poc.cpp
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+
+LOCAL_SHARED_LIBRARIES := libmedia libutils libbinder libmediadrm
+
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS = -Wall -Werror -Wno-unused-parameter -Wno-unused-variable
+
+include $(BUILD_CTS_EXECUTABLE)
\ No newline at end of file
diff --git a/hostsidetests/security/securityPatch/CVE-2017-13253/poc.cpp b/hostsidetests/security/securityPatch/CVE-2017-13253/poc.cpp
new file mode 100644
index 0000000..4b19ae2f
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-13253/poc.cpp
@@ -0,0 +1,84 @@
+/**
+ * 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.
+ */
+#include <binder/IMemory.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <media/ICrypto.h>
+#include <media/IMediaDrmService.h>
+#include <media/hardware/CryptoAPI.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <utils/StrongPointer.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+using namespace android;
+
+int main()
+{
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<IBinder> binder = sm->getService(String16("media.drm"));
+  sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
+  if (service == NULL) {
+    printf("Failed to retrieve 'media.drm' service.\n");
+    return 1;
+  }
+  sp<ICrypto> crypto = service->makeCrypto();
+  if (crypto == NULL) {
+    printf("makeCrypto failed.\n");
+    return 1;
+  }
+
+  const uint8_t clearkey_uuid[16] = {
+    0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,
+    0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B
+  };
+  if (crypto->createPlugin(clearkey_uuid, NULL, 0) != OK) {
+    printf("createPlugin failed.\n");
+    return 1;
+  }
+
+  sp<MemoryHeapBase> heap = new MemoryHeapBase(0x2000);
+  memset(heap->getBase(), 'A', 0x2000);
+  sp<MemoryBase> sourceMemory = new MemoryBase(heap, 0, 0x2000);
+  sp<MemoryBase> destMemory = new MemoryBase(heap, 0x1fff, 1);
+  int heapSeqNum = crypto->setHeap(heap);
+  if (heapSeqNum < 0) {
+    printf("setHeap failed.\n");
+    return 1;
+  }
+
+  CryptoPlugin::Pattern pattern = { .mEncryptBlocks = 0, .mSkipBlocks = 1 };
+  ICrypto::SourceBuffer source = { .mSharedMemory = sourceMemory,
+    .mHeapSeqNum = heapSeqNum };
+  CryptoPlugin::SubSample subSamples[1] = { { .mNumBytesOfClearData = 0x2000,
+      .mNumBytesOfEncryptedData = 0 } };
+  ICrypto::DestinationBuffer destination = {
+    .mType = ICrypto::kDestinationTypeSharedMemory, .mHandle = NULL, .mSharedMemory = destMemory
+  };
+
+  int val = crypto->decrypt(NULL, NULL,
+      CryptoPlugin::kMode_Unencrypted, pattern, source, 0, subSamples, 1,
+      destination, NULL);
+
+  if (val != BAD_VALUE) {
+    printf("OVERFLOW DETECTED\n");
+  }
+
+  return 0;
+}
diff --git a/hostsidetests/security/src/android/security/cts/Poc18_03.java b/hostsidetests/security/src/android/security/cts/Poc18_03.java
new file mode 100644
index 0000000..6398164
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/Poc18_03.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2017 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.platform.test.annotations.SecurityTest;
+
+public class Poc18_03 extends SecurityTestCase {
+
+  /**
+   *  b/71389378
+   */
+  @SecurityTest
+  public void testPocCVE_2017_13253() throws Exception {
+    String output = AdbUtils.runPoc("CVE-2017-13253", getDevice());
+    assertNotMatchesMultiLine(".*OVERFLOW DETECTED.*",output);
+  }
+}
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 72b1b9c..8428758 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -147,8 +147,13 @@
         if (mDevice.doesFileExist("/system/etc/selinux/plat_file_contexts")) {
             devicePlatFcFile = getDeviceFile(mDevice, cachedDevicePlatFcFiles,
                     "/system/etc/selinux/plat_file_contexts", "plat_file_contexts");
-            deviceNonplatFcFile = getDeviceFile(mDevice, cachedDeviceNonplatFcFiles,
-                    "/vendor/etc/selinux/nonplat_file_contexts", "nonplat_file_contexts");
+            if (mDevice.doesFileExist("/vendor/etc/selinux/nonplat_file_contexts")){
+                deviceNonplatFcFile = getDeviceFile(mDevice, cachedDeviceNonplatFcFiles,
+                        "/vendor/etc/selinux/nonplat_file_contexts", "nonplat_file_contexts");
+            } else {
+                deviceNonplatFcFile = getDeviceFile(mDevice, cachedDeviceNonplatFcFiles,
+                        "/vendor/etc/selinux/vendor_file_contexts", "vendor_file_contexts");
+            }
         } else {
             devicePlatFcFile = getDeviceFile(mDevice, cachedDevicePlatFcFiles,
                     "/plat_file_contexts", "plat_file_contexts");
@@ -167,6 +172,9 @@
     private static File getDeviceFile(ITestDevice device,
             Map<ITestDevice, File> cache, String deviceFilePath,
             String tmpFileName) throws Exception {
+        if (!device.doesFileExist(deviceFilePath)){
+            throw new Exception();
+        }
         File file;
         synchronized (cache) {
             file = cache.get(device);
@@ -729,6 +737,24 @@
     }
 
     /**
+     * Tests that all types in /proc have the proc_type attribute.
+     *
+     * @throws Exception
+     */
+    public void testProcTypeViolators() throws Exception {
+        assertSepolicyTests("TestProcTypeViolations", "/sepolicy_tests");
+    }
+
+    /**
+     * Tests that all types in /sys have the sysfs_type attribute.
+     *
+     * @throws Exception
+     */
+    public void testSysfsTypeViolators() throws Exception {
+        assertSepolicyTests("TestSysfsTypeViolations", "/sepolicy_tests");
+    }
+
+    /**
      * Tests that all types on /vendor have the vendor_file_type attribute.
      *
      * @throws Exception
diff --git a/hostsidetests/statsd/src/android/cts/statsd/alarm/AlarmTests.java b/hostsidetests/statsd/src/android/cts/statsd/alarm/AlarmTests.java
new file mode 100644
index 0000000..38c35d0
--- /dev/null
+++ b/hostsidetests/statsd/src/android/cts/statsd/alarm/AlarmTests.java
@@ -0,0 +1,79 @@
+/*
+ * 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.cts.statsd.alarm;
+
+import android.cts.statsd.atom.AtomTestCase;
+
+import com.android.internal.os.StatsdConfigProto;
+import com.android.internal.os.StatsdConfigProto.Alarm;
+import com.android.internal.os.StatsdConfigProto.IncidentdDetails;
+import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.internal.os.StatsdConfigProto.Subscription;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import java.util.List;
+
+/**
+ * Statsd Anomaly Detection tests.
+ */
+public class AlarmTests extends AtomTestCase {
+
+    private static final String TAG = "Statsd.AnomalyDetectionTests";
+
+    private static final boolean INCIDENTD_TESTS_ENABLED = true;
+
+    // Config constants
+    private static final int ALARM_ID = 11;
+    private static final int SUBSCRIPTION_ID_INCIDENTD = 41;
+    private static final int INCIDENTD_SECTION = -1;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        if (!INCIDENTD_TESTS_ENABLED) {
+            CLog.w(TAG, TAG + " alarm tests are disabled by a flag. Change flag to true to run");
+        }
+    }
+
+    public void testAlarm() throws Exception {
+        StatsdConfig.Builder config = getBaseConfig();
+        turnScreenOn();
+        uploadConfig(config);
+
+        String markTime = getCurrentLogcatDate();
+        Thread.sleep(9_000);
+
+        if (INCIDENTD_TESTS_ENABLED) assertTrue("No incident", didIncidentdFireSince(markTime));
+    }
+
+
+    private final StatsdConfig.Builder getBaseConfig() throws Exception {
+        return StatsdConfig.newBuilder().setId(CONFIG_ID)
+                .addAlarm(Alarm.newBuilder()
+                        .setId(ALARM_ID)
+                        .setOffsetMillis(2)
+                        .setPeriodMillis(5_000) // every 5 seconds.
+                )
+                .addSubscription(Subscription.newBuilder()
+                        .setId(SUBSCRIPTION_ID_INCIDENTD)
+                        .setRuleType(Subscription.RuleType.ALARM)
+                        .setRuleId(ALARM_ID)
+                        .setIncidentdDetails(IncidentdDetails.newBuilder()
+                                .addSection(INCIDENTD_SECTION))
+                )
+                .addAllowedLogSource("AID_SYSTEM");
+    }
+}
diff --git a/hostsidetests/theme/assets/26/213dpi.zip b/hostsidetests/theme/assets/26/213dpi.zip
new file mode 100755
index 0000000..38531ba
--- /dev/null
+++ b/hostsidetests/theme/assets/26/213dpi.zip
Binary files differ
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
index 75c3563..509092f 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
@@ -32,21 +32,6 @@
  */
 @Presubmit
 public class AccessibilityEventTest extends TestCase {
-
-    /** The number of properties of the {@link AccessibilityEvent} class. */
-    private static final int NON_STATIC_FIELD_COUNT = 32;
-
-    /**
-     * Test that no new fields have been added without updating the
-     * marshaling tests.
-     */
-    @SmallTest
-    public void testNoNewFieldsAddedWithoutUpdadingMarshallTests() {
-        // no new fields, so we are testing marshaling of all such
-        AccessibilityRecordTest.assertNoNewNonStaticFieldsAdded(AccessibilityEvent.class,
-                NON_STATIC_FIELD_COUNT);
-    }
-
     /**
      * Tests whether accessibility events are correctly written and
      * read from a parcel (version 1).
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index 95d8f2d..224d860 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -37,21 +37,8 @@
 @Presubmit
 public class AccessibilityNodeInfoTest extends AndroidTestCase {
 
-    /** The number of properties of the {@link AccessibilityNodeInfo} class that are marshalled. */
-    private static final int NUM_MARSHALLED_PROPERTIES = 35;
-
-    /**
-     * The number of properties that are purposely not marshalled
-     * mOriginalText - Used when resolving clickable spans; intentionally not parceled
-     */
-    private static final int NUM_NONMARSHALLED_PROPERTIES = 1;
-
     @SmallTest
     public void testMarshaling() throws Exception {
-        // no new fields, so we are testing marshaling of all such
-        AccessibilityRecordTest.assertNoNewNonStaticFieldsAdded(AccessibilityNodeInfo.class,
-                NUM_MARSHALLED_PROPERTIES + NUM_NONMARSHALLED_PROPERTIES);
-
         // fully populate the node info to marshal
         AccessibilityNodeInfo sentInfo = AccessibilityNodeInfo.obtain(new View(getContext()));
         fullyPopulateAccessibilityNodeInfo(sentInfo);
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
index a12ccce..72bb4e0 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
@@ -35,21 +35,6 @@
  */
 @Presubmit
 public class AccessibilityRecordTest extends AndroidTestCase {
-
-    /** The number of properties of the {@link AccessibilityEvent} class. */
-    private static final int NON_STATIC_FIELD_COUNT = 24;
-
-    /**
-     * Test that no new fields have been added without updating the
-     * marshaling tests. Note that the marshaling tests are in
-     * AccessibilityEventTests since it is a super class that is
-     * responsible for marshaling and unmarshaling.
-     */
-    @SmallTest
-    public void testNoNewFieldsAddedWithoutUpdadingMarshallTests() {
-        assertNoNewNonStaticFieldsAdded(AccessibilityRecord.class, NON_STATIC_FIELD_COUNT);
-    }
-
     /**
      * Tests the cloning obtain method.
      */
@@ -198,24 +183,4 @@
                     receivedTextIterator.next().toString());
         }
     }
-
-    /**
-     * Asserts that no new fields have been added, so we are testing marshaling
-     * of all such.
-     */
-    static void assertNoNewNonStaticFieldsAdded(Class<?> clazz, int expectedCount) {
-        int nonStaticFieldCount = 0;
-
-        while (clazz != Object.class) {
-            for (Field field : clazz.getDeclaredFields()) {
-                if ((field.getModifiers() & Modifier.STATIC) == 0) {
-                    nonStaticFieldCount++;
-                }
-            }
-            clazz = clazz.getSuperclass();
-        }
-
-        String message = "New fields have been added, so add code to test marshaling them.";
-        assertEquals(message, expectedCount, nonStaticFieldCount);
-    }
 }
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index 6c77471..c827364 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -34,6 +34,9 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT;
 
+import static org.hamcrest.Matchers.lessThan;
+import static org.junit.Assert.assertThat;
+
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.cts.activities.AccessibilityWindowQueryActivity;
@@ -52,9 +55,10 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityWindowInfo;
-
 import android.widget.Button;
-import android.accessibilityservice.cts.R;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -63,6 +67,9 @@
 import java.util.List;
 import java.util.Queue;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
 /**
  * Test cases for testing the accessibility APIs for querying of the screen content.
@@ -259,7 +266,6 @@
 
     @MediumTest
     public void testSingleAccessibilityFocusAcrossWindows() throws Exception {
-        setAccessInteractiveWindowsFlag();
         try {
             // Add two more windows.
             final View views[];
@@ -573,6 +579,27 @@
         assertTrue(numPictureInPictureWindows >= 1);
     }
 
+    public void testGetWindows_resultIsSortedByLayerDescending() throws TimeoutException {
+        addTwoAppPanelWindows();
+        List<AccessibilityWindowInfo> windows = getInstrumentation().getUiAutomation().getWindows();
+
+        AccessibilityWindowInfo windowAddedFirst = findWindow(windows, R.string.button1);
+        AccessibilityWindowInfo windowAddedSecond = findWindow(windows, R.string.button2);
+        assertThat(windowAddedFirst.getLayer(), lessThan(windowAddedSecond.getLayer()));
+
+        assertThat(windows, new IsSortedBy<>(w -> w.getLayer(), /* ascending */ false));
+    }
+
+    private AccessibilityWindowInfo findWindow(List<AccessibilityWindowInfo> windows,
+            int btnTextRes) {
+        return windows.stream()
+                .filter(w -> w.getRoot()
+                        .findAccessibilityNodeInfosByText(getString(btnTextRes))
+                        .size() == 1)
+                .findFirst()
+                .get();
+    }
+
     private boolean isDividerWindowPresent(UiAutomation uiAutomation) {
         List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
         final int windowCount = windows.size();
@@ -659,50 +686,44 @@
     }
 
     private View[] addTwoAppPanelWindows() throws TimeoutException {
-        final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+        setAccessInteractiveWindowsFlag();
+        getInstrumentation().getUiAutomation()
+                .waitForIdle(TIMEOUT_WINDOW_STATE_IDLE, TIMEOUT_ASYNC_PROCESSING);
 
-        uiAutomation.waitForIdle(TIMEOUT_WINDOW_STATE_IDLE, TIMEOUT_ASYNC_PROCESSING);
+        return new View[] {
+                addWindow(R.string.button1, params -> {
+                    params.gravity = Gravity.TOP;
+                    params.y = getStatusBarHeight(getActivity());
+                }),
+                addWindow(R.string.button2, params -> {
+                    params.gravity = Gravity.BOTTOM;
+                })
+        };
+    }
 
-        final View views[] = new View[2];
-        // Add the first window.
-        uiAutomation.executeAndWaitForEvent(() -> getInstrumentation().runOnMainSync(() -> {
-            final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
-            params.gravity = Gravity.TOP;
-            params.y = getStatusBarHeight(getActivity());
-            params.width = WindowManager.LayoutParams.MATCH_PARENT;
-            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
-            params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-            params.token = getActivity().getWindow().getDecorView().getWindowToken();
+    private Button addWindow(int btnTextRes, Consumer<WindowManager.LayoutParams> configure)
+            throws TimeoutException {
+        AtomicReference<Button> result = new AtomicReference<>();
+        getInstrumentation().getUiAutomation().executeAndWaitForEvent(() -> {
+            getInstrumentation().runOnMainSync(() -> {
+                final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+                params.width = WindowManager.LayoutParams.MATCH_PARENT;
+                params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+                params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+                params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+                params.token = getActivity().getWindow().getDecorView().getWindowToken();
+                configure.accept(params);
 
-            final Button button = new Button(getActivity());
-            button.setText(R.string.button1);
-            views[0] = button;
-            getActivity().getWindowManager().addView(button, params);
-        }), filterWindowsChangedWithChangeTypes(WINDOWS_CHANGE_ADDED), TIMEOUT_ASYNC_PROCESSING);
-
-        // Add the second window.
-        uiAutomation.executeAndWaitForEvent(() -> getInstrumentation().runOnMainSync(() -> {
-            final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
-            params.gravity = Gravity.BOTTOM;
-            params.width = WindowManager.LayoutParams.MATCH_PARENT;
-            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
-            params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-            params.token = getActivity().getWindow().getDecorView().getWindowToken();
-
-            final Button button = new Button(getActivity());
-            button.setText(R.string.button2);
-            views[1] = button;
-            getActivity().getWindowManager().addView(button, params);
-        }), filterWindowsChangedWithChangeTypes(WINDOWS_CHANGE_ADDED), TIMEOUT_ASYNC_PROCESSING);
-        return views;
+                final Button button = new Button(getActivity());
+                button.setText(btnTextRes);
+                result.set(button);
+                getActivity().getWindowManager().addView(button, params);
+            });
+        }, filterWindowsChangedWithChangeTypes(WINDOWS_CHANGE_ADDED), TIMEOUT_ASYNC_PROCESSING);
+        return result.get();
     }
 
     private void setAccessInteractiveWindowsFlag () {
@@ -806,4 +827,33 @@
     protected void scrubClass(Class<?> testCaseClass) {
         /* intentionally do not scrub */
     }
+
+    private static class IsSortedBy<T> extends TypeSafeMatcher<List<T>> {
+
+        private final Function<T, ? extends Comparable> mProperty;
+        private final boolean mAscending;
+
+        private IsSortedBy(Function<T, ? extends Comparable> comparator, boolean ascending) {
+            mProperty = comparator;
+            mAscending = ascending;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("is sorted");
+        }
+
+        @Override
+        protected boolean matchesSafely(List<T> item) {
+            for (int i = 0; i < item.size() - 1; i++) {
+                Comparable a = mProperty.apply(item.get(i));
+                Comparable b = mProperty.apply(item.get(i));
+                int aMinusB = a.compareTo(b);
+                if (aMinusB != 0 && (aMinusB < 0) != mAscending) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
 }
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java
index 21d6c69..71e2ee9 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityAndWindowManagerOverrideConfigTests.java
@@ -79,7 +79,7 @@
 
         try (final RotationSession rotationSession = new RotationSession()) {
             rotationSession.set(ROTATION_0);
-            LogSeparator logSeparator = clearLogcat();
+            LogSeparator logSeparator = separateLogs();
             resizeActivityTask(LOG_CONFIGURATION_ACTIVITY, 0, 0, 100, 100);
             ConfigurationChangeObserver c = new ConfigurationChangeObserver();
             final boolean reportedSizeAfterResize = c.findConfigurationChange(
@@ -87,7 +87,7 @@
             assertTrue("Expected to observe configuration change when resizing",
                     reportedSizeAfterResize);
 
-            logSeparator = clearLogcat();
+            logSeparator = separateLogs();
             rotationSession.set(ROTATION_180);
             final boolean reportedSizeAfterRotation = c.findConfigurationChange(
                     LOG_CONFIGURATION_ACTIVITY, logSeparator);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
index 4474bb1..68be619 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
@@ -356,7 +356,7 @@
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.disableLockScreen()
                     .sleepDevice();
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             launchActivity(TURN_SCREEN_ON_ATTR_ACTIVITY);
             mAmWmState.assertVisibility(TURN_SCREEN_ON_ATTR_ACTIVITY, true);
             assertTrue("Display turns on", isDisplayOn());
@@ -371,7 +371,7 @@
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.setLockCredential()
                     .sleepDevice();
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             launchActivityNoWait(TURN_SCREEN_ON_ATTR_ACTIVITY);
             // Wait for the activity stopped because lock screen prevent showing the activity.
             mAmWmState.waitForActivityState(TURN_SCREEN_ON_ATTR_ACTIVITY, STATE_STOPPED);
@@ -385,7 +385,7 @@
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.sleepDevice();
             mAmWmState.waitForAllStoppedActivities();
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             launchActivity(TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY);
             mAmWmState.assertVisibility(TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY, true);
             assertTrue("Display turns on", isDisplayOn());
@@ -398,14 +398,14 @@
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.sleepDevice();
             mAmWmState.waitForAllStoppedActivities();
-            LogSeparator logSeparator = clearLogcat();
+            LogSeparator logSeparator = separateLogs();
             launchActivity(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY);
             assertTrue("Display turns on", isDisplayOn());
             assertSingleLaunch(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY, logSeparator);
 
             lockScreenSession.sleepDevice();
             mAmWmState.waitForAllStoppedActivities();
-            logSeparator = clearLogcat();
+            logSeparator = separateLogs();
             launchActivity(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY);
             // Display should keep off, because setTurnScreenOn(false) has been called at
             // {@link TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY}'s onStop.
@@ -419,14 +419,14 @@
     public void testTurnScreenOnSingleTask() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.sleepDevice();
-            LogSeparator logSeparator = clearLogcat();
+            LogSeparator logSeparator = separateLogs();
             launchActivity(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY);
             mAmWmState.assertVisibility(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, true);
             assertTrue("Display turns on", isDisplayOn());
             assertSingleLaunch(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, logSeparator);
 
             lockScreenSession.sleepDevice();
-            logSeparator = clearLogcat();
+            logSeparator = separateLogs();
             launchActivity(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY);
             mAmWmState.assertVisibility(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, true);
             assertTrue("Display turns on", isDisplayOn());
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java
index ab73fcd..60f48f5 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java
@@ -84,7 +84,7 @@
     private void startActivityAndVerifyResult(final ComponentName entryActivity,
             final ComponentName actualActivity, boolean shouldStart) throws Exception {
         // See TODO below
-        // final LogSeparator logSeparator = clearLogcat();
+        // final LogSeparator logSeparator = separateLogs();
 
         // Pass in different data only when cold starting. This is to make the intent
         // different in subsequent warm/hot launches, so that the entrypoint alias
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java
index eeecec6..d4422c0 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAppConfigurationTests.java
@@ -93,12 +93,12 @@
     public void testConfigurationUpdatesWhenResizedFromFullscreen() throws Exception {
         assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
 
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         launchActivity(RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
         final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
                 logSeparator);
 
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         setActivityTaskWindowingMode(RESIZEABLE_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
                 logSeparator);
@@ -116,12 +116,12 @@
     public void testConfigurationUpdatesWhenResizedFromDockedStack() throws Exception {
         assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
 
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         launchActivity(RESIZEABLE_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
                 logSeparator);
 
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         setActivityTaskWindowingMode(RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
         final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
                 logSeparator);
@@ -139,7 +139,7 @@
         try (final RotationSession rotationSession = new RotationSession()) {
             rotationSession.set(ROTATION_0);
 
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             launchActivity(RESIZEABLE_ACTIVITY,
                     WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
             final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY,
@@ -161,7 +161,7 @@
         try (final RotationSession rotationSession = new RotationSession()) {
             rotationSession.set(ROTATION_0);
 
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             // Launch our own activity to side in case Recents (or other activity to side) doesn't
             // support rotation.
             launchActivitiesInSplitScreen(
@@ -188,7 +188,7 @@
         try (final RotationSession rotationSession = new RotationSession()) {
             rotationSession.set(ROTATION_0);
 
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             launchActivitiesInSplitScreen(
                     getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
                     getLaunchActivityBuilder().setTargetActivity(RESIZEABLE_ACTIVITY));
@@ -203,7 +203,7 @@
             throws Exception {
         final int[] rotations = { ROTATION_270, ROTATION_180, ROTATION_90, ROTATION_0 };
         for (final int rotation : rotations) {
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             final ActivityManagerState.ActivityTask task =
                     mAmWmState.getAmState().getTaskByActivity(RESIZEABLE_ACTIVITY);
             final int displayId = mAmWmState.getAmState().getStackById(task.mStackId).mDisplayId;
@@ -256,14 +256,14 @@
         assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
 
         // Launch to fullscreen stack and record size.
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         launchActivity(activityName, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
         final ReportedSizes initialFullscreenSizes = getActivityDisplaySize(activityName,
                 logSeparator);
         final Rect displayRect = getDisplayRect(activityName);
 
         // Move to docked stack.
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         setActivityTaskWindowingMode(activityName, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         final ReportedSizes dockedSizes = getActivityDisplaySize(activityName, logSeparator);
         assertSizesAreSane(initialFullscreenSizes, dockedSizes);
@@ -277,7 +277,7 @@
 
         // Resize docked stack to fullscreen size. This will trigger activity relaunch with
         // non-empty override configuration corresponding to fullscreen size.
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         mAm.resizeStack(stack.mStackId, displayRect);
 
         // Move activity back to fullscreen stack.
@@ -340,14 +340,14 @@
     @Test
     @FlakyTest(bugId = 71875755)
     public void testFullscreenAppOrientationRequests() throws Exception {
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         launchActivity(PORTRAIT_ORIENTATION_ACTIVITY);
         mAmWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */);
         ReportedSizes reportedSizes =
                 getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY, logSeparator);
         assertEquals("portrait activity should be in portrait",
                 1 /* portrait */, reportedSizes.orientation);
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
 
         launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY);
         mAmWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */);
@@ -355,7 +355,7 @@
                 getLastReportedSizesForActivity(LANDSCAPE_ORIENTATION_ACTIVITY, logSeparator);
         assertEquals("landscape activity should be in landscape",
                 2 /* landscape */, reportedSizes.orientation);
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
 
         launchActivity(PORTRAIT_ORIENTATION_ACTIVITY);
         mAmWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */);
@@ -363,18 +363,18 @@
                 getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY, logSeparator);
         assertEquals("portrait activity should be in portrait",
                 1 /* portrait */, reportedSizes.orientation);
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
     }
 
     @Test
     public void testNonfullscreenAppOrientationRequests() throws Exception {
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         launchActivity(PORTRAIT_ORIENTATION_ACTIVITY);
         final ReportedSizes initialReportedSizes =
                 getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY, logSeparator);
         assertEquals("portrait activity should be in portrait",
                 1 /* portrait */, initialReportedSizes.orientation);
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
 
         launchActivity(SDK26_TRANSLUCENT_LANDSCAPE_ACTIVITY);
         assertEquals("Legacy non-fullscreen activity requested landscape orientation",
@@ -535,7 +535,7 @@
         assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow());
 
         // Launch to docked stack and record size.
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         launchActivityInSplitScreenWithRecents(activityName);
         final ReportedSizes initialDockedSizes = getActivityDisplaySize(activityName, logSeparator);
         // Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
@@ -545,14 +545,14 @@
                 new WaitForValidActivityState.Builder(activityName).build());
 
         // Move to fullscreen stack.
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         setActivityTaskWindowingMode(
                 activityName, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
         final ReportedSizes fullscreenSizes = getActivityDisplaySize(activityName, logSeparator);
         assertSizesAreSane(fullscreenSizes, initialDockedSizes);
 
         // Move activity back to docked stack.
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         setActivityTaskWindowingMode(activityName, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         final ReportedSizes finalDockedSizes = getActivityDisplaySize(activityName, logSeparator);
 
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java
index db81483..30ed944 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerConfigChangeTests.java
@@ -111,7 +111,7 @@
             }
 
             for (int rotation = 0; rotation < 4; rotation += rotationStep) {
-                final LogSeparator logSeparator = clearLogcat();
+                final LogSeparator logSeparator = separateLogs();
                 rotationSession.set(rotation);
                 mAmWmState.computeState(activityName);
                 assertRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange,
@@ -133,14 +133,14 @@
             ComponentName activityName, boolean relaunch) throws Exception {
         try (final FontScaleSession fontScaleSession = new FontScaleSession()) {
             fontScaleSession.set(1.0f);
-            LogSeparator logSeparator = clearLogcat();
+            LogSeparator logSeparator = separateLogs();
             launchActivity(activityName);
             mAmWmState.computeState(activityName);
 
             final int densityDpi = getActivityDensityDpi(activityName, logSeparator);
 
             for (float fontScale = 0.85f; fontScale <= 1.3f; fontScale += 0.15f) {
-                logSeparator = clearLogcat();
+                logSeparator = separateLogs();
                 fontScaleSession.set(fontScale);
                 mAmWmState.computeState(activityName);
                 assertRelaunchOrConfigChanged(activityName, relaunch ? 1 : 0, relaunch ? 0 : 1,
@@ -161,13 +161,13 @@
      */
     @Test
     public void testUpdateApplicationInfo() throws Exception {
-        final LogSeparator firstLogSeparator = clearLogcat();
+        final LogSeparator firstLogSeparator = separateLogs();
 
         // Launch an activity that prints applied config.
         launchActivity(TEST_ACTIVITY);
         final int assetSeq = readAssetSeqNumber(TEST_ACTIVITY, firstLogSeparator);
 
-        final LogSeparator logSeparator = clearLogcat();
+        final LogSeparator logSeparator = separateLogs();
         // Update package info.
         executeShellCommand("am update-appinfo all " + TEST_ACTIVITY.getPackageName());
         mAmWmState.waitForWithAmState((amState) -> {
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java
index d8808ea..4a3370f 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerFreeformStackTests.java
@@ -122,7 +122,7 @@
         mAmWmState.computeState(new WaitForValidActivityState.Builder(TEST_ACTIVITY).build(),
                 new WaitForValidActivityState.Builder(NO_RELAUNCH_ACTIVITY).build());
 
-        final LogSeparator logSeparator = clearLogcat();
+        final LogSeparator logSeparator = separateLogs();
         resizeActivityTask(TEST_ACTIVITY,
                 TEST_TASK_OFFSET, TEST_TASK_OFFSET, testTaskSize2, testTaskSize1);
         resizeActivityTask(NO_RELAUNCH_ACTIVITY,
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
index 0b15afc..23eb28c 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
@@ -106,7 +106,7 @@
             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
 
             // Launch activity on new secondary display.
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
             mAmWmState.computeState(TEST_ACTIVITY);
 
@@ -363,7 +363,7 @@
             // Create new virtual display.
             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
 
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
 
             // Try to launch an activity and check it security exception was triggered.
             getLaunchActivityBuilder()
@@ -419,6 +419,7 @@
      * primary display.
      */
     @Presubmit
+    @FlakyTest(bugId = 77469851)
     @Test
     public void testConsequentLaunchActivity() throws Exception {
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
@@ -587,7 +588,7 @@
                     "Activity launched on secondary display must be resumed",
                     LAUNCHING_ACTIVITY);
 
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
 
             // Launch second activity from app on secondary display specifying same display id.
             getLaunchActivityBuilder()
@@ -778,7 +779,7 @@
             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
 
             // Destroy virtual display.
-            logSeparator = clearLogcat();
+            logSeparator = separateLogs();
         }
 
         mAmWmState.computeState(true);
@@ -1046,7 +1047,7 @@
             assertEquals("Focused stack must be on secondary display", newDisplay.mId,
                     focusedStack.mDisplayId);
 
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
 
             // Launch other activity with different uid and check security exception is triggered.
             getLaunchActivityBuilder()
@@ -1126,7 +1127,7 @@
                     RESIZEABLE_ACTIVITY);
 
             // Destroy the display and check if activities are removed from system.
-            logSeparator = clearLogcat();
+            logSeparator = separateLogs();
         }
 
         mAmWmState.waitForWithAmState(
@@ -1165,7 +1166,7 @@
             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
             // Launch a resizeable activity on new secondary display.
-            final LogSeparator initialLogSeparator = clearLogcat();
+            final LogSeparator initialLogSeparator = separateLogs();
             launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
             mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
             mAmWmState.assertFocusedActivity("Launched activity must be focused",
@@ -1176,7 +1177,7 @@
                     RESIZEABLE_ACTIVITY, initialLogSeparator);
 
             // Resize the docked stack, so that activity with virtual display will also be resized.
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             virtualDisplaySession.resizeDisplay();
 
             mAmWmState.waitForWithAmState(amState -> {
@@ -1333,7 +1334,7 @@
             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
             // Launch activity on new secondary display.
-            LogSeparator logSeparator = clearLogcat();
+            LogSeparator logSeparator = separateLogs();
             launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
             mAmWmState.assertFocusedActivity("Focus must be on secondary display",
                     RESIZEABLE_ACTIVITY);
@@ -1351,7 +1352,7 @@
                 final int initialRotation = mAmWmState.getWmState().getRotation();
                 rotationSession.set((initialRotation + 1) % 4);
 
-                logSeparator = clearLogcat();
+                logSeparator = separateLogs();
                 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
                 mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED);
                 mAmWmState.assertFocusedActivity("Focus must be on secondary display",
@@ -1369,7 +1370,7 @@
     private void rotateAndCheckSameSizes(
             RotationSession rotationSession, ComponentName activityName) throws Exception {
         for (int rotation = 3; rotation >= 0; --rotation) {
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             rotationSession.set(rotation);
             final ReportedSizes rotatedSizes = getLastReportedSizesForActivity(activityName,
                     logSeparator);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerPinnedStackTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerPinnedStackTests.java
index 1a0399e..b9e843b 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerPinnedStackTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerPinnedStackTests.java
@@ -845,7 +845,7 @@
         // Launch a PiP activity and ensure configuration change only happened once, and that the
         // configuration change happened after the picture-in-picture and multi-window callbacks
         launchActivity(PIP_ACTIVITY);
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         executeShellCommand("am broadcast -a " + ACTION_ENTER_PIP);
         waitForEnterPip(PIP_ACTIVITY);
         assertPinnedStackExists();
@@ -854,7 +854,7 @@
 
         // Trigger it to go back to fullscreen and ensure that only triggered one configuration
         // change as well
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         launchActivity(PIP_ACTIVITY);
         waitForValidPictureInPictureCallbacks(PIP_ACTIVITY, logSeparator);
         assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY, logSeparator);
@@ -886,7 +886,7 @@
             assertPinnedStackExists();
 
             // Relaunch the PiP activity back into fullscreen
-            LogSeparator logSeparator = clearLogcat();
+            LogSeparator logSeparator = separateLogs();
             launchActivity(PIP_ACTIVITY);
             // Wait until the PiP activity is reparented into the fullscreen stack (happens after
             // the transition has finished)
@@ -916,7 +916,7 @@
         assertPinnedStackExists();
 
         // Dismiss it
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
         waitForExitPipToFullscreen(PIP_ACTIVITY);
 
@@ -1032,7 +1032,7 @@
 
         // Finish the task overlay activity while animating and ensure that the PiP activity never
         // got resumed
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         executeShellCommand("am stack resize-animated " + stackId + " 20 20 500 500");
         executeShellCommand("am broadcast -a " + TEST_ACTIVITY_ACTION_FINISH_SELF);
         mAmWmState.waitFor((amState, wmState) ->
@@ -1168,7 +1168,7 @@
     public void testDisplayMetricsPinUnpin() throws Exception {
         assumeTrue(supportsPip());
 
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         launchActivity(TEST_ACTIVITY);
         final int defaultWindowingMode = mAmWmState.getAmState()
                 .getTaskByActivity(TEST_ACTIVITY).getWindowingMode();
@@ -1178,7 +1178,7 @@
         assertNotNull("Must report display dimensions", initialSizes);
         assertNotNull("Must report app bounds", initialAppBounds);
 
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
         // Wait for animation complete since we are comparing bounds
         waitForEnterPipAnimationComplete(PIP_ACTIVITY);
@@ -1193,7 +1193,7 @@
         assertNotEquals("Reported app size when pinned must be different from default",
                 initialAppSize, pinnedAppSize);
 
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         launchActivity(PIP_ACTIVITY, defaultWindowingMode);
         final ReportedSizes finalSizes = getLastReportedSizesForActivity(PIP_ACTIVITY,
                 logSeparator);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java
index 500f595..4edd541 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java
@@ -150,7 +150,7 @@
                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
 
         // Exit split-screen mode and ensure we only get 1 multi-window mode changed callback.
-        final LogSeparator logSeparator = clearLogcat();
+        final LogSeparator logSeparator = separateLogs();
         removeStacksInWindowingModes(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         final ActivityLifecycleCounts lifecycleCounts = waitForOnMultiWindowModeChanged(
                 TEST_ACTIVITY, logSeparator);
@@ -164,7 +164,7 @@
         launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
 
         // Move to docked stack.
-        LogSeparator logSeparator = clearLogcat();
+        LogSeparator logSeparator = separateLogs();
         setActivityTaskWindowingMode(TEST_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         ActivityLifecycleCounts lifecycleCounts = waitForOnMultiWindowModeChanged(
                 TEST_ACTIVITY, logSeparator);
@@ -177,7 +177,7 @@
         launchActivity(TEST_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
 
         // Move activity back to fullscreen stack.
-        logSeparator = clearLogcat();
+        logSeparator = separateLogs();
         setActivityTaskWindowingMode(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
         lifecycleCounts = waitForOnMultiWindowModeChanged(TEST_ACTIVITY, logSeparator);
         assertEquals("mMultiWindowModeChangedCount",
@@ -583,7 +583,7 @@
         final Rect initialDockBounds = mAmWmState.getWmState().getStandardStackByWindowingMode(
                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) .getBounds();
 
-        final LogSeparator logSeparator = clearLogcat();
+        final LogSeparator logSeparator = separateLogs();
 
         Rect newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, true);
         resizeDockedStack(
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java
index 3984af0..eca8940 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java
@@ -128,7 +128,7 @@
     public void testDismissKeyguardActivity_method() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.setLockCredential();
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             lockScreenSession.gotoKeyguard();
             mAmWmState.computeState(true);
             assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -146,7 +146,7 @@
     public void testDismissKeyguardActivity_method_cancelled() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.setLockCredential();
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             lockScreenSession.gotoKeyguard();
             mAmWmState.computeState(true);
             assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
index ec1eee4..2a07b27 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
@@ -240,7 +240,7 @@
     @Test
     public void testDismissKeyguardActivity_method() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             lockScreenSession.gotoKeyguard();
             mAmWmState.computeState(true);
             assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -256,7 +256,7 @@
     @Test
     public void testDismissKeyguardActivity_method_notTop() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             lockScreenSession.gotoKeyguard();
             mAmWmState.computeState(true);
             assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -270,7 +270,7 @@
     @Test
     public void testDismissKeyguardActivity_method_turnScreenOn() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             lockScreenSession.sleepDevice();
             mAmWmState.computeState(true);
             assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -349,7 +349,7 @@
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.sleepDevice();
 
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             mAmWmState.computeState(true);
             assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
             launchActivity(TURN_SCREEN_ON_ATTR_DISMISS_KEYGUARD_ACTIVITY);
@@ -381,7 +381,7 @@
     @Test
     public void testScreenOffWhileOccludedStopsActivity() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             lockScreenSession.gotoKeyguard();
             mAmWmState.assertKeyguardShowingAndNotOccluded();
             launchActivity(SHOW_WHEN_LOCKED_ATTR_ACTIVITY);
@@ -396,7 +396,7 @@
     @Test
     public void testScreenOffCausesSingleStop() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             launchActivity(TEST_ACTIVITY);
             mAmWmState.assertVisibility(TEST_ACTIVITY, true);
             lockScreenSession.sleepDevice();
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java
index 5e7f309..c2156fe 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTransitionTests.java
@@ -114,7 +114,7 @@
     public void testOccludeManifestAttr() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.gotoKeyguard();
-            final LogSeparator logSeparator = clearLogcat();
+            final LogSeparator logSeparator = separateLogs();
             launchActivity(SHOW_WHEN_LOCKED_ATTR_ACTIVITY);
             mAmWmState.computeState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY);
             assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_OCCLUDE,
@@ -127,7 +127,7 @@
     public void testOccludeAttrRemove() throws Exception {
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.gotoKeyguard();
-            LogSeparator logSeparator = clearLogcat();
+            LogSeparator logSeparator = separateLogs();
             launchActivity(SHOW_WHEN_LOCKED_ATTR_REMOVE_ATTR_ACTIVITY);
             mAmWmState.computeState(SHOW_WHEN_LOCKED_ATTR_REMOVE_ATTR_ACTIVITY);
             assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_OCCLUDE,
@@ -135,7 +135,7 @@
             assertSingleLaunch(SHOW_WHEN_LOCKED_ATTR_REMOVE_ATTR_ACTIVITY, logSeparator);
 
             lockScreenSession.gotoKeyguard();
-            logSeparator = clearLogcat();
+            logSeparator = separateLogs();
             launchActivity(SHOW_WHEN_LOCKED_ATTR_REMOVE_ATTR_ACTIVITY);
             mAmWmState.computeState(SHOW_WHEN_LOCKED_ATTR_REMOVE_ATTR_ACTIVITY);
             assertSingleStartAndStop(SHOW_WHEN_LOCKED_ATTR_REMOVE_ATTR_ACTIVITY, logSeparator);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
index 920de4c..380449c 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/lifecycle/ActivityLifecycleTests.java
@@ -121,6 +121,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 77565927)
     public void testRelaunchConfigurationChangedWhileBecomingVisible() throws Exception {
         final Activity becomingVisibleActivity =
                 mFirstActivityTestRule.launchActivity(new Intent());
@@ -434,6 +435,7 @@
     /**
      * The that recreate request from an activity is executed immediately.
      */
+    @FlakyTest(bugId = 77565927)
     @Test
     public void testLocalRecreate() throws Exception {
         // Launch the activity that will recreate itself
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
index 4b39cfa..0a3ae97 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
@@ -768,12 +768,11 @@
     }
 
     /**
-     * Tries to clear logcat and inserts log separator in case clearing didn't succeed, so we can
-     * always find the starting point from where to evaluate following logs.
+     * Inserts a log separator so we can always find the starting point from where to evaluate
+     * following logs.
      * @return Unique log separator.
      */
-    protected LogSeparator clearLogcat() {
-        executeShellCommand("logcat -c");
+    protected LogSeparator separateLogs() {
         final LogSeparator logSeparator = new LogSeparator();
         executeShellCommand("log -t " + LOG_SEPARATOR + " " + logSeparator);
         return logSeparator;
diff --git a/tests/signature/api-check/hidden-api-killswitch/Android.mk b/tests/signature/api-check/hidden-api-killswitch/Android.mk
index 2e1ee05..33afcff 100644
--- a/tests/signature/api-check/hidden-api-killswitch/Android.mk
+++ b/tests/signature/api-check/hidden-api-killswitch/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 LOCAL_MULTILIB := both
-LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker
+LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker libclassdescriptors
 LOCAL_NDK_STL_VARIANT := c++_static
 
 # Tag this module as a cts test artifact
diff --git a/tests/signature/api-check/hidden-api-killswitch/AndroidManifest.xml b/tests/signature/api-check/hidden-api-killswitch/AndroidManifest.xml
index 8699d18..2e990a1 100644
--- a/tests/signature/api-check/hidden-api-killswitch/AndroidManifest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.signature.cts.api.killswitch">
 
-    <application/>
+    <application android:debuggable="true"/>
 
     <instrumentation android:name="repackaged.android.test.InstrumentationTestRunner"
                      android:targetPackage="android.signature.cts.api.killswitch"
diff --git a/tests/signature/api-check/hidden-api-killswitch/AndroidTest.xml b/tests/signature/api-check/hidden-api-killswitch/AndroidTest.xml
index 2d99a73..35bf729 100644
--- a/tests/signature/api-check/hidden-api-killswitch/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-killswitch/AndroidTest.xml
@@ -30,6 +30,6 @@
         <option name="package" value="android.signature.cts.api.killswitch" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.KillswitchTest" />
-        <option name="runtime-hint" value="30s" />
+        <option name="runtime-hint" value="60s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java b/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
index 95f46df..61511c3 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
@@ -18,6 +18,9 @@
 
 import android.os.Debug;
 import android.signature.cts.ClassProvider;
+import android.signature.cts.DexField;
+import android.signature.cts.DexMethod;
+import android.signature.cts.DexMember;
 import dalvik.system.BaseDexClassLoader;
 
 import java.io.File;
@@ -34,19 +37,9 @@
 
     @Override
     public Stream<Class<?>> getAllClasses() {
-        if (!sJvmtiAttached) {
-            try {
-                Debug.attachJvmtiAgent(copyAgentToFile("classdescriptors").getAbsolutePath(), null,
-                        BootClassPathClassesProvider.class.getClassLoader());
-                sJvmtiAttached = true;
-                initialize();
-            } catch (Exception e) {
-                throw new RuntimeException("Error while attaching JVMTI agent", e);
-            }
-        }
+        maybeAttachJvmtiAgent();
         return Arrays.stream(getClassloaderDescriptors(Object.class.getClassLoader()))
                 .map(descriptor -> {
-                    System.err.println("Class name = " + descriptor);
                     String classname = descriptor.replace('/', '.');
                     // omit L and ; at the front and at the end
                     return classname.substring(1, classname.length() - 1);
@@ -60,6 +53,42 @@
                 });
     }
 
+    @Override
+    public Stream<DexMember> getAllMembers(Class<?> klass) {
+        maybeAttachJvmtiAgent();
+
+        String[][] field_infos = getClassMemberNamesAndTypes(klass, /* fields */ true);
+        String[][] method_infos = getClassMemberNamesAndTypes(klass, /* fields */ false);
+        if (field_infos.length != 2 || field_infos[0].length != field_infos[1].length ||
+            method_infos.length != 2 || method_infos[0].length != method_infos[1].length) {
+          throw new RuntimeException("Invalid result from getClassMemberNamesAndTypes");
+        }
+
+        String klass_desc = "L" + klass.getName().replace('.', '/') + ";";
+        DexMember[] members = new DexMember[field_infos[0].length + method_infos[0].length];
+        for (int i = 0; i < field_infos[0].length; i++) {
+            members[i] = new DexField(klass_desc, field_infos[0][i], field_infos[1][i]);
+        }
+        for (int i = 0; i < method_infos[0].length; i++) {
+            members[i + field_infos[0].length] =
+                new DexMethod(klass_desc, method_infos[0][i], method_infos[1][i]);
+        }
+        return Arrays.stream(members);
+    }
+
+    private static void maybeAttachJvmtiAgent() {
+      if (!sJvmtiAttached) {
+          try {
+              Debug.attachJvmtiAgent(copyAgentToFile("classdescriptors").getAbsolutePath(), null,
+                      BootClassPathClassesProvider.class.getClassLoader());
+              sJvmtiAttached = true;
+              initialize();
+          } catch (Exception e) {
+              throw new RuntimeException("Error while attaching JVMTI agent", e);
+          }
+      }
+    }
+
     private static File copyAgentToFile(String lib) throws Exception {
         ClassLoader cl = BootClassPathClassesProvider.class.getClassLoader();
 
@@ -84,4 +113,5 @@
     private static native void initialize();
 
     private static native String[] getClassloaderDescriptors(ClassLoader loader);
+    private static native String[][] getClassMemberNamesAndTypes(Class<?> klass, boolean getFields);
 }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
index 9673fd2..f04f476 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
@@ -18,10 +18,10 @@
 
 import android.os.Bundle;
 import android.signature.cts.DexApiDocumentParser;
-import android.signature.cts.DexApiDocumentParser.DexField;
-import android.signature.cts.DexApiDocumentParser.DexMember;
-import android.signature.cts.DexApiDocumentParser.DexMethod;
+import android.signature.cts.DexField;
+import android.signature.cts.DexMember;
 import android.signature.cts.DexMemberChecker;
+import android.signature.cts.DexMethod;
 import android.signature.cts.FailureType;
 import android.signature.cts.ResultObserver;
 
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/KillswitchTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/KillswitchTest.java
index 37ff746..3da22a9 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/KillswitchTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/KillswitchTest.java
@@ -18,7 +18,10 @@
 
 import android.provider.Settings;
 import android.signature.cts.DexApiDocumentParser;
+import android.signature.cts.DexField;
+import android.signature.cts.DexMember;
 import android.signature.cts.DexMemberChecker;
+import android.signature.cts.DexMethod;
 import android.signature.cts.FailureType;
 
 public class KillswitchTest extends AbstractApiTest {
@@ -40,71 +43,74 @@
             " when global setting hidden_api_blacklist_exemptions is set to *";
 
     public void testKillswitch() {
-        // for now, just verify that we can access something *not* on the light grey or white list
-        DexApiDocumentParser.DexMember member = new DexApiDocumentParser.DexField(
-                "Ldalvik/system/VMRuntime;", "THE_ONE", "Ldalvik/system/VMRuntime;");
-        runWithTestResultObserver(resultObserver ->
-                DexMemberChecker.checkSingleMember(member, new DexMemberChecker.Observer() {
-                    @Override
-                    public void classAccessible(boolean accessible,
-                            DexApiDocumentParser.DexMember member) {
-                        if (!accessible) {
-                            resultObserver.notifyFailure(
-                                    FailureType.MISSING_CLASS,
-                                    member.toString(),
-                                    "Class from boot classpath is not accessible"
-                                            + ERROR_MESSAGE_APPENDIX);
-                        }
+        runWithTestResultObserver(resultObserver -> {
+            DexMemberChecker.Observer observer = new DexMemberChecker.Observer() {
+                @Override
+                public void classAccessible(boolean accessible, DexMember member) {
+                    if (!accessible) {
+                        resultObserver.notifyFailure(
+                                FailureType.MISSING_CLASS,
+                                member.toString(),
+                                "Class from boot classpath is not accessible"
+                                        + ERROR_MESSAGE_APPENDIX);
+                    }
+                }
+
+                @Override
+                public void fieldAccessibleViaReflection(boolean accessible, DexField field) {
+                    if (!accessible) {
+                        resultObserver.notifyFailure(
+                                FailureType.MISSING_FIELD,
+                                field.toString(),
+                                "Field from boot classpath is not accessible via reflection"
+                                        + ERROR_MESSAGE_APPENDIX);
+                    }
+                }
+
+                @Override
+                public void fieldAccessibleViaJni(boolean accessible, DexField field) {
+                    if (!accessible) {
+                        resultObserver.notifyFailure(
+                                FailureType.MISSING_FIELD,
+                                field.toString(),
+                                "Field from boot classpath is not accessible via JNI"
+                                        + ERROR_MESSAGE_APPENDIX);
+                    }
+                }
+
+                @Override
+                public void methodAccessibleViaReflection(boolean accessible, DexMethod method) {
+                    if (method.isStaticConstructor()) {
+                        // Skip static constructors. They cannot be discovered with reflection.
+                        return;
                     }
 
-                    @Override
-                    public void fieldAccessibleViaReflection(boolean accessible,
-                            DexApiDocumentParser.DexField field) {
-                        if (!accessible) {
-                            resultObserver.notifyFailure(
-                                    FailureType.MISSING_FIELD,
-                                    field.toString(),
-                                    "Field from boot classpath is not accessible via reflection"
-                                            + ERROR_MESSAGE_APPENDIX);
-                        }
+                    if (!accessible) {
+                        resultObserver.notifyFailure(
+                                FailureType.MISSING_METHOD,
+                                method.toString(),
+                                "Method from boot classpath is not accessible via reflection"
+                                        + ERROR_MESSAGE_APPENDIX);
                     }
+                }
 
-                    @Override
-                    public void fieldAccessibleViaJni(boolean accessible,
-                            DexApiDocumentParser.DexField field) {
-                        if (!accessible) {
-                            resultObserver.notifyFailure(
-                                    FailureType.MISSING_FIELD,
-                                    field.toString(),
-                                    "Field from boot classpath is not accessible via JNI"
-                                            + ERROR_MESSAGE_APPENDIX);
-                        }
+                @Override
+                public void methodAccessibleViaJni(boolean accessible, DexMethod method) {
+                    if (!accessible) {
+                        resultObserver.notifyFailure(
+                                FailureType.MISSING_METHOD,
+                                method.toString(),
+                                "Method from boot classpath is not accessible via JNI"
+                                        + ERROR_MESSAGE_APPENDIX);
                     }
+                }
 
-                    @Override
-                    public void methodAccessibleViaReflection(boolean accessible,
-                            DexApiDocumentParser.DexMethod method) {
-                        if (!accessible) {
-                            resultObserver.notifyFailure(
-                                    FailureType.MISSING_METHOD,
-                                    method.toString(),
-                                    "Method from boot classpath is not accessible via reflection"
-                                            + ERROR_MESSAGE_APPENDIX);
-                        }
-                    }
-
-                    @Override
-                    public void methodAccessibleViaJni(boolean accessible,
-                            DexApiDocumentParser.DexMethod method) {
-                        if (!accessible) {
-                            resultObserver.notifyFailure(
-                                    FailureType.MISSING_METHOD,
-                                    method.toString(),
-                                    "Method from boot classpath is not accessible via JNI"
-                                            + ERROR_MESSAGE_APPENDIX);
-                        }
-                    }
-
-                }));
+            };
+            classProvider.getAllClasses().forEach(klass -> {
+                classProvider.getAllMembers(klass).forEach(member -> {
+                    DexMemberChecker.checkSingleMember(member, observer);
+                });
+            });
+        });
     }
 }
diff --git a/tests/signature/api-check/src/jni/classdescriptors.cpp b/tests/signature/api-check/src/jni/classdescriptors.cpp
index 3da66f1..7af2c30 100644
--- a/tests/signature/api-check/src/jni/classdescriptors.cpp
+++ b/tests/signature/api-check/src/jni/classdescriptors.cpp
@@ -17,7 +17,12 @@
 #include <jni.h>
 #include <jvmti.h>
 
+#include <stdlib.h>
 #include <string.h>
+#include <type_traits>
+
+#include <iostream>
+#include <sstream>
 
 namespace android {
 namespace signature {
@@ -51,6 +56,35 @@
   Dealloc(data);
 }
 
+template<typename T>
+class ScopedJvmtiReference {
+ static_assert(std::is_pointer<T>::value, "T must be a pointer type");
+
+ public:
+  ScopedJvmtiReference() : ref_(nullptr) {}
+
+  ~ScopedJvmtiReference() {
+    if (ref_ != nullptr) {
+      Dealloc(ref_);
+    }
+  }
+
+  // Return the pointer value.
+  T Get() { return ref_; };
+
+  // Return a pointer to the pointer value.
+  T* GetPtr() { return &ref_; };
+
+ private:
+  T ref_;
+};
+
+static void abortIfExceptionPending(JNIEnv* env) {
+  if (env->ExceptionCheck()) {
+    abort();
+  }
+}
+
 extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm,
                                                  __attribute__((unused)) char* options,
                                                  __attribute__((unused)) void* reserved) {
@@ -122,6 +156,72 @@
   }
 }
 
+extern "C" JNIEXPORT jobjectArray JNICALL
+Java_android_signature_cts_api_BootClassPathClassesProvider_getClassMemberNamesAndTypes(
+    JNIEnv* env, jclass, jclass klass, jboolean getFields) {
+  jvmtiError error;
+
+  jint count;
+  ScopedJvmtiReference<jfieldID*> fids;
+  ScopedJvmtiReference<jmethodID*> mids;
+
+  // Request a list of field/method IDs using JVMTI.
+  error = (getFields != JNI_FALSE) ? jvmti_env->GetClassFields(klass, &count, fids.GetPtr())
+                                   : jvmti_env->GetClassMethods(klass, &count, mids.GetPtr());
+  if (error != JVMTI_ERROR_NONE) {
+    std::stringstream ss;
+    ss << "Error while executing "
+       << ((getFields != JNI_FALSE) ? "GetClassFields" : "GetClassMethods")
+       << ", error code: " << static_cast<unsigned>(error);
+    std::string error = ss.str();
+    jclass rt_exception = env->FindClass("java/lang/RuntimeException");
+    env->ThrowNew(rt_exception, error.c_str());
+    return nullptr;
+  }
+
+  jobjectArray names = env->NewObjectArray(count, env->FindClass("java/lang/String"), nullptr);
+  abortIfExceptionPending(env);
+  jobjectArray types = env->NewObjectArray(count, env->FindClass("java/lang/String"), nullptr);
+  abortIfExceptionPending(env);
+
+  // Convert IDs to names and types using JVMTI.
+  for (jint i = 0; i < count; ++i) {
+    ScopedJvmtiReference<char*> name;
+    ScopedJvmtiReference<char*> type;
+
+    error = (getFields != JNI_FALSE)
+        ? jvmti_env->GetFieldName(klass, fids.Get()[i], name.GetPtr(), type.GetPtr(), nullptr)
+        : jvmti_env->GetMethodName(mids.Get()[i], name.GetPtr(), type.GetPtr(), nullptr);
+    if (error != JVMTI_ERROR_NONE) {
+      std::stringstream ss;
+      ss << "Error while executing "
+         << ((getFields != JNI_FALSE) ? "GetFieldName" : "GetMethodName")
+         << ", error code: " << static_cast<unsigned>(error);
+      std::string error = ss.str();
+      jclass rt_exception = env->FindClass("java/lang/RuntimeException");
+      env->ThrowNew(rt_exception, error.c_str());
+      return nullptr;
+    }
+
+    env->SetObjectArrayElement(names, i, env->NewStringUTF(name.Get()));
+    abortIfExceptionPending(env);
+    env->SetObjectArrayElement(types, i, env->NewStringUTF(type.Get()));
+    abortIfExceptionPending(env);
+  }
+
+  // Return as a array size 2 x count, where result[0] is an array of names and
+  // result[1] is an array of types.
+  jobjectArray result = env->NewObjectArray(
+      /* count */ 2, env->FindClass("[Ljava/lang/String;"), nullptr);
+  abortIfExceptionPending(env);
+  env->SetObjectArrayElement(result, 0, names);
+  abortIfExceptionPending(env);
+  env->SetObjectArrayElement(result, 1, types);
+  abortIfExceptionPending(env);
+
+  return result;
+}
+
 }  // namespace api
 }  // namespace cts
 }  // namespace signature
diff --git a/tests/signature/src/android/signature/cts/ClassProvider.java b/tests/signature/src/android/signature/cts/ClassProvider.java
index 2461f26..799b47c 100644
--- a/tests/signature/src/android/signature/cts/ClassProvider.java
+++ b/tests/signature/src/android/signature/cts/ClassProvider.java
@@ -36,4 +36,9 @@
      * Gets all classes available to this provider.
      */
     public abstract Stream<Class<?>> getAllClasses();
+
+    /**
+     * Gets all class members available for the given class.
+     */
+    public abstract Stream<DexMember> getAllMembers(Class<?> klass);
 }
diff --git a/tests/signature/src/android/signature/cts/DexApiDocumentParser.java b/tests/signature/src/android/signature/cts/DexApiDocumentParser.java
index 7cb60fb..c199bc0 100644
--- a/tests/signature/src/android/signature/cts/DexApiDocumentParser.java
+++ b/tests/signature/src/android/signature/cts/DexApiDocumentParser.java
@@ -19,13 +19,10 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Spliterator;
 import java.util.function.Consumer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 import java.text.ParseException;
@@ -52,7 +49,7 @@
         private static final Pattern REGEX_CLASS = Pattern.compile("^L[^->]*;$");
         private static final Pattern REGEX_FIELD = Pattern.compile("^(L[^->]*;)->(.*):(.*)$");
         private static final Pattern REGEX_METHOD =
-                Pattern.compile("^(L[^->]*;)->(.*)\\((.*)\\)(.*)$");
+                Pattern.compile("^(L[^->]*;)->(.*)(\\(.*\\).*)$");
 
         DexApiSpliterator(BufferedReader reader) {
             mReader = reader;
@@ -137,169 +134,11 @@
                             matchField.group(1), matchField.group(2), matchField.group(3));
                 } else if (matchMethod.matches()) {
                     return new DexMethod(
-                            matchMethod.group(1),matchMethod.group(2),
-                            parseDexTypeList(matchMethod.group(3)), matchMethod.group(4));
+                            matchMethod.group(1),matchMethod.group(2), matchMethod.group(3));
                 } else {
                     throw new IllegalStateException();
                 }
             }
         }
-
-        private List<String> parseDexTypeList(String typeSequence) throws ParseException {
-            List<String> list = new ArrayList<String>();
-            while (!typeSequence.isEmpty()) {
-                String type = firstDexTypeFromList(typeSequence);
-                list.add(type);
-                typeSequence = typeSequence.substring(type.length());
-            }
-            return list;
-        }
-
-        /**
-         * Returns the first dex type in `typeList` or throws a ParserException
-         * if a dex type is not recognized. The input is not changed.
-         */
-        private String firstDexTypeFromList(String typeList) throws ParseException {
-            String dexDimension = "";
-            while (typeList.startsWith("[")) {
-                dexDimension += "[";
-                typeList = typeList.substring(1);
-            }
-
-            String type = null;
-            if (typeList.startsWith("V")
-                    || typeList.startsWith("Z")
-                    || typeList.startsWith("B")
-                    || typeList.startsWith("C")
-                    || typeList.startsWith("S")
-                    || typeList.startsWith("I")
-                    || typeList.startsWith("J")
-                    || typeList.startsWith("F")
-                    || typeList.startsWith("D")) {
-                type = typeList.substring(0, 1);
-            } else if (typeList.startsWith("L") && typeList.indexOf(";") > 0) {
-                type = typeList.substring(0, typeList.indexOf(";") + 1);
-            } else {
-                throw new ParseException(
-                        "Unexpected dex type in \"" + typeList + "\"", mLineNum);
-            }
-
-            return dexDimension + type;
-        }
-    }
-
-    /**
-     * Represents one class member parsed from the reader of dex signatures.
-     */
-    public static abstract class DexMember {
-        private final String mName;
-        private final String mClassDescriptor;
-        private final String mType;
-
-        protected DexMember(String className, String name, String type) {
-            mName = name;
-            mClassDescriptor = className;
-            mType = type;
-        }
-
-        public String getName() {
-            return mName;
-        }
-
-        public String getDexClassName() {
-            return mClassDescriptor;
-        }
-
-        public String getJavaClassName() {
-            return dexToJavaType(mClassDescriptor);
-        }
-
-        public String getDexType() {
-            return mType;
-        }
-
-        public String getJavaType() {
-            return dexToJavaType(mType);
-        }
-
-        /**
-         * Converts `type` to a Java type.
-         */
-        protected static String dexToJavaType(String type) {
-            String javaDimension = "";
-            while (type.startsWith("[")) {
-                javaDimension += "[]";
-                type = type.substring(1);
-            }
-
-            String javaType = null;
-            if ("V".equals(type)) {
-                javaType = "void";
-            } else if ("Z".equals(type)) {
-                javaType = "boolean";
-            } else if ("B".equals(type)) {
-                javaType = "byte";
-            } else if ("C".equals(type)) {
-                javaType = "char";
-            } else if ("S".equals(type)) {
-                javaType = "short";
-            } else if ("I".equals(type)) {
-                javaType = "int";
-            } else if ("J".equals(type)) {
-                javaType = "long";
-            } else if ("F".equals(type)) {
-                javaType = "float";
-            } else if ("D".equals(type)) {
-                javaType = "double";
-            } else if (type.startsWith("L") && type.endsWith(";")) {
-                javaType = type.substring(1, type.length() - 1).replace('/', '.');
-            } else {
-                throw new IllegalStateException("Unexpected type " + type);
-            }
-
-            return javaType + javaDimension;
-        }
-    }
-
-    public static class DexField extends DexMember {
-        public DexField(String className, String name, String type) {
-            super(className, name, type);
-        }
-
-        @Override
-        public String toString() {
-            return getJavaType() + " " + getJavaClassName() + "." + getName();
-        }
-    }
-
-    public static class DexMethod extends DexMember {
-        private final List<String> mParamTypeList;
-
-        public DexMethod(String className, String name, List<String> paramTypeList,
-                String dexReturnType) {
-            super(className, name, dexReturnType);
-            mParamTypeList = paramTypeList;
-        }
-
-        public String getDexSignature() {
-            return "(" + String.join("", mParamTypeList) + ")" + getDexType();
-        }
-
-        public List<String> getJavaParameterTypes() {
-            return mParamTypeList
-                    .stream()
-                    .map(DexMember::dexToJavaType)
-                    .collect(Collectors.toList());
-        }
-
-        public boolean isConstructor() {
-            return "<init>".equals(getName()) && "V".equals(getDexType());
-        }
-
-        @Override
-        public String toString() {
-            return getJavaType() + " " + getJavaClassName() + "." + getName()
-                    + "(" + String.join(", ", getJavaParameterTypes()) + ")";
-        }
     }
 }
diff --git a/tests/signature/src/android/signature/cts/DexField.java b/tests/signature/src/android/signature/cts/DexField.java
new file mode 100644
index 0000000..57f6196
--- /dev/null
+++ b/tests/signature/src/android/signature/cts/DexField.java
@@ -0,0 +1,27 @@
+/*
+ * 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.signature.cts;
+
+public class DexField extends DexMember {
+  public DexField(String className, String name, String type) {
+      super(className, name, type);
+  }
+
+  @Override
+  public String toString() {
+      return getJavaType() + " " + getJavaClassName() + "." + getName();
+  }
+}
diff --git a/tests/signature/src/android/signature/cts/DexMember.java b/tests/signature/src/android/signature/cts/DexMember.java
new file mode 100644
index 0000000..930f92b
--- /dev/null
+++ b/tests/signature/src/android/signature/cts/DexMember.java
@@ -0,0 +1,89 @@
+/*
+ * 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.signature.cts;
+
+/**
+ * Represents one class member parsed from the reader of dex signatures.
+ */
+public abstract class DexMember {
+    private final String mName;
+    private final String mClassDescriptor;
+    private final String mType;
+
+    protected DexMember(String className, String name, String type) {
+        mName = name;
+        mClassDescriptor = className;
+        mType = type;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public String getDexClassName() {
+        return mClassDescriptor;
+    }
+
+    public String getJavaClassName() {
+        return dexToJavaType(mClassDescriptor);
+    }
+
+    public String getDexType() {
+        return mType;
+    }
+
+    public String getJavaType() {
+        return dexToJavaType(mType);
+    }
+
+    /**
+     * Converts `type` to a Java type.
+     */
+    protected static String dexToJavaType(String type) {
+        String javaDimension = "";
+        while (type.startsWith("[")) {
+            javaDimension += "[]";
+            type = type.substring(1);
+        }
+
+        String javaType = null;
+        if ("V".equals(type)) {
+            javaType = "void";
+        } else if ("Z".equals(type)) {
+            javaType = "boolean";
+        } else if ("B".equals(type)) {
+            javaType = "byte";
+        } else if ("C".equals(type)) {
+            javaType = "char";
+        } else if ("S".equals(type)) {
+            javaType = "short";
+        } else if ("I".equals(type)) {
+            javaType = "int";
+        } else if ("J".equals(type)) {
+            javaType = "long";
+        } else if ("F".equals(type)) {
+            javaType = "float";
+        } else if ("D".equals(type)) {
+            javaType = "double";
+        } else if (type.startsWith("L") && type.endsWith(";")) {
+            javaType = type.substring(1, type.length() - 1).replace('/', '.');
+        } else {
+            throw new IllegalStateException("Unexpected type " + type);
+        }
+
+        return javaType + javaDimension;
+    }
+}
diff --git a/tests/signature/src/android/signature/cts/DexMemberChecker.java b/tests/signature/src/android/signature/cts/DexMemberChecker.java
index 3800682..a1bfdb6 100644
--- a/tests/signature/src/android/signature/cts/DexMemberChecker.java
+++ b/tests/signature/src/android/signature/cts/DexMemberChecker.java
@@ -23,20 +23,18 @@
 public class DexMemberChecker {
 
     public interface Observer {
-        void classAccessible(boolean accessible, DexApiDocumentParser.DexMember member);
-        void fieldAccessibleViaReflection(boolean accessible, DexApiDocumentParser.DexField field);
-        void fieldAccessibleViaJni(boolean accessible, DexApiDocumentParser.DexField field);
-        void methodAccessibleViaReflection(boolean accessible,
-                DexApiDocumentParser.DexMethod method);
-        void methodAccessibleViaJni(boolean accessible, DexApiDocumentParser.DexMethod method);
+        void classAccessible(boolean accessible, DexMember member);
+        void fieldAccessibleViaReflection(boolean accessible, DexField field);
+        void fieldAccessibleViaJni(boolean accessible, DexField field);
+        void methodAccessibleViaReflection(boolean accessible, DexMethod method);
+        void methodAccessibleViaJni(boolean accessible, DexMethod method);
     }
 
     public static void init() {
         System.loadLibrary("cts_dexchecker");
     }
 
-    public static void checkSingleMember(DexApiDocumentParser.DexMember dexMember,
-            DexMemberChecker.Observer observer) {
+    public static void checkSingleMember(DexMember dexMember, DexMemberChecker.Observer observer) {
         Class<?> klass = findClass(dexMember);
         if (klass == null) {
             // Class not found. Therefore its members are not visible.
@@ -45,17 +43,16 @@
         }
         observer.classAccessible(true, dexMember);
 
-        StringBuilder error = new StringBuilder("Hidden ");
-        if (dexMember instanceof DexApiDocumentParser.DexField) {
-            DexApiDocumentParser.DexField field = (DexApiDocumentParser.DexField) dexMember;
+        if (dexMember instanceof DexField) {
+            DexField field = (DexField) dexMember;
             observer.fieldAccessibleViaReflection(
                     hasMatchingField_Reflection(klass, field),
                     field);
             observer.fieldAccessibleViaJni(
                     hasMatchingField_JNI(klass, field),
                     field);
-        } else if (dexMember instanceof DexApiDocumentParser.DexMethod) {
-            DexApiDocumentParser.DexMethod method = (DexApiDocumentParser.DexMethod) dexMember;
+        } else if (dexMember instanceof DexMethod) {
+            DexMethod method = (DexMethod) dexMember;
             observer.methodAccessibleViaReflection(
                     hasMatchingMethod_Reflection(klass, method),
                     method);
@@ -79,8 +76,7 @@
         return true;
     }
 
-    private static Class<?> findClass(DexApiDocumentParser.DexMember dexMember) {
-        Class<?> klass = null;
+    private static Class<?> findClass(DexMember dexMember) {
         try {
             return Class.forName(dexMember.getJavaClassName());
         } catch (ClassNotFoundException ex) {
@@ -88,8 +84,7 @@
         }
     }
 
-    private static boolean hasMatchingField_Reflection(Class<?> klass,
-            DexApiDocumentParser.DexField dexField) {
+    private static boolean hasMatchingField_Reflection(Class<?> klass, DexField dexField) {
         try {
             klass.getDeclaredField(dexField.getName());
             return true;
@@ -98,8 +93,7 @@
         }
     }
 
-    private static boolean hasMatchingField_JNI(Class<?> klass,
-            DexApiDocumentParser.DexField dexField) {
+    private static boolean hasMatchingField_JNI(Class<?> klass, DexField dexField) {
         try {
             getField_JNI(klass, dexField.getName(), dexField.getDexType());
             return true;
@@ -113,8 +107,7 @@
         return false;
     }
 
-    private static boolean hasMatchingMethod_Reflection(Class<?> klass,
-            DexApiDocumentParser.DexMethod dexMethod) {
+    private static boolean hasMatchingMethod_Reflection(Class<?> klass, DexMethod dexMethod) {
         List<String> methodParams = dexMethod.getJavaParameterTypes();
 
         if (dexMethod.isConstructor()) {
@@ -134,8 +127,7 @@
         return false;
     }
 
-    private static boolean hasMatchingMethod_JNI(Class<?> klass,
-            DexApiDocumentParser.DexMethod dexMethod) {
+    private static boolean hasMatchingMethod_JNI(Class<?> klass, DexMethod dexMethod) {
         try {
             getMethod_JNI(klass, dexMethod.getName(), dexMethod.getDexSignature());
             return true;
diff --git a/tests/signature/src/android/signature/cts/DexMethod.java b/tests/signature/src/android/signature/cts/DexMethod.java
new file mode 100644
index 0000000..ad21c7a
--- /dev/null
+++ b/tests/signature/src/android/signature/cts/DexMethod.java
@@ -0,0 +1,107 @@
+/*
+ * 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.signature.cts;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class DexMethod extends DexMember {
+  private final List<String> mParamTypeList;
+
+  public DexMethod(String className, String name, String signature) {
+      super(className, name, parseDexReturnType(signature));
+      mParamTypeList = parseDexTypeList(signature);
+  }
+
+  public String getDexSignature() {
+      return "(" + String.join("", mParamTypeList) + ")" + getDexType();
+  }
+
+  public List<String> getJavaParameterTypes() {
+      return mParamTypeList.stream().map(DexMember::dexToJavaType).collect(Collectors.toList());
+  }
+
+  public boolean isConstructor() {
+      return "<init>".equals(getName()) && "V".equals(getDexType());
+  }
+
+  public boolean isStaticConstructor() {
+      return "<clinit>".equals(getName()) && "V".equals(getDexType());
+  }
+
+  @Override
+  public String toString() {
+      return getJavaType() + " " + getJavaClassName() + "." + getName()
+              + "(" + String.join(", ", getJavaParameterTypes()) + ")";
+  }
+
+  private static Matcher matchSignature(String signature) {
+      Matcher m = Pattern.compile("^\\((.*)\\)(.*)$").matcher(signature);
+      if (!m.matches()) {
+          throw new RuntimeException("Could not parse method signature: " + signature);
+      }
+      return m;
+  }
+
+  private static String parseDexReturnType(String signature) {
+      return matchSignature(signature).group(2);
+  }
+
+  private static List<String> parseDexTypeList(String signature) {
+      String typeSequence = matchSignature(signature).group(1);
+      List<String> list = new ArrayList<String>();
+      while (!typeSequence.isEmpty()) {
+          String type = firstDexTypeFromList(typeSequence);
+          list.add(type);
+          typeSequence = typeSequence.substring(type.length());
+      }
+      return list;
+  }
+
+  /**
+   * Returns the first dex type in `typeList` or throws a ParserException
+   * if a dex type is not recognized. The input is not changed.
+   */
+  private static String firstDexTypeFromList(String typeList) {
+      String dexDimension = "";
+      while (typeList.startsWith("[")) {
+          dexDimension += "[";
+          typeList = typeList.substring(1);
+      }
+
+      String type = null;
+      if (typeList.startsWith("V")
+              || typeList.startsWith("Z")
+              || typeList.startsWith("B")
+              || typeList.startsWith("C")
+              || typeList.startsWith("S")
+              || typeList.startsWith("I")
+              || typeList.startsWith("J")
+              || typeList.startsWith("F")
+              || typeList.startsWith("D")) {
+          type = typeList.substring(0, 1);
+      } else if (typeList.startsWith("L") && typeList.indexOf(";") > 0) {
+          type = typeList.substring(0, typeList.indexOf(";") + 1);
+      } else {
+          throw new RuntimeException("Unexpected dex type in \"" + typeList + "\"");
+      }
+
+      return dexDimension + type;
+  }
+}
diff --git a/tests/signature/src/android/signature/cts/ExcludingClassProvider.java b/tests/signature/src/android/signature/cts/ExcludingClassProvider.java
index 290cbf5..fd9cc6c 100644
--- a/tests/signature/src/android/signature/cts/ExcludingClassProvider.java
+++ b/tests/signature/src/android/signature/cts/ExcludingClassProvider.java
@@ -45,4 +45,9 @@
         return base.getAllClasses()
                 .filter(clazz -> !testForExclusion.test(clazz.getCanonicalName()));
     }
+
+    @Override
+    public Stream<DexMember> getAllMembers(Class<?> klass) {
+        return base.getAllMembers(klass);
+    }
 }
diff --git a/tests/signature/tests/src/android/signature/cts/tests/TestClassesProvider.java b/tests/signature/tests/src/android/signature/cts/tests/TestClassesProvider.java
index 80176de..6ddcbcf 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/TestClassesProvider.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/TestClassesProvider.java
@@ -18,6 +18,7 @@
 import java.util.stream.Stream;
 
 import android.signature.cts.ClassProvider;
+import android.signature.cts.DexMember;
 import android.signature.cts.tests.data.AbstractClass;
 import android.signature.cts.tests.data.SystemApiClass;
 import android.signature.cts.tests.data.FinalClass;
@@ -46,4 +47,8 @@
         return builder.build();
     }
 
+    @Override
+    public Stream<DexMember> getAllMembers(Class<?> klass) {
+        return null;
+    }
 }
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 2543f4a..084c7b3 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -332,8 +332,12 @@
     public void testManageStorage() {
         assertCanBeHandled(new Intent(StorageManager.ACTION_MANAGE_STORAGE));
     }
- 
+
     public void testVoiceCommand() {
+        if (FeatureUtil.isLowRam()) {
+            // Low ram devices do not support voice command, skip this test
+            return;
+        }
         PackageManager packageManager = mContext.getPackageManager();
         if (packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
             Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
diff --git a/tests/tests/content/src/android/content/cts/ContextMoreTest.java b/tests/tests/content/src/android/content/cts/ContextMoreTest.java
new file mode 100644
index 0000000..545bc43
--- /dev/null
+++ b/tests/tests/content/src/android/content/cts/ContextMoreTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.cts;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ContextMoreTest extends AndroidTestCase {
+    private static final String TAG = "ContextMoreTest";
+
+    /**
+     * Test for {@link Context#getSystemService)}.
+     *
+     * Call it repeatedly from multiple threads, and:
+     * - Make sure getSystemService(ActivityManager) will always return non-null.
+     * - If ContextImpl.mServiceCache is accessible via reflection, clear it once in a while and
+     * make sure getSystemService() still returns non-null.
+     */
+    @LargeTest
+    public void testGetSystemService_multiThreaded() throws Exception {
+        // # of times the tester Runnable has been executed.
+        final AtomicInteger totalCount = new AtomicInteger(0);
+
+        // # of times the tester Runnable has failed.
+        final AtomicInteger failCount = new AtomicInteger(0);
+
+        // Run the threads until this becomes true.
+        final AtomicBoolean stop = new AtomicBoolean(false);
+
+        final Context context = getContext();
+        final Object[] serviceCache = findServiceCache(context);
+        if (serviceCache == null) {
+            Log.w(TAG, "mServiceCache not found.");
+        }
+
+        final Runnable tester = () -> {
+            for (;;) {
+                final int pass = totalCount.incrementAndGet();
+
+                final Object service = context.getSystemService(ActivityManager.class);
+                if (service == null) {
+                    failCount.incrementAndGet(); // Fail!
+                }
+
+                if (stop.get()) {
+                    return;
+                }
+
+                // Yield the CPU.
+                try {
+                    Thread.sleep(0);
+                } catch (InterruptedException e) {
+                }
+
+                // Once in a while, force clear mServiceCache.
+                if ((serviceCache != null) && ((pass % 7) == 0)) {
+                    Arrays.fill(serviceCache, null);
+                }
+            }
+        };
+
+        final int NUM_THREADS = 20;
+
+        // Create and start the threads...
+        final Thread[] threads = new Thread[NUM_THREADS];
+        for (int i = 0; i < NUM_THREADS; i++) {
+            threads[i] = new Thread(tester);
+        }
+        for (int i = 0; i < NUM_THREADS; i++) {
+            threads[i].start();
+        }
+
+        Thread.sleep(10 * 1000);
+
+        stop.set(true);
+
+        // Wait for them to stop...
+        for (int i = 0; i < NUM_THREADS; i++) {
+            threads[i].join();
+        }
+
+        assertEquals(0, failCount.get());
+        assertTrue("totalCount must be bigger than " + NUM_THREADS
+                + " but was " + totalCount.get(), totalCount.get() > NUM_THREADS);
+    }
+
+    /**
+     * Find a field by name using reflection.
+     */
+    private static Object readField(Object instance, String fieldName) {
+        final Field f;
+        try {
+            f = instance.getClass().getDeclaredField(fieldName);
+            f.setAccessible(true);
+            final Object ret = f.get(instance);
+            if (ret == null) {
+                return null;
+            }
+            return ret;
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Try to find the mServiceCache field from a Context. Returns null if none found.
+     */
+    private static Object[] findServiceCache(Context context) {
+        // Find the base context.
+        while (context instanceof ContextWrapper) {
+            context = ((ContextWrapper) context).getBaseContext();
+        }
+        // Try to find the mServiceCache field.
+        final Object serviceCache = readField(context, "mServiceCache");
+        if (serviceCache instanceof Object[]) {
+            return (Object[]) serviceCache;
+        }
+        return null;
+    }
+}
diff --git a/tests/tests/content/src/android/content/cts/TestPagingContentProvider.java b/tests/tests/content/src/android/content/cts/TestPagingContentProvider.java
index 6e38809..2a1d11e 100644
--- a/tests/tests/content/src/android/content/cts/TestPagingContentProvider.java
+++ b/tests/tests/content/src/android/content/cts/TestPagingContentProvider.java
@@ -26,7 +26,6 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.util.Log;
-import android.util.MathUtils;
 
 import javax.annotation.Nullable;
 
@@ -109,7 +108,8 @@
         Bundle extras = c.getExtras();
 
         // Calculate the number of items to include in the cursor.
-        int numItems = MathUtils.constrain(recordsetSize - offset, 0, limit);
+        int numItems = recordsetSize - offset;
+        numItems = numItems < 0 ? 0 : (numItems > limit ? limit : numItems);
 
         // Build the paged result set.
         for (int i = offset; i < offset + numItems; i++) {
diff --git a/tests/tests/keystore/src/android/server/am/ActivityManagerTestBase.java b/tests/tests/keystore/src/android/server/am/ActivityManagerTestBase.java
index bcbd868..87f80b0 100644
--- a/tests/tests/keystore/src/android/server/am/ActivityManagerTestBase.java
+++ b/tests/tests/keystore/src/android/server/am/ActivityManagerTestBase.java
@@ -116,10 +116,6 @@
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getContext();
         mAm = mContext.getSystemService(ActivityManager.class);
-        executeShellCommand("pm grant " + mContext.getPackageName()
-                + " android.permission.MANAGE_ACTIVITY_STACKS");
-        executeShellCommand("pm grant " + mContext.getPackageName()
-                + " android.permission.ACTIVITY_EMBEDDING");
 
         pressWakeupButton();
         pressUnlockButton();
diff --git a/tests/tests/media/res/raw/color_176x144_bt2020_lr_hlg_h265.mp4 b/tests/tests/media/res/raw/color_176x144_bt2020_lr_hlg_h265.mp4
new file mode 100644
index 0000000..748151c
--- /dev/null
+++ b/tests/tests/media/res/raw/color_176x144_bt2020_lr_hlg_h265.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/color_176x144_bt2020_lr_smpte2084_h265.mp4 b/tests/tests/media/res/raw/color_176x144_bt2020_lr_smpte2084_h265.mp4
new file mode 100644
index 0000000..f21237f
--- /dev/null
+++ b/tests/tests/media/res/raw/color_176x144_bt2020_lr_smpte2084_h265.mp4
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 34e8a82..eae9d51 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -352,6 +352,18 @@
                 R.raw.color_176x144_srgb_lr_sdr_h265, 4 /* testId */,
                 MediaFormat.COLOR_RANGE_LIMITED, MediaFormat.COLOR_STANDARD_BT709,
                 2 /* MediaFormat.COLOR_TRANSFER_SRGB */);
+        // Test the main10 streams with surface as the decoder might
+        // support opaque buffers only.
+        testColorAspects(
+                R.raw.color_176x144_bt2020_lr_smpte2084_h265, 5 /* testId */,
+                MediaFormat.COLOR_RANGE_LIMITED, MediaFormat.COLOR_STANDARD_BT2020,
+                MediaFormat.COLOR_TRANSFER_ST2084,
+                getActivity().getSurfaceHolder().getSurface());
+        testColorAspects(
+                R.raw.color_176x144_bt2020_lr_hlg_h265, 6 /* testId */,
+                MediaFormat.COLOR_RANGE_LIMITED, MediaFormat.COLOR_STANDARD_BT2020,
+                MediaFormat.COLOR_TRANSFER_HLG,
+                getActivity().getSurfaceHolder().getSurface());
     }
 
     /**
@@ -392,6 +404,13 @@
     private void testColorAspects(
             int res, int testId, int expectRange, int expectStandard, int expectTransfer)
             throws Exception {
+        testColorAspects(
+                res, testId, expectRange, expectStandard, expectTransfer, null /*surface*/);
+    }
+
+    private void testColorAspects(
+            int res, int testId, int expectRange, int expectStandard, int expectTransfer,
+            Surface surface) throws Exception {
         MediaFormat format = MediaUtils.getTrackFormatForResource(mContext, res, "video");
         MediaFormat mimeFormat = new MediaFormat();
         mimeFormat.setString(MediaFormat.KEY_MIME, format.getString(MediaFormat.KEY_MIME));
@@ -400,21 +419,21 @@
             if (!MediaUtils.supports(decoderName, format)) {
                 MediaUtils.skipTest(decoderName + " cannot play resource " + res);
             } else {
-                testColorAspects(
-                        decoderName, res, testId, expectRange, expectStandard, expectTransfer);
+                testColorAspects(decoderName, res, testId,
+                        expectRange, expectStandard, expectTransfer, surface);
             }
         }
     }
 
     private void testColorAspects(
             String decoderName, int res, int testId, int expectRange,
-            int expectStandard, int expectTransfer) throws Exception {
+            int expectStandard, int expectTransfer, Surface surface) throws Exception {
         AssetFileDescriptor fd = mResources.openRawResourceFd(res);
         MediaExtractor ex = new MediaExtractor();
         ex.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
         MediaFormat format = ex.getTrackFormat(0);
         MediaCodec dec = MediaCodec.createByCodecName(decoderName);
-        dec.configure(format, null, null, 0);
+        dec.configure(format, surface, null, 0);
         dec.start();
         ByteBuffer[] buf = dec.getInputBuffers();
         ex.selectTrack(0);
@@ -494,6 +513,8 @@
         }
         log.submit(getInstrumentation());
 
+        assertTrue(rangeMatch && colorMatch && transferMatch);
+
         dec.release();
         ex.release();
         fd.close();
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
index ff6402c..604ec5f 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
@@ -116,23 +116,31 @@
     EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
 }
 
-// Draws the following checkerboard pattern using glScissor and glClear:
-//        +----+----+ (W, H)
-//        | OR | Ob |
-//        +----+----+  TB = transparent black
-//        | TB | OR |  OR = opaque red
-// (0, 0) +----+----+  Ob = opaque blue
+// Draws the following checkerboard pattern using glScissor and glClear.
+// The number is the depth value.
+//        +-----+-----+ (W, H)
+//        | OR  | Ob  |
+//        | 0.5 | 0.0 |
+//        +-----+-----+  TB = transparent black
+//        | TB  | OR  |  OR = opaque red
+//        | 1.0 | 0.5 |  Ob = opaque blue
+// (0, 0) +-----+-----+
+//
 void DrawCheckerboard(int width, int height) {
     glEnable(GL_SCISSOR_TEST);
     glClearColor(1.f, 0.f, 0.f, 1.f);
+    glClearDepthf(0.5f);
     glScissor(0, 0, width, height);
-    glClear(GL_COLOR_BUFFER_BIT);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glClearColor(0.f, 0.f, 0.f, 0.f);
+    glClearDepthf(1.0f);
     glScissor(0, 0, width / 2, height / 2);
-    glClear(GL_COLOR_BUFFER_BIT);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glClearColor(0.f, 0.f, 1.f, 1.f);
+    glClearDepthf(0.f);
     glScissor(width / 2, height / 2, width / 2, height / 2);
-    glClear(GL_COLOR_BUFFER_BIT);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    glDisable(GL_SCISSOR_TEST);
 }
 
 void CompileProgram(const char* vertex_source, const char* fragment_source, GLuint* program_out) {
@@ -175,22 +183,28 @@
 
 void CheckGoldenPixel(const GoldenPixel& golden, uint8_t* pixel, bool alpha_format) {
     EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
-    EXPECT_EQ(golden.color == kRed ? 255 : 0, pixel[0]);
-    EXPECT_EQ(0, pixel[1]);
-    EXPECT_EQ(golden.color == kBlue ? 255 : 0, pixel[2]);
+    EXPECT_EQ(golden.color == kRed ? 255 : 0, pixel[0])
+        << "Red doesn't match at X=" << golden.x << ", Y=" << golden.y;
+    EXPECT_EQ(0, pixel[1])
+        << "Green doesn't match at X=" << golden.x << ", Y=" << golden.y;
+    EXPECT_EQ(golden.color == kBlue ? 255 : 0, pixel[2])
+        << "Blue doesn't match at X=" << golden.x << ", Y=" << golden.y;
     // Formats without alpha should be read as opaque.
-    EXPECT_EQ((golden.color != kZero || !alpha_format) ? 255 : 0,
-              pixel[3]);
+    EXPECT_EQ((golden.color != kZero || !alpha_format) ? 255 : 0, pixel[3])
+        << "Alpha doesn't match at X=" << golden.x << ", Y=" << golden.y;
 }
 
 void CheckGoldenPixel(const GoldenPixel& golden, float* pixel, bool alpha_format) {
     EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
-    EXPECT_EQ(golden.color == kRed ? 1.f : 0.f, pixel[0]);
-    EXPECT_EQ(0.f, pixel[1]);
-    EXPECT_EQ(golden.color == kBlue ? 1.f : 0.f, pixel[2]);
+    EXPECT_EQ(golden.color == kRed ? 1.f : 0.f, pixel[0])
+        << "Red doesn't match at X=" << golden.x << ", Y=" << golden.y;
+    EXPECT_EQ(0.f, pixel[1])
+        << "Green doesn't match at X=" << golden.x << ", Y=" << golden.y;
+    EXPECT_EQ(golden.color == kBlue ? 1.f : 0.f, pixel[2])
+        << "Blue doesn't match at X=" << golden.x << ", Y=" << golden.y;
     // Formats without alpha should be read as opaque.
-    EXPECT_EQ((golden.color != kZero || !alpha_format) ? 1.f : 0.f,
-              pixel[3]);
+    EXPECT_EQ((golden.color != kZero || !alpha_format) ? 1.f : 0.f, pixel[3])
+        << "Alpha doesn't match at X=" << golden.x << ", Y=" << golden.y;
 }
 
 void CheckGoldenPixels(const std::vector<GoldenPixel>& goldens, bool float_format, bool alpha_format) {
@@ -239,16 +253,17 @@
     #version 100
     attribute vec2 aPosition;
     attribute float aDepth;
+    uniform mediump float uScale;
     varying mediump vec2 vTexCoords;
     void main() {
         vTexCoords = (vec2(1.0) + aPosition) * 0.5;
-        gl_Position.xy = aPosition * 0.5;
+        gl_Position.xy = aPosition * uScale;
         gl_Position.z = aDepth;
         gl_Position.w = 1.0;
     }
 )glsl";
 
-const char* kFragmentShader = R"glsl(
+const char* kTextureFragmentShader = R"glsl(
     #version 100
     precision mediump float;
     varying mediump vec2 vTexCoords;
@@ -258,14 +273,24 @@
     }
 )glsl";
 
+const char* kColorFragmentShader = R"glsl(
+    #version 100
+    precision mediump float;
+    uniform lowp vec4 uColor;
+    void main() {
+        gl_FragColor = uColor;
+    }
+)glsl";
+
 const char* kVertexShaderEs3 = R"glsl(
     #version 300 es
     in vec2 aPosition;
     in float aDepth;
+    uniform mediump float uScale;
     out mediump vec2 vTexCoords;
     void main() {
         vTexCoords = (vec2(1.0) + aPosition) * 0.5;
-        gl_Position.xy = aPosition * 0.5;
+        gl_Position.xy = aPosition * uScale;
         gl_Position.z = aDepth;
         gl_Position.w = 1.0;
     }
@@ -277,7 +302,7 @@
     in mediump vec2 vTexCoords;
     uniform lowp sampler2DArray uTexture;
     uniform mediump float uLayer;
-    out lowp vec4 color;
+    out mediump vec4 color;
     void main() {
         color = texture(uTexture, vec3(vTexCoords, uLayer));
     }
@@ -295,23 +320,29 @@
 // It looks like this:
 //
 //        +---+ 1, 1
-//        |\ /| 
+//        |\ /|
 //        | x |
 //        |/ \|
 // -1, -1 +---+
-/*const float kPyramidPositions[] = {
+const float kPyramidPositions[] = {
     -1.f, -1.f, -1.f, 0.f, 0.f, 1.f, -1.f, 1.f, -1.f,
     -1.f, 1.f, -1.f, 0.f, 0.f, 1.f, 1.f, 1.f, -1.f,
     1.f, 1.f, -1.f, 0.f, 0.f, 1.f, 1.f, -1.f, -1.f,
     1.f, -1.f, -1.f, 0.f, 0.f, 1.f, -1.f, -1.f, -1.f,
-};*/
+};
 
 }  // namespace
 
-class AHardwareBufferGLTest : public ::testing::Test {
+class AHardwareBufferGLTest : public ::testing::TestWithParam<AHardwareBuffer_Desc> {
 public:
     void SetUp() override;
+    virtual bool SetUpBuffer(const AHardwareBuffer_Desc& desc);
+    void TearDownBuffer();
     void TearDown() override;
+    void MakeCurrent(int which) {
+        if (GetParam().stride != 0) return;
+        eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[which]);
+    }
 
 protected:
     std::set<std::string> mEGLExtensions;
@@ -319,6 +350,10 @@
     EGLSurface mSurface = EGL_NO_SURFACE;
     EGLContext mContext[2];
     int mGLVersion = 0;
+
+    AHardwareBuffer* mBuffer = nullptr;
+    EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
+    GLenum mTexTarget = GL_NONE;
 };
 
 void AHardwareBufferGLTest::SetUp() {
@@ -374,6 +409,34 @@
     ASSERT_EQ(EGLBoolean{EGL_TRUE}, result);
 }
 
+bool AHardwareBufferGLTest::SetUpBuffer(const AHardwareBuffer_Desc& desc) {
+    mTexTarget = desc.layers > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
+    if (desc.layers > 1 && mGLVersion < 3) return false;
+    // Nonzero stride indicates that desc.format should be interpreted as a GL format
+    // and the test should be run in a single context, without using AHardwareBuffer.
+    // This simplifies verifying that the test behaves as expected even if the
+    // AHardwareBuffer format under test is not supported.
+    if (desc.stride != 0) return true;
+
+    int result = AHardwareBuffer_allocate(&desc, &mBuffer);
+    // Skip if this format cannot be allocated.
+    if (result != NO_ERROR) return false;
+
+    const EGLint attrib_list[] = { EGL_NONE };
+    mEGLImage = eglCreateImageKHR(
+        mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+        eglGetNativeClientBufferANDROID(mBuffer), attrib_list);
+    EXPECT_NE(EGL_NO_IMAGE_KHR, mEGLImage);
+    return mEGLImage != EGL_NO_IMAGE_KHR;
+}
+
+void AHardwareBufferGLTest::TearDownBuffer() {
+    if (mBuffer != nullptr) {
+        eglDestroyImageKHR(mDisplay, mEGLImage);
+        AHardwareBuffer_release(mBuffer);
+    }
+}
+
 void AHardwareBufferGLTest::TearDown() {
     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     for (int i = 0; i < 2; ++i) {
@@ -385,39 +448,27 @@
     eglTerminate(mDisplay);
 }
 
-class AHardwareBufferColorFormatTest
-    : public AHardwareBufferGLTest,
-      public ::testing::WithParamInterface<AHardwareBuffer_Desc> {};
+class AHardwareBufferColorFormatTest : public AHardwareBufferGLTest {};
 
 // Verify that when allocating an AHardwareBuffer succeeds with GPU_COLOR_OUTPUT,
 // it can be bound as a framebuffer attachment, glClear'ed and then read from
 // another context using glReadPixels.
 TEST_P(AHardwareBufferColorFormatTest, GpuColorOutputIsRenderable) {
-    AHardwareBuffer* buffer = NULL;
     AHardwareBuffer_Desc desc = GetParam();
     desc.width = 100;
     desc.height = 100;
     desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
     // This test does not make sense for layered buffers - don't bother testing them.
     if (desc.layers > 1) return;
-
-    int result = AHardwareBuffer_allocate(&desc, &buffer);
-    // Skip if this format cannot be allocated.
-    if (result != NO_ERROR) return;
-
-    const EGLint attrib_list[] = { EGL_NONE };
-    EGLImageKHR egl_image = eglCreateImageKHR(
-        mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-        eglGetNativeClientBufferANDROID(buffer), attrib_list);
-    ASSERT_NE(EGL_NO_IMAGE_KHR, egl_image);
+    if (!SetUpBuffer(desc)) return;
 
     // Bind the EGLImage to renderbuffers and framebuffers in both contexts.
     GLuint renderbuffer[2], fbo[2];
     for (int i = 0; i < 2; ++i) {
-        eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[i]);
+        MakeCurrent(i);
         glGenRenderbuffers(1, &renderbuffer[i]);
         glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[i]);
-        glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, static_cast<GLeglImageOES>(egl_image));
+        glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, static_cast<GLeglImageOES>(mEGLImage));
         EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
         glGenFramebuffers(1, &fbo[i]);
         glBindFramebuffer(GL_FRAMEBUFFER, fbo[i]);
@@ -432,7 +483,7 @@
     glFinish();
     EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
 
-    eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[0]);
+    MakeCurrent(0);
     std::vector<GoldenPixel> goldens{
         {10, 90, kRed},  {40, 90, kRed},  {60, 90, kBlue}, {90, 90, kBlue},
         {10, 60, kRed},  {40, 60, kRed},  {60, 60, kBlue}, {90, 60, kBlue},
@@ -443,43 +494,29 @@
 
     // Clean up GL objects
     for (int i = 0; i < 2; ++i) {
-        eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[i]);
+        MakeCurrent(i);
         glDeleteFramebuffers(1, &fbo[i]);
         glDeleteRenderbuffers(1, &renderbuffer[i]);
     }
-    eglDestroyImageKHR(mDisplay, egl_image);
-    AHardwareBuffer_release(buffer);
+    TearDownBuffer();
 }
 
 // Verify that when allocating an AHardwareBuffer succeeds with GPU_SAMPLED_IMAGE,
 // it can be bound as a texture, set to a color with glTexSubImage2D and sampled
 // from in a fragment shader.
 TEST_P(AHardwareBufferColorFormatTest, GpuSampledImageCanBeSampled) {
-    AHardwareBuffer* buffer = NULL;
     AHardwareBuffer_Desc desc = GetParam();
     desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
-
-    // Skip texture arrays if the device doesn't support OpenGL ES 3.
-    if (desc.layers > 1 && mGLVersion < 3) return;
-    const GLenum textarget = desc.layers > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
-
-    int result = AHardwareBuffer_allocate(&desc, &buffer);
-    // Skip if this format cannot be allocated.
-    if (result != NO_ERROR) return;
-
-    const EGLint attrib_list[] = { EGL_NONE };
-    EGLImageKHR egl_image = eglCreateImageKHR(
-        mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-        eglGetNativeClientBufferANDROID(buffer), attrib_list);
+    if (!SetUpBuffer(desc)) return;
 
     // Bind the EGLImage to textures in both contexts.
     GLuint texture[2];
     for (int i = 0; i < 2; ++i) {
-        eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[i]);
+        MakeCurrent(i);
         glGenTextures(1, &texture[i]);
         glActiveTexture(GL_TEXTURE1);
-        glBindTexture(textarget, texture[i]);
-        glEGLImageTargetTexture2DOES(textarget, static_cast<GLeglImageOES>(egl_image));
+        glBindTexture(mTexTarget, texture[i]);
+        glEGLImageTargetTexture2DOES(mTexTarget, static_cast<GLeglImageOES>(mEGLImage));
         EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
     }
     // In the second context, upload opaque red to the texture.
@@ -487,13 +524,13 @@
     glFinish();
 
     // In the first context, draw a quad that samples from the texture.
-    eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[0]);
+    MakeCurrent(0);
     GLuint fbo, renderbuffer;
     glGenFramebuffers(1, &fbo);
     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
     glGenRenderbuffers(1, &renderbuffer);
     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
-    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 40, 40);
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 40, 40);
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
     ASSERT_EQ(GLenum{GL_FRAMEBUFFER_COMPLETE}, glCheckFramebufferStatus(GL_FRAMEBUFFER));
     glClearColor(0.f, 0.f, 0.f, 0.f);
@@ -502,7 +539,7 @@
     // Compile the shader.
     GLuint program = 0;
     CompileProgram(desc.layers > 1 ? kVertexShaderEs3 : kVertexShader,
-                   desc.layers > 1 ? kArrayFragmentShaderEs3 : kFragmentShader,
+                   desc.layers > 1 ? kArrayFragmentShaderEs3 : kTextureFragmentShader,
                    &program);
     glUseProgram(program);
     EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
@@ -514,6 +551,7 @@
     glVertexAttrib1f(a_depth_location, 0.f);
     glEnableVertexAttribArray(a_position_location);
     glUniform1i(glGetUniformLocation(program, "uTexture"), 1);
+    glUniform1f(glGetUniformLocation(program, "uScale"), 0.5f);
     if (desc.layers > 1) {
         glUniform1f(glGetUniformLocation(program, "uLayer"), static_cast<float>(desc.layers - 1));
     }
@@ -535,41 +573,26 @@
     glDeleteFramebuffers(1, &fbo);
     glDeleteRenderbuffers(1, &renderbuffer);
     glDeleteTextures(1, &texture[0]);
-    eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[1]);
+    MakeCurrent(1);
     glDeleteTextures(1, &texture[1]);
-    eglDestroyImageKHR(mDisplay, egl_image);
-    AHardwareBuffer_release(buffer);
+    TearDownBuffer();
 }
 
 // Verify that buffers which have both GPU_SAMPLED_IMAGE and GPU_COLOR_OUTPUT
 // can be both rendered and sampled as a texture.
 TEST_P(AHardwareBufferColorFormatTest, GpuColorOutputAndSampledImage) {
-    AHardwareBuffer* buffer = NULL;
     AHardwareBuffer_Desc desc = GetParam();
     desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
-
-    // Skip texture arrays if the device doesn't support OpenGL ES 3.
-    if (desc.layers > 1 && mGLVersion < 3) return;
-    const GLenum textarget = desc.layers > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
-
-    int result = AHardwareBuffer_allocate(&desc, &buffer);
-    // Skip if this format cannot be allocated.
-    if (result != NO_ERROR) return;
-
-    const EGLint attrib_list[] = { EGL_NONE };
-    EGLImageKHR egl_image = eglCreateImageKHR(
-        mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-        eglGetNativeClientBufferANDROID(buffer), attrib_list);
-    ASSERT_NE(EGL_NO_IMAGE_KHR, egl_image);
+    if (!SetUpBuffer(desc)) return;
 
     // Bind the EGLImage to textures in both contexts.
     GLuint texture[2];
     for (int i = 0; i < 2; ++i) {
-        eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[i]);
+        MakeCurrent(i);
         glGenTextures(1, &texture[i]);
         glActiveTexture(GL_TEXTURE1);
-        glBindTexture(textarget, texture[i]);
-        glEGLImageTargetTexture2DOES(textarget, static_cast<GLeglImageOES>(egl_image));
+        glBindTexture(mTexTarget, texture[i]);
+        glEGLImageTargetTexture2DOES(mTexTarget, static_cast<GLeglImageOES>(mEGLImage));
         EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
     }
 
@@ -590,13 +613,13 @@
     EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
 
     // In the first context, draw a quad that samples from the texture.
-    eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[0]);
+    MakeCurrent(0);
     GLuint fbo, renderbuffer;
     glGenFramebuffers(1, &fbo);
     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
     glGenRenderbuffers(1, &renderbuffer);
     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
-    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 40, 40);
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 40, 40);
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
     ASSERT_EQ(GLenum{GL_FRAMEBUFFER_COMPLETE}, glCheckFramebufferStatus(GL_FRAMEBUFFER));
     glClearColor(0.f, 0.f, 0.f, 0.f);
@@ -605,7 +628,7 @@
     // Compile the shader.
     GLuint program = 0;
     CompileProgram(desc.layers > 1 ? kVertexShaderEs3 : kVertexShader,
-                   desc.layers > 1 ? kArrayFragmentShaderEs3 : kFragmentShader,
+                   desc.layers > 1 ? kArrayFragmentShaderEs3 : kTextureFragmentShader,
                    &program);
     glUseProgram(program);
     EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
@@ -617,6 +640,7 @@
     glVertexAttrib1f(a_depth_location, 0.f);
     glEnableVertexAttribArray(a_position_location);
     glUniform1i(glGetUniformLocation(program, "uTexture"), 1);
+    glUniform1f(glGetUniformLocation(program, "uScale"), 0.5f);
     if (desc.layers > 1) {
         glUniform1f(glGetUniformLocation(program, "uLayer"), static_cast<float>(desc.layers - 1));
     }
@@ -641,11 +665,10 @@
     glDeleteFramebuffers(1, &fbo);
     glDeleteRenderbuffers(1, &renderbuffer);
     glDeleteTextures(1, &texture[0]);
-    eglMakeCurrent(mDisplay, mSurface, mSurface, mContext[1]);
+    MakeCurrent(1);
     glDeleteFramebuffers(1, &texture_fbo);
     glDeleteTextures(1, &texture[1]);
-    eglDestroyImageKHR(mDisplay, egl_image);
-    AHardwareBuffer_release(buffer);
+    TearDownBuffer();
 }
 
 INSTANTIATE_TEST_CASE_P(
@@ -671,4 +694,218 @@
         AHardwareBuffer_Desc{20, 20, 4, AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT, 0, 0, 0, 0},
         AHardwareBuffer_Desc{30, 20, 16, AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM, 0, 0, 0, 0}));
 
+
+class AHardwareBufferDepthFormatTest : public AHardwareBufferGLTest {
+public:
+    bool SetUpBuffer(const AHardwareBuffer_Desc& desc) override {
+        // ES 2.0 only supports GL_DEPTH_COMPONENT16 for depth renderbuffers.
+        if (desc.stride != 0 && mGLVersion < 3 && desc.format != GL_DEPTH_COMPONENT16) return false;
+        return AHardwareBufferGLTest::SetUpBuffer(desc);
+    }
+};
+
+// Verify that depth testing against a depth buffer rendered in another context
+// works correctly.
+TEST_P(AHardwareBufferDepthFormatTest, DepthAffectsDrawAcrossContexts) {
+    AHardwareBuffer_Desc desc = GetParam();
+    desc.width = 40;
+    desc.height = 40;
+    desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
+    // This test does not make sense for layered buffers - don't bother testing them.
+    if (desc.layers > 1) return;
+    if (!SetUpBuffer(desc)) return;
+
+    // Bind the EGLImage to renderbuffers and framebuffers in both contexts.
+    // The depth buffer is shared, but the color buffer is not.
+    GLuint fbo[2], color_rb[2], depth_rb[2];
+    for (int i = 0; i < 2; ++i) {
+        MakeCurrent(i);
+        glGenFramebuffers(1, &fbo[i]);
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo[i]);
+        glGenRenderbuffers(1, &color_rb[i]);
+        glBindRenderbuffer(GL_RENDERBUFFER, color_rb[i]);
+        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 40, 40);
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_rb[i]);
+        glGenRenderbuffers(1, &depth_rb[i]);
+        glBindRenderbuffer(GL_RENDERBUFFER, depth_rb[i]);
+        if (desc.stride == 0) {
+            glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, static_cast<GLeglImageOES>(mEGLImage));
+        } else {
+            glRenderbufferStorage(GL_RENDERBUFFER, desc.format, 40, 40);
+        }
+        EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rb[i]);
+        ASSERT_EQ(GLenum{GL_FRAMEBUFFER_COMPLETE},
+                  glCheckFramebufferStatus(GL_FRAMEBUFFER));
+    }
+
+    // In the second context, clear the depth buffer to a checkerboard pattern.
+    DrawCheckerboard(40, 40);
+    glFinish();
+    EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
+
+    // In the first context, clear the color buffer only, then draw a red pyramid.
+    MakeCurrent(0);
+    glClearColor(0.f, 0.f, 0.f, 0.f);
+    glClear(GL_COLOR_BUFFER_BIT);
+    GLuint program = 0;
+    CompileProgram(kVertexShader, kColorFragmentShader, &program);
+    glUseProgram(program);
+    EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
+
+    GLint a_position_location = glGetAttribLocation(program, "aPosition");
+    GLint a_depth_location = glGetAttribLocation(program, "aDepth");
+    glVertexAttribPointer(a_position_location, 2, GL_FLOAT, GL_TRUE, 3 * sizeof(float), kPyramidPositions);
+    glVertexAttribPointer(a_depth_location, 1, GL_FLOAT, GL_TRUE, 3 * sizeof(float), kPyramidPositions + 2);
+    glEnableVertexAttribArray(a_position_location);
+    glEnableVertexAttribArray(a_depth_location);
+    glUniform4f(glGetUniformLocation(program, "uColor"), 1.f, 0.f, 0.f, 1.f);
+    glUniform1f(glGetUniformLocation(program, "uScale"), 1.0f);
+    glViewport(0, 0, 40, 40);
+    glEnable(GL_DEPTH_TEST);
+    glDepthFunc(GL_LESS);
+    glDrawArrays(GL_TRIANGLES, 0, 12);
+    EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
+    glFinish();
+
+    // Check golden pixels.
+    std::vector<GoldenPixel> goldens{
+        {5, 35, kRed}, {15, 35, kRed},  {25, 35, kZero}, {35, 35, kZero},
+        {5, 25, kRed}, {15, 25, kZero}, {25, 25, kZero}, {35, 25, kZero},
+        {5, 15, kRed}, {15, 15, kRed},  {25, 15, kZero}, {35, 15, kRed},
+        {5, 5,  kRed}, {15, 5,  kRed},  {25, 5,  kRed},  {35, 5,  kRed},
+    };
+    CheckGoldenPixels(goldens, /*float_format=*/false, /*alpha_format=*/true);
+
+    // Tear down the GL objects.
+    glDeleteProgram(program);
+    for (int i = 0; i < 2; ++i) {
+        MakeCurrent(i);
+        glDeleteFramebuffers(1, &fbo[i]);
+        glDeleteRenderbuffers(1, &color_rb[i]);
+        glDeleteRenderbuffers(1, &depth_rb[i]);
+    }
+    TearDownBuffer();
+}
+
+// Verify that depth buffers with usage GPU_SAMPLED_IMAGE can be used as textures.
+TEST_P(AHardwareBufferDepthFormatTest, DepthCanBeSampled) {
+    AHardwareBuffer_Desc desc = GetParam();
+    desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    // ES 2.0 does not support depth textures. There is an extension OES_depth_texture, but it is
+    // incompatible with ES 3.x depth texture support.
+    if (mGLVersion < 3) return;
+    if (!SetUpBuffer(desc)) return;
+
+    // Bind the EGLImage to renderbuffers and framebuffers in both contexts.
+    // The depth buffer is shared, but the color buffer is not.
+    GLuint fbo[2], depth_texture[2], color_rb;
+    for (int i = 0; i < 2; ++i) {
+        MakeCurrent(i);
+        glGenFramebuffers(1, &fbo[i]);
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo[i]);
+        glGenTextures(1, &depth_texture[i]);
+        glActiveTexture(GL_TEXTURE3);
+        glBindTexture(mTexTarget, depth_texture[i]);
+        if (desc.stride == 0) {
+            glEGLImageTargetTexture2DOES(mTexTarget, static_cast<GLeglImageOES>(mEGLImage));
+        } else {
+            if (desc.layers > 1) {
+                glTexStorage3D(mTexTarget, 1, desc.format, desc.width, desc.height, desc.layers);
+            } else {
+                glTexStorage2D(mTexTarget, 1, desc.format, desc.width, desc.height);
+            }
+        }
+        glTexParameteri(mTexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(mTexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
+    }
+
+    // In the second context, attach the depth texture to the framebuffer and clear to 1.
+    if (desc.layers > 1) {
+        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture[1], 0, desc.layers - 1);
+    } else {
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mTexTarget, depth_texture[1], 0);
+    }
+    ASSERT_EQ(GLenum{GL_FRAMEBUFFER_COMPLETE},
+              glCheckFramebufferStatus(GL_FRAMEBUFFER));
+    glClearDepthf(1.f);
+    glClear(GL_DEPTH_BUFFER_BIT);
+    glFinish();
+
+    // In the first context, draw a quad using the depth texture.
+    MakeCurrent(0);
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
+    glGenRenderbuffers(1, &color_rb);
+    glBindRenderbuffer(GL_RENDERBUFFER, color_rb);
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 40, 40);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_rb);
+    ASSERT_EQ(GLenum{GL_FRAMEBUFFER_COMPLETE},
+                  glCheckFramebufferStatus(GL_FRAMEBUFFER));
+
+    glClearColor(0.f, 0.f, 0.f, 0.f);
+    glClear(GL_COLOR_BUFFER_BIT);
+    GLuint program = 0;
+    CompileProgram(desc.layers > 1 ? kVertexShaderEs3 : kVertexShader,
+                   desc.layers > 1 ? kArrayFragmentShaderEs3 : kTextureFragmentShader,
+                   &program);
+    glUseProgram(program);
+    EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
+
+    GLint a_position_location = glGetAttribLocation(program, "aPosition");
+    GLint a_depth_location = glGetAttribLocation(program, "aDepth");
+    glVertexAttribPointer(a_position_location, 2, GL_FLOAT, GL_TRUE, 0, kQuadPositions);
+    glVertexAttrib1f(a_depth_location, 0.f);
+    glEnableVertexAttribArray(a_position_location);
+    glUniform1i(glGetUniformLocation(program, "uTexture"), 3);
+    glUniform1f(glGetUniformLocation(program, "uScale"), 0.5f);
+    if (desc.layers > 1) {
+        glUniform1f(glGetUniformLocation(program, "uLayer"), static_cast<float>(desc.layers - 1));
+    }
+    glViewport(0, 0, 40, 40);
+    glDrawArrays(GL_TRIANGLES, 0, 12);
+    EXPECT_EQ(GLenum{GL_NO_ERROR}, glGetError());
+    glFinish();
+
+    // Check the rendered pixels. There should be a red square in the middle.
+    std::vector<GoldenPixel> goldens{
+        {5, 35, kZero}, {15, 35, kZero}, {25, 35, kZero}, {35, 35, kZero},
+        {5, 25, kZero}, {15, 25, kRed},  {25, 25, kRed},  {35, 25, kZero},
+        {5, 15, kZero}, {15, 15, kRed},  {25, 15, kRed},  {35, 15, kZero},
+        {5,  5, kZero}, {15,  5, kZero}, {25, 5,  kZero}, {35, 5,  kZero},
+    };
+    CheckGoldenPixels(goldens, /*float_format=*/false, /*alpha_format=*/true);
+
+    glDeleteRenderbuffers(1, &color_rb);
+    for (int i = 0; i < 2; ++i) {
+        MakeCurrent(i);
+        glDeleteTextures(1, &depth_texture[i]);
+        glDeleteFramebuffers(1, &fbo[i]);
+    }
+}
+
+// See comment in SetUpBuffer for explanation of nonzero stride and GL format.
+INSTANTIATE_TEST_CASE_P(
+    SingleLayer,
+    AHardwareBufferDepthFormatTest,
+    ::testing::Values(
+        AHardwareBuffer_Desc{16, 24, 1, GL_DEPTH_COMPONENT16, 0, 1, 0, 0},
+        AHardwareBuffer_Desc{16, 24, 1, AHARDWAREBUFFER_FORMAT_D16_UNORM, 0, 0, 0, 0},
+        AHardwareBuffer_Desc{44, 21, 1, AHARDWAREBUFFER_FORMAT_D24_UNORM, 0, 0, 0, 0},
+        AHardwareBuffer_Desc{57, 33, 1, AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT, 0, 0, 0, 0},
+        AHardwareBuffer_Desc{20, 10, 1, AHARDWAREBUFFER_FORMAT_D32_FLOAT, 0, 0, 0, 0},
+        AHardwareBuffer_Desc{57, 33, 1, AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT, 0, 0, 0, 0}));
+
+
+INSTANTIATE_TEST_CASE_P(
+    MultipleLayers,
+    AHardwareBufferDepthFormatTest,
+    ::testing::Values(
+        AHardwareBuffer_Desc{16, 24, 6, GL_DEPTH_COMPONENT16, 0, 1, 0, 0},
+        AHardwareBuffer_Desc{16, 24, 6, AHARDWAREBUFFER_FORMAT_D16_UNORM, 0, 0, 0, 0},
+        AHardwareBuffer_Desc{44, 21, 4, AHARDWAREBUFFER_FORMAT_D24_UNORM, 0, 0, 0, 0},
+        AHardwareBuffer_Desc{57, 33, 7, AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT, 0, 0, 0, 0},
+        AHardwareBuffer_Desc{20, 10, 5, AHARDWAREBUFFER_FORMAT_D32_FLOAT, 0, 0, 0, 0},
+        AHardwareBuffer_Desc{57, 33, 3, AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT, 0, 0, 0, 0}));
+
 }  // namespace android
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferTest.cpp
index f48b766..324ab9e 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferTest.cpp
@@ -320,4 +320,35 @@
     AHardwareBuffer_release(buffer);
 }
 
+TEST(AHardwareBufferTest, ProtectedContentAndCpuReadIncompatible) {
+    AHardwareBuffer* buffer = NULL;
+    AHardwareBuffer_Desc desc = {};
+    desc.width = 120;
+    desc.width = 240;
+    desc.layers = 1;
+    desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
+    desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+
+    // Allocation of a CPU-readable buffer should succeed...
+    int err = AHardwareBuffer_allocate(&desc, &buffer);
+    EXPECT_EQ(NO_ERROR, err);
+    AHardwareBuffer_release(buffer);
+    buffer = nullptr;
+
+    // ...but not if it's a protected buffer.
+    desc.usage =
+        AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+        AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+        AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
+    err = AHardwareBuffer_allocate(&desc, &buffer);
+    EXPECT_NE(NO_ERROR, err);
+
+    desc.usage =
+        AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+        AHARDWAREBUFFER_USAGE_CPU_READ_RARELY |
+        AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
+    err = AHardwareBuffer_allocate(&desc, &buffer);
+    EXPECT_NE(NO_ERROR, err);
+}
+
 } // namespace android
diff --git a/tests/tests/nativehardware/src/android/hardware/cts/HardwareBufferVrTest.java b/tests/tests/nativehardware/src/android/hardware/cts/HardwareBufferVrTest.java
index 922fc91..daf0a82 100644
--- a/tests/tests/nativehardware/src/android/hardware/cts/HardwareBufferVrTest.java
+++ b/tests/tests/nativehardware/src/android/hardware/cts/HardwareBufferVrTest.java
@@ -29,22 +29,27 @@
         if (!pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
             return;
         }
-
         final long flags = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT;
-        HardwareBuffer buffer = HardwareBuffer.create(
-            2, 4, HardwareBuffer.RGBA_8888, 2, flags);
-        assertEquals(2, buffer.getWidth());
-        assertEquals(4, buffer.getHeight());
-        assertEquals(2, buffer.getLayers());
-        assertEquals(HardwareBuffer.RGBA_8888, buffer.getFormat());
-        assertEquals(flags, buffer.getUsage());
+        final int formats[] = {
+            HardwareBuffer.RGB_565,
+            HardwareBuffer.RGBA_8888,
+            HardwareBuffer.RGBA_1010102,
+            HardwareBuffer.RGBA_FP16,
+        };
+        for (final int format : formats) {
+            HardwareBuffer buffer = HardwareBuffer.create(2, 4, format, 2, flags);
+            assertEquals(2, buffer.getWidth());
+            assertEquals(4, buffer.getHeight());
+            assertEquals(2, buffer.getLayers());
+            assertEquals(format, buffer.getFormat());
+            assertEquals(flags, buffer.getUsage());
 
-        buffer = HardwareBuffer.create(
-            4, 12, HardwareBuffer.RGB_565, 3, flags);
-        assertEquals(4, buffer.getWidth());
-        assertEquals(12, buffer.getHeight());
-        assertEquals(3, buffer.getLayers());
-        assertEquals(HardwareBuffer.RGB_565, buffer.getFormat());
-        assertEquals(flags, buffer.getUsage());
+            buffer = HardwareBuffer.create(345, 231, format, 5, flags);
+            assertEquals(345, buffer.getWidth());
+            assertEquals(231, buffer.getHeight());
+            assertEquals(5, buffer.getLayers());
+            assertEquals(format, buffer.getFormat());
+            assertEquals(flags, buffer.getUsage());
+        }
     }
 }
diff --git a/tests/tests/net/src/android/net/cts/NetworkRequestTest.java b/tests/tests/net/src/android/net/cts/NetworkRequestTest.java
index c862c77..2a5ef31 100644
--- a/tests/tests/net/src/android/net/cts/NetworkRequestTest.java
+++ b/tests/tests/net/src/android/net/cts/NetworkRequestTest.java
@@ -30,6 +30,35 @@
                 .hasCapability(NET_CAPABILITY_MMS));
     }
 
+    public void testUnwantedCapabilities() {
+        assertTrue(new NetworkRequest.Builder()
+                .addUnwantedCapability(NET_CAPABILITY_MMS)
+                .build()
+                .hasUnwantedCapability(NET_CAPABILITY_MMS));
+        assertFalse(new NetworkRequest.Builder()
+                .removeCapability(NET_CAPABILITY_MMS)
+                .build()
+                .hasCapability(NET_CAPABILITY_MMS));
+    }
+
+    public void testCapabilityMutualExclusivity() {
+        NetworkRequest.Builder reqBuilder = new NetworkRequest.Builder()
+                .addCapability(NET_CAPABILITY_MMS);
+
+        assertTrue(reqBuilder.build().hasCapability(NET_CAPABILITY_MMS));
+        assertFalse(reqBuilder.build().hasUnwantedCapability(NET_CAPABILITY_MMS));
+
+        // Move capability to unwanted list
+        reqBuilder.addUnwantedCapability(NET_CAPABILITY_MMS);
+        assertFalse(reqBuilder.build().hasCapability(NET_CAPABILITY_MMS));
+        assertTrue(reqBuilder.build().hasUnwantedCapability(NET_CAPABILITY_MMS));
+
+        // Move it back to the list of capabilities
+        reqBuilder.addCapability(NET_CAPABILITY_MMS);
+        assertTrue(reqBuilder.build().hasCapability(NET_CAPABILITY_MMS));
+        assertFalse(reqBuilder.build().hasUnwantedCapability(NET_CAPABILITY_MMS));
+    }
+
     public void testTransports() {
         assertTrue(new NetworkRequest.Builder().addTransportType(TRANSPORT_BLUETOOTH).build()
                 .hasTransport(TRANSPORT_BLUETOOTH));
diff --git a/tests/tests/secure_element/Android.mk b/tests/tests/secure_element/Android.mk
new file mode 100644
index 0000000..5c7187e
--- /dev/null
+++ b/tests/tests/secure_element/Android.mk
@@ -0,0 +1,16 @@
+# 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.
+
+include $(call all-subdir-makefiles)
+
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk
new file mode 100644
index 0000000..8e16c21
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk
@@ -0,0 +1,38 @@
+# 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_PACKAGE_NAME := CtsSecureElementAccessControlTestCases1
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+LOCAL_JAVA_LIBRARIES += android.test.runner
+LOCAL_JAVA_LIBRARIES += android.test.base
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/AndroidManifest.xml b/tests/tests/secure_element/access_control/AccessControlApp1/AndroidManifest.xml
new file mode 100644
index 0000000..87a7aa5
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.omapi.accesscontrol1.cts">
+
+    <application>
+        <uses-library android:name="android.test.runner"/>
+    </application>
+
+    <!-- This is a self-instrumenting test package. -->
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:label="CTS tests for Open Mobile API"
+                     android:targetPackage="android.omapi.accesscontrol1.cts">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener"/>
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/AndroidTest.xml b/tests/tests/secure_element/access_control/AccessControlApp1/AndroidTest.xml
new file mode 100644
index 0000000..26d0f39
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<configuration description="Config for CTS OMAPI test cases">
+    <option name="test-suite-tag" value="cts"/>
+    <option name="config-descriptor:metadata" key="component" value="systems"/>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true"/>
+        <option name="test-file-name" value="CtsSecureElementAccessControlTestCases1.apk"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="android.omapi.accesscontrol1.cts"/>
+        <option name="runtime-hint" value="10m10s"/>
+    </test>
+</configuration>
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/src/android/omapi/accesscontrol1/cts/AccessControlTest.java b/tests/tests/secure_element/access_control/AccessControlApp1/src/android/omapi/accesscontrol1/cts/AccessControlTest.java
new file mode 100644
index 0000000..3727c60
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/src/android/omapi/accesscontrol1/cts/AccessControlTest.java
@@ -0,0 +1,376 @@
+/*
+ * 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.
+ */
+
+/* Contributed by Orange */
+
+package android.omapi.accesscontrol1.cts;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeoutException;
+
+import android.os.RemoteException;
+import android.se.omapi.Channel;
+import android.se.omapi.Reader;
+import android.se.omapi.SEService;
+import android.se.omapi.SEService.OnConnectedListener;
+import android.se.omapi.Session;
+import android.test.AndroidTestCase;
+
+public class AccessControlTest extends AndroidTestCase {
+    private final static String UICC_READER_PREFIX = "SIM";
+    private final static String ESE_READER_PREFIX = "eSE";
+    private final static String SD_READER_PREFIX = "SD";
+
+    private final static byte[] AID_40 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x40 };
+    private final static byte[] AID_41 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x41 };
+    private final static byte[] AID_42 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x42 };
+    private final static byte[] AID_43 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x43 };
+    private final static byte[] AID_44 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x44 };
+    private final static byte[] AID_45 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x45 };
+    private final static byte[] AID_46 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x46 };
+    private final static byte[] AID_47 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x47 };
+    private final static byte[] AID_48 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x48 };
+    private final static byte[] AID_49 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x49 };
+    private final static byte[] AID_4A = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4A };
+    private final static byte[] AID_4B = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4B };
+    private final static byte[] AID_4C = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4C };
+    private final static byte[] AID_4D = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4D };
+    private final static byte[] AID_4E = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4E };
+    private final static byte[] AID_4F = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4F };
+
+    private final static byte[][] AUTHORIZED_AID = new byte[][] { AID_40,
+        AID_41, AID_42, AID_44, AID_45, AID_47, AID_48, AID_49, AID_4A,
+        AID_4B, AID_4C, AID_4D, AID_4E, AID_4F };
+    private final static byte[][] UNAUTHORIZED_AID = new byte[][] { AID_43,
+        AID_46 };
+
+    /* Authorized APDU for AID_40 */
+    private final static byte[][] AUTHORIZED_APDU_AID_40 = new byte[][] {
+        { 0x00, 0x06, 0x00, 0x00 }, { (byte) 0xA0, 0x06, 0x00, 0x00 },};
+    /* Unauthorized APDU for AID_40 */
+    private final static byte[][] UNAUTHORIZED_APDU_AID_40 = new byte[][] {
+        { 0x00, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x80, 0x06, 0x00, 0x00 },
+        { (byte) 0xA0, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x94, 0x06, 0x00, 0x00, 0x00 }, };
+
+    /* Authorized APDU for AID_41 */
+    private final static byte[][] AUTHORIZED_APDU_AID_41 = new byte[][] {
+        { (byte) 0x94, 0x06, 0x00, 0x00 },
+        { (byte) 0x94, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x94, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0x94, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA } };
+    /* Unauthorized APDU for AID_41 */
+    private final static byte[][] UNAUTHORIZED_APDU_AID_41 = new byte[][] {
+        { 0x00, 0x06, 0x00, 0x00 }, { (byte) 0x80, 0x06, 0x00, 0x00 },
+        { (byte) 0xA0, 0x06, 0x00, 0x00 },
+        { 0x00, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x00, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0x80, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0xA0, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0x80, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0xA0, 0x08, 0x00, 0x00, 0x00 },
+        { 0x00, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0x80, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0xA0, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+    };
+
+    private final long SERVICE_CONNECTION_TIME_OUT = 3000;
+    private SEService seService;
+    private Object serviceMutex = new Object();
+    private Timer connectionTimer;
+    private ServiceConnectionTimerTask mTimerTask = new ServiceConnectionTimerTask();
+    private boolean connected = false;
+
+    private final OnConnectedListener mListener = new OnConnectedListener() {
+        public void onConnected() {
+            synchronized (serviceMutex) {
+                connected = true;
+                serviceMutex.notify();
+            }
+        }
+    };
+
+    class SynchronousExecutor implements Executor {
+        public void execute(Runnable r) {
+            r.run();
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        seService = new SEService(getContext(), new SynchronousExecutor(), mListener);
+        connectionTimer = new Timer();
+        connectionTimer.schedule(mTimerTask, SERVICE_CONNECTION_TIME_OUT);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (seService != null && seService.isConnected()) {
+            seService.shutdown();
+            connected = false;
+        }
+    }
+
+    private void waitForConnection() throws TimeoutException {
+        synchronized (serviceMutex) {
+            if (!connected) {
+                try {
+                    serviceMutex.wait();
+                 } catch (InterruptedException e) {
+                    e.printStackTrace();
+                 }
+            }
+            if (!connected) {
+                throw new TimeoutException(
+                    "Service could not be connected after "
+                    + SERVICE_CONNECTION_TIME_OUT + " ms");
+            }
+            if (connectionTimer != null) {
+                connectionTimer.cancel();
+            }
+        }
+    }
+
+    public void testAuthorizedAID() {
+        for (byte[] aid : AUTHORIZED_AID) {
+            testSelectableAid(aid);
+        }
+    }
+
+    public void testUnauthorizedAID() {
+        for (byte[] aid : UNAUTHORIZED_AID) {
+            testUnauthorisedAid(aid);
+        }
+    }
+
+    public void testAuthorizedAPDUAID40() {
+        for (byte[] apdu : AUTHORIZED_APDU_AID_40) {
+            testTransmitAPDU(AID_40, apdu);
+        }
+    }
+
+    public void testUnauthorisedAPDUAID40() {
+        for (byte[] apdu : UNAUTHORIZED_APDU_AID_40) {
+            testUnauthorisedAPDU(AID_40, apdu);
+        }
+    }
+
+    public void testAuthorizedAPDUAID41() {
+        for (byte[] apdu : AUTHORIZED_APDU_AID_41) {
+            testTransmitAPDU(AID_41, apdu);
+        }
+    }
+
+    public void testUnauthorisedAPDUAID41() {
+        for (byte[] apdu : UNAUTHORIZED_APDU_AID_41) {
+            testUnauthorisedAPDU(AID_41, apdu);
+        }
+    }
+
+    private void testSelectableAid(byte[] aid) {
+        Session session = null;
+        Channel channel = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte) 0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        } finally{
+            if (channel != null)
+                channel.close();
+            if (session != null)
+                session.close();
+        }
+    }
+
+    private void testUnauthorisedAid(byte[] aid) {
+        Session session = null;
+        Channel channel = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte) 0x00);
+                fail("SecurityException Expected ");
+            }
+        } catch(SecurityException ex){ }
+        catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+        if (channel != null)
+            channel.close();
+        if (session != null)
+            session.close();
+    }
+
+    private void testTransmitAPDU(byte[] aid, byte[] apdu) {
+        Session session = null;
+        Channel channel = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte) 0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+                byte[] apduResponse = channel.transmit(apdu);
+                assertNotNull("Null Channel", apduResponse);
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+        if (channel != null)
+            channel.close();
+        if (session != null)
+            session.close();
+    }
+
+    private void testUnauthorisedAPDU(byte[] aid, byte[] apdu) {
+        Session session = null;
+        Channel channel = null;
+        boolean exceptionOnTransmit = false;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte) 0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+                exceptionOnTransmit = true;
+                channel.transmit(apdu);
+                fail("Security Exception is expected");
+            }
+        } catch (SecurityException ex) {
+          if (!exceptionOnTransmit) {
+            fail("Unexpected SecurityException onSelect" + ex);
+          }
+        } catch (Exception e) {
+          fail("Unexpected Exception " + e);
+        } finally {
+            if(channel != null)
+                channel.close();
+            if (session != null)
+                session.close();
+        }
+    }
+
+    /**
+     * Verifies TLV data
+     *
+     * @param tlv
+     * @return true if the data is tlv formatted, false otherwise
+     */
+    private static boolean verifyBerTlvData(byte[] tlv) {
+        if (tlv == null || tlv.length == 0) {
+            throw new RuntimeException("Invalid tlv, null");
+        }
+
+        int i = 0;
+        byte[] key = new byte[2];
+        key[0] = tlv[i];
+        if ((key[0] & 0x1F) == 0x1F) {
+            // extra byte for TAG field
+            key[1] = tlv[i = i + 1];
+        }
+
+        int len = tlv[i = i + 1] & 0xFF;
+        if (len > 127) {
+            // more than 1 byte for length
+            int bytesLength = len - 128;
+            len = 0;
+            for (int j = bytesLength - 1; j >= 0; j--) {
+              len += (tlv[i = i + 1] & 0xFF) * Math.pow(10, j);
+            }
+        }
+        return tlv.length == (i + len + 3);
+    }
+
+    class ServiceConnectionTimerTask extends TimerTask {
+        @Override
+        public void run() {
+            synchronized (serviceMutex) {
+                serviceMutex.notifyAll();
+            }
+        }
+    }
+}
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk
new file mode 100644
index 0000000..2ef5b3a
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk
@@ -0,0 +1,38 @@
+# 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_PACKAGE_NAME := CtsSecureElementAccessControlTestCases2
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+LOCAL_JAVA_LIBRARIES += android.test.runner
+LOCAL_JAVA_LIBRARIES += android.test.base
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/AndroidManifest.xml b/tests/tests/secure_element/access_control/AccessControlApp2/AndroidManifest.xml
new file mode 100644
index 0000000..e92a577
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.omapi.accesscontrol2.cts">
+
+    <application>
+        <uses-library android:name="android.test.runner"/>
+    </application>
+
+    <!-- This is a self-instrumenting test package. -->
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:label="CTS tests for Open Mobile API"
+                     android:targetPackage="android.omapi.accesscontrol2.cts">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener"/>
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/AndroidTest.xml b/tests/tests/secure_element/access_control/AccessControlApp2/AndroidTest.xml
new file mode 100644
index 0000000..50eec10
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<configuration description="Config for CTS OMAPI test cases">
+    <option name="test-suite-tag" value="cts"/>
+    <option name="config-descriptor:metadata" key="component" value="systems"/>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true"/>
+        <option name="test-file-name" value="CtsSecureElementAccessControlTestCases2.apk"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="android.omapi.accesscontrol2.cts"/>
+        <option name="runtime-hint" value="10m10s"/>
+    </test>
+</configuration>
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/src/android/omapi/accesscontrol2/cts/AccessControlTest.java b/tests/tests/secure_element/access_control/AccessControlApp2/src/android/omapi/accesscontrol2/cts/AccessControlTest.java
new file mode 100644
index 0000000..8b51205
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/src/android/omapi/accesscontrol2/cts/AccessControlTest.java
@@ -0,0 +1,375 @@
+/*
+ * 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.
+ */
+
+/* Contributed by Orange */
+
+package android.omapi.accesscontrol2.cts;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeoutException;
+
+import android.os.RemoteException;
+import android.se.omapi.Channel;
+import android.se.omapi.Reader;
+import android.se.omapi.SEService;
+import android.se.omapi.SEService.OnConnectedListener;
+import android.se.omapi.Session;
+import android.test.AndroidTestCase;
+
+public class AccessControlTest extends AndroidTestCase {
+    private final static String UICC_READER_PREFIX = "SIM";
+    private final static String ESE_READER_PREFIX = "eSE";
+    private final static String SD_READER_PREFIX = "SD";
+
+    private final static byte[] AID_40 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x40 };
+    private final static byte[] AID_41 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x41 };
+    private final static byte[] AID_42 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x42 };
+    private final static byte[] AID_43 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x43 };
+    private final static byte[] AID_44 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x44 };
+    private final static byte[] AID_45 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x45 };
+    private final static byte[] AID_46 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x46 };
+    private final static byte[] AID_47 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x47 };
+    private final static byte[] AID_48 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x48 };
+    private final static byte[] AID_49 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x49 };
+    private final static byte[] AID_4A = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4A };
+    private final static byte[] AID_4B = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4B };
+    private final static byte[] AID_4C = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4C };
+    private final static byte[] AID_4D = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4D };
+    private final static byte[] AID_4E = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4E };
+    private final static byte[] AID_4F = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4F };
+
+    private final static byte[][] AUTHORIZED_AID = new byte[][] { AID_40,
+        AID_41, AID_43, AID_45, AID_46 };
+    private final static byte[][] UNAUTHORIZED_AID = new byte[][] { AID_42,
+        AID_44, AID_47, AID_48, AID_49, AID_4A, AID_4B, AID_4C, AID_4D, AID_4E, AID_4F};
+
+    /* Authorized APDU for AID_40 */
+    private final static byte[][] AUTHORIZED_APDU_AID_40 = new byte[][] {
+        { 0x00, 0x06, 0x00, 0x00 }, { (byte) 0xA0, 0x06, 0x00, 0x00 },};
+    /* Unauthorized APDU for AID_40 */
+    private final static byte[][] UNAUTHORIZED_APDU_AID_40 = new byte[][] {
+        { 0x00, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x80, 0x06, 0x00, 0x00 },
+        { (byte) 0xA0, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x94, 0x06, 0x00, 0x00, 0x00 }, };
+
+    /* Authorized APDU for AID_41 */
+    private final static byte[][] AUTHORIZED_APDU_AID_41 = new byte[][] {
+        { (byte) 0x94, 0x06, 0x00, 0x00 },
+        { (byte) 0x94, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x94, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0x94, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA } };
+    /* Unauthorized APDU for AID_41 */
+    private final static byte[][] UNAUTHORIZED_APDU_AID_41 = new byte[][] {
+        { 0x00, 0x06, 0x00, 0x00 }, { (byte) 0x80, 0x06, 0x00, 0x00 },
+        { (byte) 0xA0, 0x06, 0x00, 0x00 },
+        { 0x00, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x00, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0x80, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0xA0, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0x80, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0xA0, 0x08, 0x00, 0x00, 0x00 },
+        { 0x00, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0x80, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0xA0, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+    };
+
+    private final long SERVICE_CONNECTION_TIME_OUT = 3000;
+    private SEService seService;
+    private Object serviceMutex = new Object();
+    private Timer connectionTimer;
+    private ServiceConnectionTimerTask mTimerTask = new ServiceConnectionTimerTask();
+    private boolean connected = false;
+
+    private final OnConnectedListener mListener = new OnConnectedListener() {
+        public void onConnected() {
+            synchronized (serviceMutex) {
+                connected = true;
+                serviceMutex.notify();
+            }
+        }
+    };
+
+    class SynchronousExecutor implements Executor {
+        public void execute(Runnable r) {
+            r.run();
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        seService = new SEService(getContext(), new SynchronousExecutor(), mListener);
+        connectionTimer = new Timer();
+        connectionTimer.schedule(mTimerTask, SERVICE_CONNECTION_TIME_OUT);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (seService != null && seService.isConnected()) {
+            seService.shutdown();
+            connected = false;
+        }
+    }
+
+    private void waitForConnection() throws TimeoutException {
+        synchronized (serviceMutex) {
+            if (!connected) {
+                try {
+                    serviceMutex.wait();
+                 } catch (InterruptedException e) {
+                    e.printStackTrace();
+                 }
+            }
+            if (!connected) {
+                throw new TimeoutException(
+                    "Service could not be connected after "
+                    + SERVICE_CONNECTION_TIME_OUT + " ms");
+            }
+            if (connectionTimer != null) {
+                connectionTimer.cancel();
+            }
+        }
+    }
+
+    public void testAuthorizedAID() {
+        for (byte[] aid : AUTHORIZED_AID) {
+            testSelectableAid(aid);
+        }
+    }
+
+    public void testUnauthorizedAID() {
+        for (byte[] aid : UNAUTHORIZED_AID) {
+            testUnauthorisedAid(aid);
+        }
+    }
+
+    public void testAuthorizedAPDUAID40() {
+        for (byte[] apdu : AUTHORIZED_APDU_AID_40) {
+            testTransmitAPDU(AID_40, apdu);
+        }
+    }
+
+    public void testUnauthorisedAPDUAID40() {
+        for (byte[] apdu : UNAUTHORIZED_APDU_AID_40) {
+            testUnauthorisedAPDU(AID_40, apdu);
+        }
+    }
+
+    public void testAuthorizedAPDUAID41() {
+        for (byte[] apdu : AUTHORIZED_APDU_AID_41) {
+            testTransmitAPDU(AID_41, apdu);
+        }
+    }
+
+    public void testUnauthorisedAPDUAID41() {
+        for (byte[] apdu : UNAUTHORIZED_APDU_AID_41) {
+            testUnauthorisedAPDU(AID_41, apdu);
+        }
+    }
+
+    private void testSelectableAid(byte[] aid) {
+        Session session = null;
+        Channel channel = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte) 0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        } finally{
+            if (channel != null)
+                channel.close();
+            if (session != null)
+                session.close();
+        }
+    }
+
+    private void testUnauthorisedAid(byte[] aid) {
+        Session session = null;
+        Channel channel = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte)0x00);
+                fail("SecurityException Expected ");
+            }
+        } catch(SecurityException ex){ }
+        catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+        if (channel != null)
+            channel.close();
+        if (session != null)
+            session.close();
+    }
+
+    private void testTransmitAPDU(byte[] aid, byte[] apdu) {
+        Session session = null;
+        Channel channel = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte)0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+                byte[] apduResponse = channel.transmit(apdu);
+                assertNotNull("Null Channel", apduResponse);
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+        if (channel != null)
+            channel.close();
+        if (session != null)
+            session.close();
+    }
+
+    private void testUnauthorisedAPDU(byte[] aid, byte[] apdu) {
+        Session session = null;
+        Channel channel = null;
+        boolean exceptionOnTransmit = false;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte) 0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+                exceptionOnTransmit = true;
+                channel.transmit(apdu);
+                fail("Security Exception is expected");
+            }
+        } catch (SecurityException ex) {
+          if (!exceptionOnTransmit) {
+            fail("Unexpected SecurityException onSelect" + ex);
+          }
+        } catch (Exception e) {
+          fail("Unexpected Exception " + e);
+        } finally {
+            if(channel != null)
+                channel.close();
+            if (session != null)
+                session.close();
+        }
+    }
+
+    /**
+     * Verifies TLV data
+     *
+     * @param tlv
+     * @return true if the data is tlv formatted, false otherwise
+     */
+    private static boolean verifyBerTlvData(byte[] tlv) {
+        if (tlv == null || tlv.length == 0) {
+            throw new RuntimeException("Invalid tlv, null");
+        }
+
+        int i = 0;
+        byte[] key = new byte[2];
+        key[0] = tlv[i];
+        if ((key[0] & 0x1F) == 0x1F) {
+            // extra byte for TAG field
+            key[1] = tlv[i = i + 1];
+        }
+
+        int len = tlv[i = i + 1] & 0xFF;
+        if (len > 127) {
+            // more than 1 byte for length
+            int bytesLength = len - 128;
+            len = 0;
+            for (int j = bytesLength - 1; j >= 0; j--) {
+              len += (tlv[i = i + 1] & 0xFF) * Math.pow(10, j);
+            }
+        }
+        return tlv.length == (i + len + 3);
+    }
+
+    class ServiceConnectionTimerTask extends TimerTask {
+        @Override
+        public void run() {
+            synchronized (serviceMutex) {
+                serviceMutex.notifyAll();
+            }
+        }
+    }
+}
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk
new file mode 100644
index 0000000..e52f2f9
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk
@@ -0,0 +1,38 @@
+# 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_PACKAGE_NAME := CtsSecureElementAccessControlTestCases3
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+LOCAL_JAVA_LIBRARIES += android.test.runner
+LOCAL_JAVA_LIBRARIES += android.test.base
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/AndroidManifest.xml b/tests/tests/secure_element/access_control/AccessControlApp3/AndroidManifest.xml
new file mode 100644
index 0000000..dd6375c
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.omapi.accesscontrol3.cts">
+
+    <application>
+        <uses-library android:name="android.test.runner"/>
+    </application>
+
+    <!-- This is a self-instrumenting test package. -->
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:label="CTS tests for Open Mobile API"
+                     android:targetPackage="android.omapi.accesscontrol3.cts">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener"/>
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/AndroidTest.xml b/tests/tests/secure_element/access_control/AccessControlApp3/AndroidTest.xml
new file mode 100644
index 0000000..6dcac02
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<configuration description="Config for CTS OMAPI test cases">
+    <option name="test-suite-tag" value="cts"/>
+    <option name="config-descriptor:metadata" key="component" value="systems"/>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true"/>
+        <option name="test-file-name" value="CtsSecureElementAccessControlTestCases3.apk"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="android.omapi.accesscontrol3.cts"/>
+        <option name="runtime-hint" value="10m10s"/>
+    </test>
+</configuration>
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/src/android/omapi/accesscontrol3/cts/AccessControlTest.java b/tests/tests/secure_element/access_control/AccessControlApp3/src/android/omapi/accesscontrol3/cts/AccessControlTest.java
new file mode 100644
index 0000000..5ca0c51
--- /dev/null
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/src/android/omapi/accesscontrol3/cts/AccessControlTest.java
@@ -0,0 +1,379 @@
+/*
+ * 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.
+ */
+
+/* Contributed by Orange */
+
+package android.omapi.accesscontrol3.cts;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeoutException;
+
+import android.os.RemoteException;
+import android.se.omapi.Channel;
+import android.se.omapi.Reader;
+import android.se.omapi.SEService;
+import android.se.omapi.SEService.OnConnectedListener;
+import android.se.omapi.Session;
+import android.test.AndroidTestCase;
+
+public class AccessControlTest extends AndroidTestCase {
+    private final static String UICC_READER_PREFIX = "SIM";
+    private final static String ESE_READER_PREFIX = "eSE";
+    private final static String SD_READER_PREFIX = "SD";
+
+    private final static byte[] AID_40 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x40 };
+    private final static byte[] AID_41 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x41 };
+    private final static byte[] AID_42 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x42 };
+    private final static byte[] AID_43 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x43 };
+    private final static byte[] AID_44 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x44 };
+    private final static byte[] AID_45 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x45 };
+    private final static byte[] AID_46 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x46 };
+    private final static byte[] AID_47 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x47 };
+    private final static byte[] AID_48 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x48 };
+    private final static byte[] AID_49 = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, 0x49 };
+    private final static byte[] AID_4A = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4A };
+    private final static byte[] AID_4B = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4B };
+    private final static byte[] AID_4C = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4C };
+    private final static byte[] AID_4D = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4D };
+    private final static byte[] AID_4E = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4E };
+    private final static byte[] AID_4F = new byte[] { (byte) 0xA0, 0x00, 0x00,
+        0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
+        0x53, (byte) 0x4F };
+
+    private final static byte[][] AUTHORIZED_AID = new byte[][] { AID_40,
+        AID_41, AID_45, AID_46 };
+    private final static byte[][] UNAUTHORIZED_AID = new byte[][] { AID_42,
+        AID_43, AID_44, AID_47, AID_48, AID_49, AID_4A, AID_4B, AID_4C, AID_4D, AID_4E,
+        AID_4F };
+
+    /* Authorized APDU for AID_40 */
+    private final static byte[][] AUTHORIZED_APDU_AID_40 = new byte[][] {
+        { 0x00, 0x06, 0x00, 0x00 }, { (byte) 0x80, 0x06, 0x00, 0x00 },
+        { (byte) 0xA0, 0x06, 0x00, 0x00 },
+        { (byte) 0x94, 0x06, 0x00, 0x00 },
+        { 0x00, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0x80, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0xA0, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0x94, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { 0x00, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x80, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0xA0, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x94, 0x08, 0x00, 0x00, 0x00 },
+        { 0x00, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0x80, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0xA0, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0x94, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 }};
+
+    /* Authorized APDU for AID_41 */
+    private final static byte[][] AUTHORIZED_APDU_AID_41 = new byte[][] {
+        { (byte) 0x94, 0x06, 0x00, 0x00 },
+        { (byte) 0x94, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x94, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0x94, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA } };
+    /* Unauthorized APDU for AID_41 */
+    private final static byte[][] UNAUTHORIZED_APDU_AID_41 = new byte[][] {
+        { 0x00, 0x06, 0x00, 0x00 }, { (byte) 0x80, 0x06, 0x00, 0x00 },
+        { (byte) 0xA0, 0x06, 0x00, 0x00 },
+        { 0x00, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0x00, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0x80, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0xA0, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
+        { (byte) 0x80, 0x08, 0x00, 0x00, 0x00 },
+        { (byte) 0xA0, 0x08, 0x00, 0x00, 0x00 },
+        { 0x00, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0x80, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+        { (byte) 0xA0, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
+    };
+
+    private final long SERVICE_CONNECTION_TIME_OUT = 3000;
+    private SEService seService;
+    private Object serviceMutex = new Object();
+    private Timer connectionTimer;
+    private ServiceConnectionTimerTask mTimerTask = new ServiceConnectionTimerTask();
+    private boolean connected = false;
+
+    private final OnConnectedListener mListener = new OnConnectedListener() {
+        @Override
+        public void onConnected() {
+            synchronized (serviceMutex) {
+                connected = true;
+                serviceMutex.notify();
+            }
+        }
+    };
+
+    class SynchronousExecutor implements Executor {
+        public void execute(Runnable r) {
+            r.run();
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        seService = new SEService(getContext(), new SynchronousExecutor(), mListener);
+        connectionTimer = new Timer();
+        connectionTimer.schedule(mTimerTask, SERVICE_CONNECTION_TIME_OUT);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (seService != null && seService.isConnected()) {
+            seService.shutdown();
+            connected = false;
+        }
+    }
+
+    private void waitForConnection() throws TimeoutException {
+        synchronized (serviceMutex) {
+            if (!connected) {
+                try {
+                    serviceMutex.wait();
+                 } catch (InterruptedException e) {
+                    e.printStackTrace();
+                 }
+            }
+            if (!connected) {
+                throw new TimeoutException(
+                    "Service could not be connected after "
+                    + SERVICE_CONNECTION_TIME_OUT + " ms");
+            }
+            if (connectionTimer != null) {
+                connectionTimer.cancel();
+            }
+        }
+    }
+
+    public void testAuthorizedAID() {
+        for (byte[] aid : AUTHORIZED_AID) {
+            testSelectableAid(aid);
+        }
+    }
+
+    public void testUnauthorizedAID() {
+        for (byte[] aid : UNAUTHORIZED_AID) {
+            testUnauthorisedAid(aid);
+        }
+    }
+
+    public void testAuthorizedAPDUAID40() {
+        for (byte[] apdu : AUTHORIZED_APDU_AID_40) {
+            testTransmitAPDU(AID_40, apdu);
+        }
+    }
+
+    public void testAuthorizedAPDUAID41() {
+        for (byte[] apdu : AUTHORIZED_APDU_AID_41) {
+            testTransmitAPDU(AID_41, apdu);
+        }
+    }
+
+    public void testUnauthorisedAPDUAID41() {
+        for (byte[] apdu : UNAUTHORIZED_APDU_AID_41) {
+            testUnauthorisedAPDU(AID_41, apdu);
+        }
+    }
+
+    private void testSelectableAid(byte[] aid) {
+        Session session = null;
+        Channel channel = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte)0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        } finally{
+            if (channel != null)
+                channel.close();
+            if (session != null)
+                session.close();
+        }
+    }
+
+    private void testUnauthorisedAid(byte[] aid) {
+        Session session = null;
+        Channel channel = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte)0x00);
+                fail("SecurityException Expected ");
+            }
+        } catch(SecurityException ex){ }
+        catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+        if (channel != null)
+            channel.close();
+        if (session != null)
+            session.close();
+    }
+
+    private void testTransmitAPDU(byte[] aid, byte[] apdu) {
+        Session session = null;
+        Channel channel = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte)0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+                byte[] apduResponse = channel.transmit(apdu);
+                assertNotNull("Null Channel", apduResponse);
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+        if (channel != null)
+            channel.close();
+        if (session != null)
+            session.close();
+    }
+
+    private void testUnauthorisedAPDU(byte[] aid, byte[] apdu) {
+        Session session = null;
+        Channel channel = null;
+        boolean exceptionOnTransmit = false;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("Null Session", session);
+                channel = session.openLogicalChannel(aid, (byte)0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+                exceptionOnTransmit = true;
+                channel.transmit(apdu);
+                fail("Security Exception is expected");
+            }
+        } catch (SecurityException ex) {
+          if (!exceptionOnTransmit) {
+            fail("Unexpected SecurityException onSelect" + ex);
+          }
+        } catch (Exception e) {
+          fail("Unexpected Exception " + e);
+        } finally {
+            if(channel != null)
+                channel.close();
+            if (session != null)
+                session.close();
+        }
+    }
+
+    /**
+     * Verifies TLV data
+     *
+     * @param tlv
+     * @return true if the data is tlv formatted, false otherwise
+     */
+    private static boolean verifyBerTlvData(byte[] tlv) {
+        if (tlv == null || tlv.length == 0) {
+            throw new RuntimeException("Invalid tlv, null");
+        }
+
+        int i = 0;
+        byte[] key = new byte[2];
+        key[0] = tlv[i];
+        if ((key[0] & 0x1F) == 0x1F) {
+            // extra byte for TAG field
+            key[1] = tlv[i = i + 1];
+        }
+
+        int len = tlv[i = i + 1] & 0xFF;
+        if (len > 127) {
+            // more than 1 byte for length
+            int bytesLength = len - 128;
+            len = 0;
+            for (int j = bytesLength - 1; j >= 0; j--) {
+              len += (tlv[i = i + 1] & 0xFF) * Math.pow(10, j);
+            }
+        }
+        return tlv.length == (i + len + 3);
+    }
+
+    class ServiceConnectionTimerTask extends TimerTask {
+        @Override
+        public void run() {
+            synchronized (serviceMutex) {
+                serviceMutex.notifyAll();
+            }
+        }
+    }
+}
diff --git a/tests/tests/secure_element/access_control/Android.mk b/tests/tests/secure_element/access_control/Android.mk
new file mode 100644
index 0000000..5c7187e
--- /dev/null
+++ b/tests/tests/secure_element/access_control/Android.mk
@@ -0,0 +1,16 @@
+# 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.
+
+include $(call all-subdir-makefiles)
+
diff --git a/tests/tests/secure_element/omapi/Android.mk b/tests/tests/secure_element/omapi/Android.mk
new file mode 100644
index 0000000..f12aa75
--- /dev/null
+++ b/tests/tests/secure_element/omapi/Android.mk
@@ -0,0 +1,38 @@
+# 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_PACKAGE_NAME := CtsOmapiTestCases
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+LOCAL_JAVA_LIBRARIES += android.test.runner
+LOCAL_JAVA_LIBRARIES += android.test.base
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/omapi/AndroidManifest.xml b/tests/tests/secure_element/omapi/AndroidManifest.xml
new file mode 100644
index 0000000..ce5ccc9
--- /dev/null
+++ b/tests/tests/secure_element/omapi/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.omapi.cts">
+
+    <application>
+        <uses-library android:name="android.test.runner"/>
+    </application>
+
+    <!-- This is a self-instrumenting test package. -->
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:label="CTS tests for Open Mobile API"
+                     android:targetPackage="android.omapi.cts">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener"/>
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/secure_element/omapi/AndroidTest.xml b/tests/tests/secure_element/omapi/AndroidTest.xml
new file mode 100644
index 0000000..faeb9c3
--- /dev/null
+++ b/tests/tests/secure_element/omapi/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<configuration description="Config for CTS OMAPI test cases">
+    <option name="test-suite-tag" value="cts"/>
+    <option name="config-descriptor:metadata" key="component" value="systems"/>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true"/>
+        <option name="test-file-name" value="CtsOmapiTestCases.apk"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="android.omapi.cts"/>
+        <option name="runtime-hint" value="10m10s"/>
+    </test>
+</configuration>
diff --git a/tests/tests/secure_element/omapi/src/android/omapi/cts/OmapiTest.java b/tests/tests/secure_element/omapi/src/android/omapi/cts/OmapiTest.java
new file mode 100644
index 0000000..93eefa3
--- /dev/null
+++ b/tests/tests/secure_element/omapi/src/android/omapi/cts/OmapiTest.java
@@ -0,0 +1,564 @@
+/*
+ * 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.
+ */
+
+/* Contributed by Orange */
+
+package android.omapi.cts;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.NoSuchElementException;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeoutException;
+
+import android.se.omapi.Channel;
+import android.se.omapi.Reader;
+import android.se.omapi.SEService;
+import android.se.omapi.SEService.OnConnectedListener;
+import android.se.omapi.Session;
+import android.test.AndroidTestCase;
+
+public class OmapiTest extends AndroidTestCase {
+
+    private final static String UICC_READER_PREFIX = "SIM";
+    private final static String ESE_READER_PREFIX = "eSE";
+    private final static String SD_READER_PREFIX = "SD";
+    private final static byte[] SELECTABLE_AID =
+            new byte[]{(byte) 0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                    0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x31};
+    private final static byte[] LONG_SELECT_RESPONSE_AID =
+            new byte[]{(byte) 0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                    0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x32};
+    private final static byte[] NON_SELECTABLE_AID =
+            new byte[]{(byte) 0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+                    0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, (byte) 0xFF};
+
+    /* MANAGE open/close and SELECT AID */
+    private final static byte[][] ILLEGAL_COMMANDS_TRANSMIT = new byte[][]{{0x00, 0x70, 0x00, 0x00},
+            {0x00, 0x70, (byte) 0x80, 0x00},
+            {0x00, (byte) 0xA4, 0x04, 0x04, 0x10, 0x4A, 0x53,
+                    0x52, 0x31, 0x37, 0x37, 0x54, 0x65, 0x73,
+                    0x74, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30}
+    };
+
+    /* OMAPI APDU Test case 1 and 3 */
+    private final static byte[][] NO_DATA_APDU = new byte[][]{{0x00, 0x06, 0x00, 0x00},
+            {(byte) 0x80, 0x06, 0x00, 0x00},
+            {(byte) 0xA0, 0x06, 0x00, 0x00},
+            {(byte) 0x94, 0x06, 0x00, 0x00},
+            {0x00, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA},
+            {(byte) 0x80, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA},
+            {(byte) 0xA0, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA},
+            {(byte) 0x94, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA}
+    };
+    /* OMAPI APDU Test case 2 and 4 */
+    private final static byte[][] DATA_APDU = new byte[][]{{0x00, 0x08, 0x00, 0x00, 0x00},
+            {(byte) 0x80, 0x08, 0x00, 0x00, 0x00},
+            {(byte) 0xA0, 0x08, 0x00, 0x00, 0x00},
+            {(byte) 0x94, 0x08, 0x00, 0x00, 0x00},
+            {0x00, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00},
+            {(byte) 0x80, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00},
+            {(byte) 0xA0, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00},
+            {(byte) 0x94, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00}
+    };
+
+    private final static byte[] CHECK_SELECT_P2_APDU = new byte[]{0x00, (byte) 0xF4, 0x00, 0x00};
+
+    /* OMAPI APDU Test case 1 and 3 */
+    private final static byte[][] SW_62xx_NO_DATA_APDU =
+            new byte[][]{{0x00, (byte) 0xF3, 0x00, 0x06},
+                    {0x00, (byte) 0xF3, 0x00, 0x0A, 0x01, (byte) 0xAA}
+            };
+    /* OMAPI APDU Test case 2 and 4 */
+    private final static byte[] SW_62xx_DATA_APDU = new byte[]{0x00, (byte) 0xF3, 0x00, 0x08, 0x00};
+    private final static byte[] SW_62xx_VALIDATE_DATA_APDU =
+            new byte[]{0x00, (byte) 0xF3, 0x00, 0x0C, 0x01, (byte) 0xAA, 0x00};
+    private final static byte[][] SW_62xx =
+            new byte[][]{{0x62, 0x00}, {0x62, (byte) 0x81}, {0x62, (byte) 0x82},
+                    {0x62, (byte) 0x83},
+                    {0x62, (byte) 0x85}, {0x62, (byte) 0xF1}, {0x62, (byte) 0xF2},
+                    {0x63, (byte) 0xF1},
+                    {0x63, (byte) 0xF2}, {0x63, (byte) 0xC2}, {0x62, 0x02}, {0x62, (byte) 0x80},
+                    {0x62, (byte) 0x84}, {0x62, (byte) 0x86}, {0x63, 0x00}, {0x63, (byte) 0x81}
+            };
+    private final static byte[][] SEGMENTED_RESP_APDU = new byte[][]{
+            //Get response Case2 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+            {0x00, (byte) 0xC2, 0x08, 0x00, 0x00},
+            //Get response Case4 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+            {0x00, (byte) 0xC4, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
+            //Get response Case2 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+            {0x00, (byte) 0xC6, 0x08, 0x00, 0x00},
+            //Get response Case4 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+            {0x00, (byte) 0xC8, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
+            //Test device buffer capacity 7FFF data
+            {0x00, (byte) 0xC2, (byte) 0x7F, (byte) 0xFF, 0x00},
+            //Get response 6CFF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+            {0x00, (byte) 0xCF, 0x08, 0x00, 0x00},
+            //Get response with another CLA  with answer length (P1P2) of 0x0800, 2048 bytes
+            {(byte) 0x94, (byte) 0xC2, 0x08, 0x00, 0x00}
+    };
+    private final long SERVICE_CONNECTION_TIME_OUT = 3000;
+    private SEService seService;
+    private Object serviceMutex = new Object();
+    private Timer connectionTimer;
+    private ServiceConnectionTimerTask mTimerTask = new ServiceConnectionTimerTask();
+    private boolean connected = false;
+    private final OnConnectedListener mListener = new OnConnectedListener() {
+                @Override
+                public void onConnected() {
+                    synchronized (serviceMutex) {
+                        connected = true;
+                        serviceMutex.notify();
+                    }
+                }
+            };
+
+    class SynchronousExecutor implements Executor {
+        public void execute(Runnable r) {
+            r.run();
+        }
+    }
+
+    private void assertGreaterOrEqual(long greater, long lesser) {
+        assertTrue("" + greater + " expected to be greater than or equal to " + lesser,
+                greater >= lesser);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        seService = new SEService(getContext(), new SynchronousExecutor(), mListener);
+        connectionTimer = new Timer();
+        connectionTimer.schedule(mTimerTask, SERVICE_CONNECTION_TIME_OUT);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (seService != null && seService.isConnected()) {
+            seService.shutdown();
+            connected = false;
+        }
+    }
+
+    private void waitForConnection() throws TimeoutException {
+        synchronized (serviceMutex) {
+            if (!connected) {
+                try {
+                    serviceMutex.wait();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (!connected) {
+                throw new TimeoutException(
+                        "Service could not be connected after " + SERVICE_CONNECTION_TIME_OUT
+                                + " ms");
+            }
+            if (connectionTimer != null) {
+                connectionTimer.cancel();
+            }
+        }
+    }
+
+    /** Tests getReaders API */
+    public void testGetReaders() {
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                String name = reader.getName();
+                if (!(name.startsWith(UICC_READER_PREFIX) || name.startsWith(ESE_READER_PREFIX)
+                        || name.startsWith(SD_READER_PREFIX))) {
+                    fail("Incorrect Reader name");
+                }
+                assertNotNull("getseService returned null", reader.getSEService());
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+    }
+
+    /** Tests getATR API */
+    public void testATR() {
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+            ArrayList<Reader> uiccReaders = new ArrayList<Reader>();
+            if (readers != null && readers.length > 0) {
+                for (int i = 0; i < readers.length; i++) {
+                    if (readers[i].getName().startsWith(UICC_READER_PREFIX)) {
+                        uiccReaders.add(readers[i]);
+                    }
+                }
+
+                for (Reader reader : uiccReaders) {
+                    Session session = null;
+                    try {
+                        session = reader.openSession();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                    assertNotNull("Could not open session", session);
+                    byte[] atr = session.getATR();
+                    session.close();
+                    assertNotNull("ATR is Null", atr);
+                }
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+    }
+
+    /** Tests OpenBasicChannel API when aid is null */
+    public void testOpenBasicChannelNullAid() {
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                Session session = reader.openSession();
+                assertNotNull("Could not open session", session);
+                Channel channel = session.openBasicChannel(null, (byte)0x00);
+                if (reader.getName().startsWith(UICC_READER_PREFIX)) {
+                    assertNull("Basic channel on UICC can be opened", channel);
+                } else {
+                    assertNotNull("Basic Channel cannot be opened", channel);
+                }
+                if (channel != null) {
+                    channel.close();
+                }
+                session.close();
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+    }
+
+    /** Tests OpenBasicChannel API when aid is provided */
+    public void testOpenBasicChannelNonNullAid() {
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                Session session = reader.openSession();
+                assertNotNull("Could not open session", session);
+                Channel channel = session.openBasicChannel(SELECTABLE_AID, (byte)0x00);
+                if (reader.getName().startsWith(UICC_READER_PREFIX)) {
+                    assertNull("Basic channel on UICC can be opened", channel);
+                } else {
+                    assertNotNull("Basic Channel cannot be opened", channel);
+                }
+                if (channel != null) {
+                    channel.close();
+                }
+                session.close();
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+    }
+
+    /** Tests Select API */
+    public void testSelectableAid() {
+        testSelectableAid(SELECTABLE_AID);
+    }
+
+    public void testLongSelectResponse() {
+        byte[] selectResponse = testSelectableAid(LONG_SELECT_RESPONSE_AID);
+        assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
+    }
+
+
+    private byte[] testSelectableAid(byte[] aid) {
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                Session session = reader.openSession();
+                assertNotNull("Null Session", session);
+                Channel channel = session.openLogicalChannel(aid, (byte)0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertGreaterOrEqual(selectResponse.length, 2);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                channel.close();
+                session.close();
+                return selectResponse;
+            }
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e);
+        }
+        return null;
+    }
+
+    /** Tests if NoSuchElementException in Select */
+    public void testWrongAid() {
+        testNonSelectableAid(NON_SELECTABLE_AID);
+    }
+
+    public void testNonSelectableAid(byte[] aid) {
+        boolean exception = false;
+        Session session = null;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("null session", session);
+                Channel channel = session.openLogicalChannel(aid, (byte)0x00);
+            }
+        } catch (NoSuchElementException e) {
+            exception = true;
+            if (session != null) {
+                session.close();
+            }
+        } catch (Exception e) {
+            fail("unexpected exception " + e);
+        }
+        assertTrue(exception);
+    }
+
+    /** Tests if Security Exception in Transmit */
+    public void testSecurityExceptionInTransmit() {
+        boolean exception = false;
+        Session session;
+        Channel channel;
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                assertTrue(reader.isSecureElementPresent());
+                session = reader.openSession();
+                assertNotNull("null session", session);
+                channel = session.openLogicalChannel(SELECTABLE_AID, (byte)0x00);
+                assertNotNull("Null Channel", channel);
+                byte[] selectResponse = channel.getSelectResponse();
+                assertNotNull("Null Select Response", selectResponse);
+                assertGreaterOrEqual(selectResponse.length, 2);
+                assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
+                assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
+                for (byte[] cmd : ILLEGAL_COMMANDS_TRANSMIT) {
+                    try {
+                        exception = false;
+                        byte[] response = channel.transmit(cmd);
+                    } catch (SecurityException e) {
+                        exception = true;
+                    }
+                    assertTrue(exception);
+                }
+                channel.close();
+                session.close();
+            }
+        } catch (Exception e) {
+            fail("unexpected exception " + e);
+        }
+    }
+
+    private byte[] internalTransmitApdu(Reader reader, byte[] apdu) {
+        try {
+            assertTrue(reader.isSecureElementPresent());
+            Session session = reader.openSession();
+            assertNotNull("null session", session);
+            Channel channel = session.openLogicalChannel(SELECTABLE_AID, (byte)0x00);
+            assertNotNull("Null Channel", channel);
+            byte[] selectResponse = channel.getSelectResponse();
+            assertNotNull("Null Select Response", selectResponse);
+            assertGreaterOrEqual(selectResponse.length, 2);
+            byte[] transmitResponse = channel.transmit(apdu);
+            channel.close();
+            session.close();
+            return transmitResponse;
+        } catch (Exception e) {
+            fail("unexpected exception " + e);
+        }
+        return null;
+    }
+
+    /**
+     * Tests Transmit API for all readers.
+     *
+     * Checks the return status and verifies the size of the
+     * response.
+     */
+    public void testTransmitApdu() {
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                for (byte[] apdu : NO_DATA_APDU) {
+                    byte[] response = internalTransmitApdu(reader, apdu);
+                    assertEquals(response.length, 2);
+                    assertEquals(response[response.length - 1] & 0xFF, 0x00);
+                    assertEquals(response[response.length - 2] & 0xFF, 0x90);
+                }
+
+                for (byte[] apdu : DATA_APDU) {
+                    byte[] response = internalTransmitApdu(reader, apdu);
+                    /* 256 byte data and 2 bytes of status word */
+                    assertEquals(response.length, 258);
+                    assertEquals(response[response.length - 1] & 0xFF, 0x00);
+                    assertEquals(response[response.length - 2] & 0xFF, 0x90);
+                }
+            }
+        } catch (Exception e) {
+            fail("unexpected exception " + e);
+        }
+    }
+
+    /**
+     * Tests if underlying implementations returns the correct Status Word
+     *
+     * TO verify that :
+     * - the device does not modify the APDU sent to the Secure Element
+     * - the warning code is properly received by the application layer as SW answer
+     * - the verify that the application layer can fetch the additionnal data (when present)
+     */
+    public void testStatusWordTransmit() {
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                for (byte[] apdu : SW_62xx_NO_DATA_APDU) {
+                    for (byte i = 0x00; i < SW_62xx.length; i++) {
+                        apdu[2] = (byte)(i+1);
+                        byte[] response = internalTransmitApdu(reader, apdu);
+                        byte[] SW = SW_62xx[i];
+                        assertEquals(response[response.length - 1], SW[1]);
+                        assertEquals(response[response.length - 2], SW[0]);
+                    }
+                }
+
+                for (byte i = 0x00; i < SW_62xx.length; i++) {
+                    byte[] apdu = SW_62xx_DATA_APDU;
+                    apdu[2] = (byte)(i+1);
+                    byte[] response = internalTransmitApdu(reader, apdu);
+                    byte[] SW = SW_62xx[i];
+                    assertGreaterOrEqual(response.length, 3);
+                    assertEquals(response[response.length - 1], SW[1]);
+                    assertEquals(response[response.length - 2], SW[0]);
+                }
+
+                for (byte i = 0x00; i < SW_62xx.length; i++) {
+                    byte[] apdu = SW_62xx_VALIDATE_DATA_APDU;
+                    apdu[2] = (byte)(i+1);
+                    byte[] response = internalTransmitApdu(reader, apdu);
+                    assertGreaterOrEqual(response.length, apdu.length + 2);
+                    byte[] responseSubstring = Arrays.copyOfRange(response, 0, apdu.length);
+                    apdu[0] = 0x01;
+                    assertTrue(Arrays.equals(responseSubstring, apdu));
+                    byte[] SW = SW_62xx[i];
+                    assertEquals(response[response.length - 1], SW[1]);
+                    assertEquals(response[response.length - 2], SW[0]);
+                }
+            }
+        } catch (Exception e) {
+            fail("unexpected exception " + e);
+        }
+    }
+
+    /** Test if the responses are segmented by the underlying implementation */
+    public void testSegmentedResponseTransmit() {
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                for (byte[] apdu : SEGMENTED_RESP_APDU) {
+                    byte[] response = internalTransmitApdu(reader, apdu);
+                    byte[] b = { 0x00, 0x00, apdu[2], apdu[3] };
+                    ByteBuffer wrapped = ByteBuffer.wrap(b);
+                    int expectedLength = wrapped.getInt();
+                    assertEquals(response.length, expectedLength + 2);
+                    assertEquals(response[response.length - 1] & 0xFF, 0x00);
+                    assertEquals(response[response.length - 2] & 0xFF, 0x90);
+                    assertEquals(response[response.length - 3] & 0xFF, 0xFF);
+                }
+            }
+        } catch (Exception e) {
+            fail("unexpected exception " + e);
+        }
+    }
+
+    /** Test the P2 value of the select command sent by the underlying implementation */
+    public void testP2Value() {
+        try {
+            waitForConnection();
+            Reader[] readers = seService.getReaders();
+
+            for (Reader reader : readers) {
+                byte[] response = internalTransmitApdu(reader, CHECK_SELECT_P2_APDU);
+                assertGreaterOrEqual(response.length, 3);
+                assertEquals(response[response.length - 1] & 0xFF, 0x00);
+                assertEquals(response[response.length - 2] & 0xFF, 0x90);
+                assertEquals(response[response.length - 3] & 0xFF, 0x00);
+            }
+        } catch (Exception e) {
+          fail("unexpected exception " + e);
+        }
+    }
+
+    /**
+     * Verifies TLV data
+     * @param tlv
+     * @return true if the data is tlv formatted, false otherwise
+     */
+    private static boolean verifyBerTlvData(byte[] tlv){
+        if (tlv == null || tlv.length == 0) {
+            throw new RuntimeException("Invalid tlv, null");
+        }
+        int i = 0;
+        if ((tlv[i++] & 0x1F) == 0x1F) {
+            // extra byte for TAG field
+            i++;
+        }
+
+        int len = tlv[i++] & 0xFF;
+        if (len > 127) {
+            // more than 1 byte for length
+            int bytesLength = len-128;
+            len = 0;
+            for(int j = bytesLength; j > 0; j--) {
+                len += (len << 8) + (tlv[i++] & 0xFF);
+            }
+        }
+        // Additional 2 bytes for the SW
+        return (tlv.length == (i+len+2));
+    }
+
+    class ServiceConnectionTimerTask extends TimerTask {
+        @Override
+        public void run() {
+            synchronized (serviceMutex) {
+                serviceMutex.notifyAll();
+            }
+        }
+    }
+}
diff --git a/tests/tests/security/res/raw/bug_33751193_avc.mp4 b/tests/tests/security/res/raw/bug_33751193_avc.mp4
new file mode 100644
index 0000000..a621fab
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_33751193_avc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_73172046.mp4 b/tests/tests/security/res/raw/bug_73172046.mp4
new file mode 100644
index 0000000..4de44ba
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_73172046.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_13276.mp4 b/tests/tests/security/res/raw/cve_2017_13276.mp4
new file mode 100644
index 0000000..6cd86d3
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_13276.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 4104e32..506f2a1 100755
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -27,6 +27,8 @@
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.SurfaceTexture;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
@@ -377,6 +379,12 @@
         doStagefrightTest(R.raw.bug_34097672);
     }
 
+
+    @SecurityTest
+    public void testStagefright_bug_33751193() throws Exception {
+        doStagefrightTestRawBlob(R.raw.bug_33751193_avc, "video/avc", 320, 240);
+    }
+
     @SecurityTest
     public void testStagefright_bug_33818508() throws Exception {
         doStagefrightTest(R.raw.bug_33818508);
@@ -579,6 +587,11 @@
      ***********************************************************/
 
     @SecurityTest
+    public void testStagefright_cve_2017_13276() throws Exception {
+        doStagefrightTest(R.raw.cve_2017_13276);
+    }
+
+    @SecurityTest
     public void testStagefright_cve_2016_6764() throws Exception {
         doStagefrightTest(R.raw.cve_2016_6764);
     }
@@ -608,6 +621,15 @@
         doStagefrightTest(R.raw.bug_37093318, (4 * 60 * 1000));
     }
 
+    @SecurityTest
+    public void testStagefright_bug_73172046() throws Exception {
+        doStagefrightTest(R.raw.bug_73172046);
+
+        Bitmap bitmap = BitmapFactory.decodeResource(
+                getInstrumentation().getContext().getResources(), R.raw.bug_73172046);
+        bitmap.recycle();
+    }
+
     private void doStagefrightTest(final int rid) throws Exception {
         doStagefrightTestMediaPlayer(rid);
         doStagefrightTestMediaCodec(rid);
@@ -649,7 +671,7 @@
         in2.close();
         Log.i(TAG, "checked server");
     }
-  
+
     private void doStagefrightTest(final int rid, int timeout) throws Exception {
         runWithTimeout(new Runnable() {
             @Override
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerNegativeTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerNegativeTest.java
index 0fca1fa..bae8b0f 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerNegativeTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerNegativeTest.java
@@ -57,7 +57,7 @@
 
     private static void callMethodExpectingSecurityException(Object instance, String name,
             String expectedMessage, Object... args)
-            throws NoSuchMethodException, IllegalAccessException {
+            throws IllegalAccessException {
 
         Method m = null;
         for (Method method : instance.getClass().getDeclaredMethods()) {
@@ -90,7 +90,7 @@
         try {
             callMethodExpectingSecurityException(readField(manager, "mService"), method,
                     expectedMessage, args);
-        } catch (NoSuchFieldException|NoSuchMethodException e) {
+        } catch (NoSuchFieldException | LinkageError e) {
             if (DISALLOW_REFLECTION_ERROR) {
                 throw new RuntimeException(e);
             } else {
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
index c9b5000..6d080b2 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
@@ -171,8 +171,11 @@
             setIsEnabled = PhoneAccount.Builder.class.getDeclaredMethod(
                     "setIsEnabled", boolean.class);
         } catch (NoSuchMethodException e) {
-            fail("Failed to find setIsEnabled method.");
+            // This is the ideal case; ideally we should NOT be able to even reflect this method
+            // since its hidden.
+            return;
         }
+        // However, if reflection somehow finds the @hide method, we'll try executing it.
         setIsEnabled.invoke(phoneAccountBuilder, true);
         final PhoneAccount phoneAccount  = phoneAccountBuilder.build();
         mTelecomManager.registerPhoneAccount(phoneAccount);
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index 2b67f95..20f971f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
@@ -20,6 +20,7 @@
 import android.os.Bundle;
 import android.telecom.CallAudioState;
 import android.telecom.Connection;
+import android.telecom.ConnectionService;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -39,7 +40,8 @@
 
 public class SelfManagedConnectionServiceTest extends BaseTelecomTestWithMockServices {
     private Uri TEST_ADDRESS_1 = Uri.fromParts("sip", "call1@test.com", null);
-    private Uri TEST_ADDRESS_2 = Uri.fromParts("sip", "call2@test.com", null);
+    private Uri TEST_ADDRESS_2 = Uri.fromParts("tel", "650-555-1212", null);
+    private Uri TEST_ADDRESS_3 = Uri.fromParts("tel", "650-555-1213", null);
 
     @Override
     protected void setUp() throws Exception {
@@ -100,17 +102,26 @@
         PhoneAccount registeredAccount = mTelecomManager.getPhoneAccount(
                 TestUtils.TEST_SELF_MANAGED_HANDLE_1);
 
+        assertPhoneAccountRegistered(TestUtils.TEST_SELF_MANAGED_HANDLE_2);
+        assertPhoneAccountEnabled(TestUtils.TEST_SELF_MANAGED_HANDLE_2);
+        PhoneAccount registeredAccount2 = mTelecomManager.getPhoneAccount(
+                TestUtils.TEST_SELF_MANAGED_HANDLE_2);
+
         // It should exist and be the same as the previously registered one.
         assertNotNull(registeredAccount);
+        assertNotNull(registeredAccount2);
 
         // We cannot just check for equality of the PhoneAccount since the one we registered is not
         // enabled, and the one we get back after registration is.
         assertPhoneAccountEquals(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1, registeredAccount);
+        assertPhoneAccountEquals(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_2, registeredAccount2);
 
         // An important assumption is that self-managed PhoneAccounts are automatically
         // enabled by default.
         assertTrue("Self-managed PhoneAccounts must be enabled by default.",
                 registeredAccount.isEnabled());
+        assertTrue("Self-managed PhoneAccounts must be enabled by default.",
+                registeredAccount2.isEnabled());
     }
 
     /**
@@ -198,15 +209,20 @@
             return;
         }
 
-        TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
-                TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+        addAndVerifyIncomingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+        addAndVerifyIncomingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_2, TEST_ADDRESS_3);
+    }
+
+    private void addAndVerifyIncomingCall(PhoneAccountHandle handle, Uri address)
+            throws Exception {
+        TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager, handle, address);
 
         // Ensure Telecom bound to the self managed CS
         if (!CtsSelfManagedConnectionService.waitForBinding()) {
             fail("Could not bind to Self-Managed ConnectionService");
         }
 
-        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
+        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
 
         // Expect callback indicating that UI should be shown.
         connection.getOnShowIncomingUiInvokeCounter().waitForCount(1);
@@ -222,7 +238,7 @@
      * Tests ensures that Telecom disallow to place outgoing self-managed call when the ongoing
      * managed call can not be held.
      */
-    public void testDisallowOutgoingCallWhileOngoingManagedCallCanNotBeHeld() {
+    public void testDisallowOutgoingCallWhileOngoingManagedCallCanNotBeHeld() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
@@ -240,34 +256,47 @@
                 TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
 
         // THEN the new outgoing call is failed.
+        CtsSelfManagedConnectionService.waitForBinding();
         assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
                 CtsSelfManagedConnectionService.CREATE_OUTGOING_CONNECTION_FAILED_LOCK));
     }
 
     /**
      * Tests ability to add a new self-managed outgoing connection.
+     * <p>
+     * A self-managed {@link ConnectionService} shall be able to place an outgoing call to tel or
+     * sip {@link Uri}s without being interrupted by system UX or other Telephony-related logic.
      */
     public void testAddSelfManagedOutgoingConnection() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
-        TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
-                TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+        placeAndVerifyOutgoingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+    }
+
+    private void placeAndVerifyOutgoingCall(PhoneAccountHandle handle, Uri address) throws Exception {
+
+        TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager, handle, address);
 
         // Ensure Telecom bound to the self managed CS
         if (!CtsSelfManagedConnectionService.waitForBinding()) {
             fail("Could not bind to Self-Managed ConnectionService");
         }
 
-        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
-        assert(!connection.isIncomingCall());
+        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
+        assertNotNull("Self-Managed Connection should NOT be null.", connection);
+        assertTrue("Self-Managed Connection should be outgoing.", !connection.isIncomingCall());
 
+        // The self-managed ConnectionService must NOT have been prompted to show its incoming call
+        // UI for an outgoing call.
         assertEquals(connection.getOnShowIncomingUiInvokeCounter().getInvokeCount(), 0);
 
         setActiveAndVerify(connection);
 
         // Expect there to be no managed calls at the moment.
         assertFalse(mTelecomManager.isInManagedCall());
+        // But there should be a call (including self-managed).
+        assertTrue(mTelecomManager.isInCall());
 
         setDisconnectedAndVerify(connection);
     }
diff --git a/tests/tests/telephony/src/android/telephony/cts/CarrierConfigManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/CarrierConfigManagerTest.java
index 572b31a..7323f30 100644
--- a/tests/tests/telephony/src/android/telephony/cts/CarrierConfigManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/CarrierConfigManagerTest.java
@@ -78,6 +78,7 @@
                 config.getBoolean(CarrierConfigManager.KEY_VVM_PREFETCH_BOOL), true);
             assertEquals("KEY_CARRIER_VVM_PACKAGE_NAME_STRING doesn't match static default.",
                 config.getString(CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING), "");
+            assertFalse(CarrierConfigManager.isConfigForIdentifiedCarrier(config));
         }
     }
 
diff --git a/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java b/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java
index 8a13349..7745497 100644
--- a/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.os.Looper;
+import android.telephony.CellInfo;
 import android.telephony.CellLocation;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
@@ -28,6 +29,8 @@
 
 import com.android.compatibility.common.util.TestThread;
 
+import java.util.List;
+
 public class PhoneStateListenerTest extends  AndroidTestCase{
 
     public static final long WAIT_TIME = 1000;
@@ -38,7 +41,9 @@
     private boolean mOnUserMobileDataStateChanged;
     private boolean mOnDataActivityCalled;
     private boolean mOnDataConnectionStateChangedCalled;
+    private boolean mOnDataConnectionStateChangedWithNetworkTypeCalled;
     private boolean mOnMessageWaitingIndicatorChangedCalled;
+    private boolean mOnCellInfoChangedCalled;
     private boolean mOnServiceStateChangedCalled;
     private boolean mOnSignalStrengthChangedCalled;
     private SignalStrength mSignalStrength;
@@ -371,6 +376,13 @@
                             mLock.notify();
                         }
                     }
+                    @Override
+                    public void onDataConnectionStateChanged(int state, int networkType) {
+                        synchronized(mLock) {
+                            mOnDataConnectionStateChangedWithNetworkTypeCalled = true;
+                            mLock.notify();
+                        }
+                    }
                 };
                 mTelephonyManager.listen(
                         mListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
@@ -380,15 +392,18 @@
         });
 
         assertFalse(mOnDataConnectionStateChangedCalled);
+        assertFalse(mOnDataConnectionStateChangedWithNetworkTypeCalled);
         t.start();
 
         synchronized (mLock) {
-            while(!mOnDataConnectionStateChangedCalled){
+            while(!mOnDataConnectionStateChangedCalled ||
+                    !mOnDataConnectionStateChangedWithNetworkTypeCalled){
                 mLock.wait();
             }
         }
         t.checkException();
         assertTrue(mOnDataConnectionStateChangedCalled);
+        assertTrue(mOnDataConnectionStateChangedWithNetworkTypeCalled);
     }
 
     public void testOnDataActivity() throws Throwable {
@@ -428,6 +443,43 @@
         assertTrue(mOnDataActivityCalled);
     }
 
+    public void testOnCellInfoChanged() throws Throwable {
+        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
+            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+            return;
+        }
+
+        TestThread t = new TestThread(new Runnable() {
+            public void run() {
+                Looper.prepare();
+
+                mListener = new PhoneStateListener() {
+                    @Override
+                    public void onCellInfoChanged(List<CellInfo> cellInfo) {
+                        synchronized(mLock) {
+                            mOnCellInfoChangedCalled = true;
+                            mLock.notify();
+                        }
+                    }
+                };
+                mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_INFO);
+
+                Looper.loop();
+            }
+        });
+
+        assertFalse(mOnDataActivityCalled);
+        t.start();
+
+        synchronized (mLock) {
+            while(!mOnCellInfoChangedCalled){
+                mLock.wait();
+            }
+        }
+        t.checkException();
+        assertTrue(mOnCellInfoChangedCalled);
+    }
+
     public void testOnUserMobileDataStateChanged() throws Throwable {
         if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
             Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
diff --git a/tests/vr/jni/VrExtensionsJni.cpp b/tests/vr/jni/VrExtensionsJni.cpp
index c93ca62..4ab4e2a 100644
--- a/tests/vr/jni/VrExtensionsJni.cpp
+++ b/tests/vr/jni/VrExtensionsJni.cpp
@@ -177,6 +177,8 @@
     const int formats[] = {
       AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,
       AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+      AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,
+      AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT,
       // Do not test AHARDWAREBUFFER_FORMAT_BLOB, it isn't color-renderable.
     };
     const int samples[] = {1, 2, 4};
diff --git a/tools/cts-tradefed/res/config/retry.xml b/tools/cts-tradefed/res/config/retry.xml
index d425d8e..3a67455 100644
--- a/tools/cts-tradefed/res/config/retry.xml
+++ b/tools/cts-tradefed/res/config/retry.xml
@@ -37,7 +37,6 @@
 
     <option name="plan" value="cts-retry" />
     <option name="test-tag" value="cts" />
-    <option name="skip-device-info" value="true" />
     <option name="enable-root" value="false" />
 
     <!-- retain 200MB of host log -->