Merge "Adding more incidentd privacy filtering tests." into pi-dev
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-and-roll-caps.apk b/hostsidetests/appsecurity/res/pkgsigverify/v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-and-roll-caps.apk
new file mode 100644
index 0000000..8c8f140
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-and-roll-caps.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
index 05521b9..bb0735a 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
@@ -525,6 +525,19 @@
         assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
     }
 
+    public void testInstallV3KeyRotationToAncestor() throws Exception {
+        // tests that a v3 signed APK with RSA key cannot be upgraded by one of its past certs
+        assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-caps.apk");
+        assertInstallFails("v3-rsa-pkcs1-sha256-2048-1.apk");
+    }
+
+    public void testInstallV3KeyRotationToAncestorWithRollback() throws Exception {
+        // tests that a v3 signed APK with RSA key can be upgraded by one of its past certs if it
+        // has granted that cert the rollback capability
+        assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-2-with-por_1_2-full-and-roll-caps.apk");
+        assertInstallSucceeds("v3-rsa-pkcs1-sha256-2048-1.apk");
+    }
+
     public void testInstallV3KeyRotationMultipleHops() throws Exception {
         // tests that a v3 signed APK with RSA key can rotate to a new key which is the result of
         // multiple rotations from the original: APK signed with key 1 can be updated by key 3, when
diff --git a/libs/wrappedgtest/Android.mk b/libs/wrappedgtest/Android.mk
deleted file mode 100644
index f89ba9d..0000000
--- a/libs/wrappedgtest/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright 2012 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_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := ctswrappedgtest
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/libs/wrappedgtest/src/WrappedGTestActivity.java b/libs/wrappedgtest/src/WrappedGTestActivity.java
deleted file mode 100644
index 0633a5b..0000000
--- a/libs/wrappedgtest/src/WrappedGTestActivity.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2012 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.test.wrappedgtest;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.os.Bundle;
-
-public class WrappedGTestActivity extends Activity {
-
-    private WrappedGTestInstrumentation mInstrumentation;
-
-    public void setInstrumentation(WrappedGTestInstrumentation instrumentation) {
-        mInstrumentation = instrumentation;
-    }
-
-    public int runGTests() {
-        return runTests(this);
-    }
-
-    public void sendStatus(String output) {
-        Bundle outputBundle = new Bundle();
-        outputBundle.putString("gtest", output);
-        mInstrumentation.sendStatus(1, outputBundle);
-    }
-
-    protected static native int runTests(WrappedGTestActivity activity);
-}
diff --git a/libs/wrappedgtest/src/WrappedGTestInstrumentation.java b/libs/wrappedgtest/src/WrappedGTestInstrumentation.java
deleted file mode 100644
index b29aaab..0000000
--- a/libs/wrappedgtest/src/WrappedGTestInstrumentation.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012 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.test.wrappedgtest;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-
-
-public class WrappedGTestInstrumentation extends Instrumentation {
-
-    private static final String TAG = "WrappedGTestInstrumentation";
-    private WrappedGTestActivity mActivity;
-    protected Class mActivityClass;
-
-    public WrappedGTestInstrumentation() {
-    }
-
-    @Override
-    public void onCreate(Bundle arguments) {
-        // attempt to disable keyguard,  if current test has permission to do so
-        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
-                == PackageManager.PERMISSION_GRANTED) {
-            Log.i(TAG, "Disabling keyguard");
-            KeyguardManager keyguardManager =
-                (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
-            keyguardManager.newKeyguardLock("cts").disableKeyguard();
-        } else {
-            Log.i(TAG, "Test lacks permission to disable keyguard. " +
-                    "UI based tests may fail if keyguard is up");
-        }
-        super.onCreate(arguments);
-        start();
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-
-        Intent intent = new Intent(getTargetContext(), mActivityClass);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        mActivity = (WrappedGTestActivity)startActivitySync(intent);
-        mActivity.setInstrumentation(this);
-        mActivity.runGTests();
-
-        finish(Activity.RESULT_OK, new Bundle());
-    }
-}
diff --git a/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java b/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java
index a8d16b7..9e070ff9 100644
--- a/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java
+++ b/tests/app/src/android/app/cts/Instrumentation_ActivityMonitorTest.java
@@ -135,7 +135,8 @@
         final Context context = instrumentation.getTargetContext();
 
         // Start ActivityMonitorTestActivity
-        final Intent intent = new Intent(context, ActivityMonitorTestActivity.class);
+        final Intent intent = new Intent(context, ActivityMonitorTestActivity.class)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         ActivityMonitorTestActivity amTestActivity =
                 (ActivityMonitorTestActivity) instrumentation.startActivitySync(intent);
 
@@ -183,7 +184,8 @@
         final Context context = instrumentation.getTargetContext();
 
         // Start ActivityMonitorTestActivity
-        final Intent intent = new Intent(context, ActivityMonitorTestActivity.class);
+        final Intent intent = new Intent(context, ActivityMonitorTestActivity.class)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         ActivityMonitorTestActivity amTestActivity =
                 (ActivityMonitorTestActivity) instrumentation.startActivitySync(intent);
 
@@ -234,7 +236,8 @@
         final Context context = instrumentation.getTargetContext();
 
         // Start ActivityMonitorTestActivity
-        final Intent intent = new Intent(context, ActivityMonitorTestActivity.class);
+        final Intent intent = new Intent(context, ActivityMonitorTestActivity.class)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         ActivityMonitorTestActivity amTestActivity =
                 (ActivityMonitorTestActivity) instrumentation.startActivitySync(intent);
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index 3fd9fa3..d2353a1 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -15,6 +15,7 @@
 import static com.android.ex.camera2.blocking.BlockingSessionCallback.*;
 
 import android.graphics.ImageFormat;
+import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
@@ -307,6 +308,116 @@
         constrainedHighSpeedRecording(/*enableSessionParams*/ true);
     }
 
+    public void testAbandonedHighSpeedRequest() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.i(TAG, "Testing bad suface for createHighSpeedRequestList for camera " + id);
+                // Re-use the MediaRecorder object for the same camera device.
+                mMediaRecorder = new MediaRecorder();
+                openDevice(id);
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
+                if (!mStaticInfo.isConstrainedHighSpeedVideoSupported()) {
+                    Log.i(TAG, "Camera " + id +
+                            " does not support constrained high speed video, skipping");
+                    continue;
+                }
+
+                StreamConfigurationMap config =
+                        mStaticInfo.getValueFromKeyNonNull(
+                                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+                Size[] highSpeedVideoSizes = config.getHighSpeedVideoSizes();
+                Size size = highSpeedVideoSizes[0];
+                Range<Integer> fpsRange = getHighestHighSpeedFixedFpsRangeForSize(config, size);
+                mCollector.expectNotNull("Unable to find the fixed frame rate fps range for " +
+                        "size " + size, fpsRange);
+                if (fpsRange == null) {
+                    continue;
+                }
+
+                int captureRate = fpsRange.getLower();
+                int videoFramerate = captureRate / SLOWMO_SLOW_FACTOR;
+                // Skip the test if the highest recording FPS supported by CamcorderProfile
+                if (fpsRange.getUpper() > getFpsFromHighSpeedProfileForSize(size)) {
+                    Log.w(TAG, "high speed recording " + size + "@" + captureRate + "fps"
+                            + " is not supported by CamcorderProfile");
+                    continue;
+                }
+
+                mOutMediaFileName = VIDEO_FILE_PATH + "/test_video.mp4";
+                prepareRecording(size, videoFramerate, captureRate);
+                updatePreviewSurfaceWithVideo(size, captureRate);
+
+                List<Surface> outputSurfaces = new ArrayList<Surface>(2);
+                assertTrue("Both preview and recording surfaces should be valid",
+                        mPreviewSurface.isValid() && mRecordingSurface.isValid());
+
+                outputSurfaces.add(mPreviewSurface);
+                outputSurfaces.add(mRecordingSurface);
+
+                mSessionListener = new BlockingSessionCallback();
+                mSession = configureCameraSession(mCamera, outputSurfaces, /*highSpeed*/true,
+                        mSessionListener, mHandler);
+
+                CaptureRequest.Builder requestBuilder =
+                        mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
+                requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
+                requestBuilder.addTarget(mPreviewSurface);
+                requestBuilder.addTarget(mRecordingSurface);
+
+                // 1. Test abandoned MediaRecorder
+                releaseRecorder();
+                try {
+                    List<CaptureRequest> slowMoRequests =
+                            ((CameraConstrainedHighSpeedCaptureSession) mSession).
+                            createHighSpeedRequestList(requestBuilder.build());
+                    fail("Create high speed request on abandoned surface must fail!");
+                } catch (IllegalArgumentException e) {
+                    Log.i(TAG, "Release recording surface test passed");
+                    // expected
+                }
+
+                // 2. Test abandoned preview surface
+                mMediaRecorder = new MediaRecorder();
+                SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
+                Surface previewSurface = new Surface(preview);
+                preview.setDefaultBufferSize(size.getWidth(), size.getHeight());
+
+                outputSurfaces = new ArrayList<Surface>();
+                outputSurfaces.add(previewSurface);
+
+                prepareRecording(size, videoFramerate, captureRate);
+                updatePreviewSurfaceWithVideo(size, captureRate);
+
+                mSession = configureCameraSession(mCamera, outputSurfaces, /*highSpeed*/true,
+                        mSessionListener, mHandler);
+
+                requestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
+                requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
+                requestBuilder.addTarget(previewSurface);
+
+                // Abandon preview surface.
+                previewSurface.release();
+
+                try {
+                    List<CaptureRequest> slowMoRequests =
+                            ((CameraConstrainedHighSpeedCaptureSession) mSession).
+                            createHighSpeedRequestList(requestBuilder.build());
+                    fail("Create high speed request on abandoned preview surface must fail!");
+                } catch (IllegalArgumentException e) {
+                    Log.i(TAG, "Release preview surface test passed");
+                    // expected
+                }
+            } finally {
+                closeDevice();
+                releaseRecorder();
+            }
+        }
+    }
+
     /**
      * <p>
      * Test recording framerate accuracy when switching from low FPS to high FPS.
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index b047bd0..fa0742f 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -967,6 +967,63 @@
         }
     }
 
+    public void testConfigureAbandonedSurface() throws Exception {
+        for (String id : mCameraIds) {
+            Log.i(TAG, String.format(
+                    "Testing Camera %s for configuring abandoned surface", id));
+
+            openDevice(id);
+            try {
+                SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
+                Surface previewSurface = new Surface(preview);
+
+                // Abandon preview SurfaceTexture.
+                preview.release();
+
+                try {
+                    CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview);
+                    fail("Configuring abandoned surfaces must fail!");
+                } catch (IllegalArgumentException e) {
+                    // expected
+                    Log.i(TAG, "normal session check passed");
+                }
+
+                // Try constrained high speed session/requests
+                if (!mStaticInfo.isConstrainedHighSpeedVideoSupported()) {
+                    continue;
+                }
+
+                List<Surface> surfaces = new ArrayList<>();
+                surfaces.add(previewSurface);
+                CameraCaptureSession.StateCallback sessionListener =
+                        mock(CameraCaptureSession.StateCallback.class);
+
+                try {
+                    mCamera.createConstrainedHighSpeedCaptureSession(surfaces,
+                            sessionListener, mHandler);
+                    fail("Configuring abandoned surfaces in high speed session must fail!");
+                } catch (IllegalArgumentException e) {
+                    // expected
+                    Log.i(TAG, "high speed session check 1 passed");
+                }
+
+                // Also try abandone the Surface directly
+                previewSurface.release();
+
+                try {
+                    mCamera.createConstrainedHighSpeedCaptureSession(surfaces,
+                            sessionListener, mHandler);
+                    fail("Configuring abandoned surfaces in high speed session must fail!");
+                } catch (IllegalArgumentException e) {
+                    // expected
+                    Log.i(TAG, "high speed session check 2 passed");
+                }
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
     public void testAfSceneChange() throws Exception {
         final int NUM_FRAMES_VERIFIED = 3;
 
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
index 636a6b8..e8b0463 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
@@ -414,7 +414,7 @@
                 result = mNsm.querySummary(
                         mNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
-                assertTrue(result != null);
+                assertNotNull(result);
                 NetworkStats.Bucket bucket = new NetworkStats.Bucket();
                 long totalTxPackets = 0;
                 long totalRxPackets = 0;
@@ -448,8 +448,6 @@
                 assertTrue("No Rx packets usage for uid " + Process.myUid(), totalRxPackets > 0);
                 assertTrue("No Tx bytes usage for uid " + Process.myUid(), totalTxBytes > 0);
                 assertTrue("No Tx packets usage for uid " + Process.myUid(), totalTxPackets > 0);
-            } catch (RemoteException | SecurityException e) {
-                fail("testAppSummary fails with exception: " + e.toString());
             } finally {
                 if (result != null) {
                     result.close();
@@ -481,31 +479,16 @@
                 result = mNsm.queryDetails(
                         mNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime);
-                assertTrue(result != null);
-                NetworkStats.Bucket bucket = new NetworkStats.Bucket();
-                long totalTxPackets = 0;
-                long totalRxPackets = 0;
-                long totalTxBytes = 0;
-                long totalRxBytes = 0;
-                while (result.hasNextBucket()) {
-                    assertTrue(result.getNextBucket(bucket));
-                    assertTimestamps(bucket);
-                    assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_ALL);
-                    assertEquals(bucket.getMetered(), NetworkStats.Bucket.METERED_ALL);
-                    assertEquals(bucket.getDefaultNetwork(),
-                            NetworkStats.Bucket.DEFAULT_NETWORK_ALL);
-                    if (bucket.getUid() == Process.myUid()) {
-                        totalTxPackets += bucket.getTxPackets();
-                        totalRxPackets += bucket.getRxPackets();
-                        totalTxBytes += bucket.getTxBytes();
-                        totalRxBytes += bucket.getRxBytes();
-                    }
-                }
-                assertFalse(result.getNextBucket(bucket));
-                assertTrue("No Rx bytes usage for uid " + Process.myUid(), totalRxBytes > 0);
-                assertTrue("No Rx packets usage for uid " + Process.myUid(), totalRxPackets > 0);
-                assertTrue("No Tx bytes usage for uid " + Process.myUid(), totalTxBytes > 0);
-                assertTrue("No Tx packets usage for uid " + Process.myUid(), totalTxPackets > 0);
+                long totalBytesWithSubscriberId = getTotalAndAssertNotEmpty(result);
+
+                // Test without filtering by subscriberId
+                result = mNsm.queryDetails(
+                        mNetworkInterfacesToTest[i].getNetworkType(), null,
+                        mStartTime, mEndTime);
+
+                assertTrue("More bytes with subscriberId filter than without.",
+                        getTotalAndAssertNotEmpty(result) >= totalBytesWithSubscriberId);
+
             } catch (RemoteException | SecurityException e) {
                 fail("testAppDetails fails with exception: " + e.toString());
             } finally {
@@ -539,7 +522,7 @@
                 result = mNsm.queryDetailsForUid(
                         mNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime, Process.myUid());
-                assertTrue(result != null);
+                assertNotNull(result);
                 NetworkStats.Bucket bucket = new NetworkStats.Bucket();
                 long totalTxPackets = 0;
                 long totalRxPackets = 0;
@@ -563,8 +546,6 @@
                 assertTrue("No Rx packets usage for uid " + Process.myUid(), totalRxPackets > 0);
                 assertTrue("No Tx bytes usage for uid " + Process.myUid(), totalTxBytes > 0);
                 assertTrue("No Tx packets usage for uid " + Process.myUid(), totalTxPackets > 0);
-            } catch (RemoteException | SecurityException e) {
-                fail("testUidDetails fails with exception: " + e.toString());
             } finally {
                 if (result != null) {
                     result.close();
@@ -576,8 +557,6 @@
                         mNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime, Process.myUid());
                 fail("negative testUidDetails fails: no exception thrown.");
-            } catch (RemoteException e) {
-                fail("testUidDetails fails with exception: " + e.toString());
             } catch (SecurityException e) {
                 // expected outcome
             }
@@ -596,7 +575,7 @@
                 result = mNsm.queryDetailsForUidTag(
                         mNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
                         mStartTime, mEndTime, Process.myUid(), NETWORK_TAG);
-                assertTrue(result != null);
+                assertNotNull(result);
                 NetworkStats.Bucket bucket = new NetworkStats.Bucket();
                 long totalTxPackets = 0;
                 long totalRxPackets = 0;
@@ -619,14 +598,72 @@
                 }
                 assertTrue("No Rx bytes tagged with 0x" + Integer.toHexString(NETWORK_TAG)
                         + " for uid " + Process.myUid(), totalRxBytes > 0);
-                assertTrue("No Rx packets tagged with " + Integer.toHexString(NETWORK_TAG)
+                assertTrue("No Rx packets tagged with 0x" + Integer.toHexString(NETWORK_TAG)
                         + " for uid " + Process.myUid(), totalRxPackets > 0);
                 assertTrue("No Tx bytes tagged with 0x" + Integer.toHexString(NETWORK_TAG)
                         + " for uid " + Process.myUid(), totalTxBytes > 0);
                 assertTrue("No Tx packets tagged with 0x" + Integer.toHexString(NETWORK_TAG)
                         + " for uid " + Process.myUid(), totalTxPackets > 0);
+            } finally {
+                if (result != null) {
+                    result.close();
+                }
+            }
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
+            try {
+                result = mNsm.queryDetailsForUidTag(
+                        mNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
+                        mStartTime, mEndTime, Process.myUid(), NETWORK_TAG);
+                fail("negative testUidDetails fails: no exception thrown.");
             } catch (SecurityException e) {
-                fail("testUidDetails fails with exception: " + e.toString());
+                // expected outcome
+            }
+        }
+    }
+
+    public void testUidTagStateDetails() throws Exception {
+        for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
+            // Relatively large tolerance to accommodate for history bucket size.
+            if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
+                continue;
+            }
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
+            NetworkStats result = null;
+            try {
+                // Assume test is running in the background and thus is in STATE_DEFAULT.
+                result = mNsm.queryDetailsForUidTagState(
+                        mNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
+                        mStartTime, mEndTime, Process.myUid(), NETWORK_TAG,
+                        NetworkStats.Bucket.STATE_DEFAULT);
+                assertNotNull(result);
+                NetworkStats.Bucket bucket = new NetworkStats.Bucket();
+                long totalTxPackets = 0;
+                long totalRxPackets = 0;
+                long totalTxBytes = 0;
+                long totalRxBytes = 0;
+                while (result.hasNextBucket()) {
+                    assertTrue(result.getNextBucket(bucket));
+                    assertTimestamps(bucket);
+                    assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_DEFAULT);
+                    assertEquals(bucket.getMetered(), NetworkStats.Bucket.METERED_ALL);
+                    assertEquals(bucket.getDefaultNetwork(),
+                            NetworkStats.Bucket.DEFAULT_NETWORK_ALL);
+                    assertEquals(bucket.getUid(), Process.myUid());
+                    if (bucket.getTag() == NETWORK_TAG) {
+                        totalTxPackets += bucket.getTxPackets();
+                        totalRxPackets += bucket.getRxPackets();
+                        totalTxBytes += bucket.getTxBytes();
+                        totalRxBytes += bucket.getRxBytes();
+                    }
+                }
+                assertTrue("No Rx bytes tagged with 0x" + Integer.toHexString(NETWORK_TAG)
+                        + " for uid " + Process.myUid(), totalRxBytes > 0);
+                assertTrue("No Rx packets tagged with 0x" + Integer.toHexString(NETWORK_TAG)
+                        + " for uid " + Process.myUid(), totalRxPackets > 0);
+                assertTrue("No Tx bytes tagged with 0x" + Integer.toHexString(NETWORK_TAG)
+                        + " for uid " + Process.myUid(), totalTxBytes > 0);
+                assertTrue("No Tx packets tagged with 0x" + Integer.toHexString(NETWORK_TAG)
+                        + " for uid " + Process.myUid(), totalTxPackets > 0);
             } finally {
                 if (result != null) {
                     result.close();
@@ -668,6 +705,36 @@
         }
     }
 
+    private long getTotalAndAssertNotEmpty(NetworkStats result) {
+        assertTrue(result != null);
+        NetworkStats.Bucket bucket = new NetworkStats.Bucket();
+        long totalTxPackets = 0;
+        long totalRxPackets = 0;
+        long totalTxBytes = 0;
+        long totalRxBytes = 0;
+        while (result.hasNextBucket()) {
+            assertTrue(result.getNextBucket(bucket));
+            assertTimestamps(bucket);
+            assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_ALL);
+            assertEquals(bucket.getMetered(), NetworkStats.Bucket.METERED_ALL);
+            assertEquals(bucket.getDefaultNetwork(),
+                    NetworkStats.Bucket.DEFAULT_NETWORK_ALL);
+            if (bucket.getUid() == Process.myUid()) {
+                totalTxPackets += bucket.getTxPackets();
+                totalRxPackets += bucket.getRxPackets();
+                totalTxBytes += bucket.getTxBytes();
+                totalRxBytes += bucket.getRxBytes();
+            }
+        }
+        assertFalse(result.getNextBucket(bucket));
+        assertTrue("No Rx bytes usage for uid " + Process.myUid(), totalRxBytes > 0);
+        assertTrue("No Rx packets usage for uid " + Process.myUid(), totalRxPackets > 0);
+        assertTrue("No Tx bytes usage for uid " + Process.myUid(), totalTxBytes > 0);
+        assertTrue("No Tx packets usage for uid " + Process.myUid(), totalTxPackets > 0);
+
+        return totalRxBytes + totalTxBytes;
+    }
+
     private void assertTimestamps(final NetworkStats.Bucket bucket) {
         assertTrue("Start timestamp " + bucket.getStartTimeStamp() + " is less than " +
                 mStartTime, bucket.getStartTimeStamp() >= mStartTime);
diff --git a/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java b/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
index 4e1469b..f27f06c 100644
--- a/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
+++ b/tests/tests/content/src/android/content/res/cts/TypedArrayTest.java
@@ -55,8 +55,7 @@
     private static final String EXPECTED_NON_RESOURCE_STRING = "testNonResourcesString";
     private static final String XML_BEGIN = "resources";
     private static final int EXPECTED_INT_ATT = 86400;
-    private static final int EXPECTED_CHANGING_CONFIG =
-            ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_LOCALE;
+    private static final int EXPECTED_CHANGING_CONFIG = ActivityInfo.CONFIG_ORIENTATION;
 
     private TypedArray mTypedArray;
 
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 07f1ff7..f4715fc 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -89,6 +89,8 @@
     <protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
     <protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" />
+    <protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
+    <protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
 
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
@@ -180,6 +182,8 @@
     <protected-broadcast
         android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
     <protected-broadcast
+        android:name="android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED" />
+    <protected-broadcast
         android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
         android:name="android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED" />
@@ -1100,6 +1104,8 @@
 
     <!-- Allows an app to use fingerprint hardware.
          <p>Protection level: normal
+         @deprecated Applications should request {@link
+         android.Manifest.permission#USE_BIOMETRIC} instead
     -->
     <permission android:name="android.permission.USE_FINGERPRINT"
         android:permissionGroup="android.permission-group.SENSORS"
@@ -1107,6 +1113,15 @@
         android:description="@string/permdesc_useFingerprint"
         android:protectionLevel="normal" />
 
+    <!-- Allows an app to use device supported biometric modalities.
+         <p>Protection level: normal
+    -->
+    <permission android:name="android.permission.USE_BIOMETRIC"
+        android:permissionGroup="android.permission-group.SENSORS"
+        android:label="@string/permlab_useBiometric"
+        android:description="@string/permdesc_useBiometric"
+        android:protectionLevel="normal" />
+
     <!-- ====================================================================== -->
     <!-- REMOVED PERMISSIONS                                                    -->
     <!-- ====================================================================== -->
@@ -1341,6 +1356,13 @@
         android:label="@string/permlab_changeWifiState"
         android:protectionLevel="normal" />
 
+    <!-- @SystemApi @hide Allows apps to create and manage IPsec tunnels.
+         <p>Only granted to applications that are currently bound by the
+         system for creating and managing IPsec-based interfaces.
+    -->
+    <permission android:name="android.permission.MANAGE_IPSEC_TUNNELS"
+        android:protectionLevel="signature|appop" />
+
     <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
@@ -1441,6 +1463,13 @@
         android:label="@string/permlab_bluetooth"
         android:protectionLevel="normal" />
 
+    <!-- @SystemApi Allows an application to suspend other apps, which will prevent the user
+         from using them until they are unsuspended.
+         @hide
+    -->
+    <permission android:name="android.permission.SUSPEND_APPS"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows applications to discover and pair bluetooth devices.
          <p>Protection level: normal
     -->
@@ -1987,11 +2016,11 @@
     <permission android:name="android.permission.REMOVE_TASKS"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi @hide Allows an application to create/manage/remove stacks -->
+    <!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks -->
     <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
         android:protectionLevel="signature|privileged|development" />
 
-    <!-- @SystemApi @hide Allows an application to embed other activities -->
+    <!-- @SystemApi @TestApi @hide Allows an application to embed other activities -->
     <permission android:name="android.permission.ACTIVITY_EMBEDDING"
                 android:protectionLevel="signature|privileged|development" />
 
@@ -3092,6 +3121,12 @@
     <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to control the color saturation of the display.
+         @hide
+         @SystemApi -->
+    <permission android:name="android.permission.CONTROL_DISPLAY_SATURATION"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to collect usage infomation about brightness slider changes.
          <p>Not for use by third-party applications.</p>
          @hide
@@ -3274,6 +3309,11 @@
         android:protectionLevel="signature|privileged|development|appop" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
+    <!-- @hide @SystemApi Allows an application to observe usage time of apps. The app can register
+         for callbacks when apps reach a certain usage time limit, etc. -->
+    <permission android:name="android.permission.OBSERVE_APP_USAGE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @hide @SystemApi Allows an application to change the app idle state of an app.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
@@ -3310,8 +3350,9 @@
     <permission android:name="android.permission.BACKUP"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows application to manage RecoverableKeyStoreLoader.
-    <p>Not for use by third-party applications.
+    <!-- @SystemApi Allows application to manage
+         {@link android.security.keystore.recovery.RecoveryController}.
+         <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.RECOVER_KEYSTORE"
         android:protectionLevel="signature|privileged" />
@@ -4207,6 +4248,16 @@
                   android:exported="false">
         </receiver>
 
+        <receiver android:name="com.android.server.am.BatteryStatsService$UsbConnectionReceiver"
+                  android:exported="false">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.hardware.usb.action.USB_STATE" />
+            </intent-filter>
+        </receiver>
+
         <service android:name="android.hardware.location.GeofenceHardwareService"
             android:permission="android.permission.LOCATION_HARDWARE"
             android:exported="false" />
diff --git a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
index 37b9461..be999f5 100644
--- a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
@@ -82,6 +82,7 @@
         "android.net.conn.TETHER_STATE_CHANGED",
         "android.net.conn.INET_CONDITION_ACTION",
         "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED",
+        "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED",
         "com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER"
     };
 
diff --git a/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java
index f7ec3b7..7ed8049 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -16,63 +16,241 @@
 
 package android.telephony.cts;
 
-import android.content.Context;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
-import android.os.Looper;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.test.AndroidTestCase;
-import android.util.Log;
+import android.telephony.SubscriptionPlan;
 
-import com.android.compatibility.common.util.TestThread;
+import com.android.compatibility.common.util.SystemUtil;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.ZonedDateTime;
+import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
 
-public class SubscriptionManagerTest extends AndroidTestCase {
-    private SubscriptionManager mSubscriptionManager;
-    private static ConnectivityManager mCm;
-    private SubscriptionManager.OnSubscriptionsChangedListener mListener;
-    private final Object mLock = new Object();
-    private boolean mOnSubscriptionsChangedCalled = false;
-    private static final int TOLERANCE = 1000;
-    private static final String TAG = "android.telephony.cts.SubscriptionManagerTest";
+@RunWith(AndroidJUnit4.class)
+public class SubscriptionManagerTest {
+    private SubscriptionManager mSm;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mSubscriptionManager = new SubscriptionManager(getContext());
-        mCm = (ConnectivityManager)getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+    private int mSubId;
+    private String mPackageName;
+
+    @Before
+    public void setUp() throws Exception {
+        mSm = InstrumentationRegistry.getContext().getSystemService(SubscriptionManager.class);
+        mSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+        mPackageName = InstrumentationRegistry.getContext().getPackageName();
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        if (mListener != null) {
-            // unregister the listener
-            mSubscriptionManager.removeOnSubscriptionsChangedListener(mListener);
+    /**
+     * Sanity check that both {@link PackageManager#FEATURE_TELEPHONY} and
+     * {@link NetworkCapabilities#TRANSPORT_CELLULAR} network must both be
+     * either defined or undefined; you can't cross the streams.
+     */
+    @Test
+    public void testSanity() throws Exception {
+        final boolean hasCellular = findCellularNetwork() != null;
+        if (isSupported() && !hasCellular) {
+            fail("Device claims to support " + PackageManager.FEATURE_TELEPHONY
+                    + " but has no active cellular network, which is required for validation");
+        } else if (!isSupported() && hasCellular) {
+            fail("Device has active cellular network, but claims to not support "
+                    + PackageManager.FEATURE_TELEPHONY);
         }
-        super.tearDown();
+
+        if (isSupported()) {
+            if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+                fail("Device must have a valid default data subId for validation");
+            }
+        }
     }
 
-    public void testGetActiveSubscriptionInfoCount() {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
-            return;
-        }
-        assertTrue(mSubscriptionManager.getActiveSubscriptionInfoCount() <=
-                mSubscriptionManager.getActiveSubscriptionInfoCountMax());
+    @Test
+    public void testGetActiveSubscriptionInfoCount() throws Exception {
+        if (!isSupported()) return;
+
+        assertTrue(mSm.getActiveSubscriptionInfoCount() <=
+                mSm.getActiveSubscriptionInfoCountMax());
     }
 
-    public void testActiveSubscriptions() {
-        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
-            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
-            return;
-        }
-        List<SubscriptionInfo> subList = mSubscriptionManager.getActiveSubscriptionInfoList();
+    @Test
+    public void testActiveSubscriptions() throws Exception {
+        if (!isSupported()) return;
+
+        List<SubscriptionInfo> subList = mSm.getActiveSubscriptionInfoList();
         // Assert when there is no sim card present or detected
-        assertTrue(subList != null && subList.size() > 0);
+        assertNotNull("Active subscriber required", subList);
+        assertFalse("Active subscriber required", subList.isEmpty());
         for (int i = 0; i < subList.size(); i++) {
             assertTrue(subList.get(i).getSubscriptionId() >= 0);
             assertTrue(subList.get(i).getSimSlotIndex() >= 0);
         }
     }
+
+    @Test
+    public void testSubscriptionPlans() throws Exception {
+        if (!isSupported()) return;
+
+        // Make ourselves the owner
+        setSubPlanOwner(mSubId, mPackageName);
+
+        // Push empty list and we get empty back
+        mSm.setSubscriptionPlans(mSubId, Arrays.asList());
+        assertEquals(Arrays.asList(), mSm.getSubscriptionPlans(mSubId));
+
+        // Push simple plan and get it back
+        final SubscriptionPlan plan = buildSubscriptionPlan();
+        mSm.setSubscriptionPlans(mSubId, Arrays.asList(plan));
+        assertEquals(Arrays.asList(plan), mSm.getSubscriptionPlans(mSubId));
+
+        // Now revoke our access
+        setSubPlanOwner(mSubId, null);
+        try {
+            mSm.setSubscriptionPlans(mSubId, Arrays.asList());
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            mSm.getSubscriptionPlans(mSubId);
+            fail();
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testSubscriptionPlansOverrideCongested() throws Exception {
+        if (!isSupported()) return;
+
+        // Make ourselves the owner
+        setSubPlanOwner(mSubId, mPackageName);
+
+        // Missing plans means no overrides
+        mSm.setSubscriptionPlans(mSubId, Arrays.asList());
+        try {
+            mSm.setSubscriptionOverrideCongested(mSubId, true, 0);
+            fail();
+        } catch (SecurityException | IllegalStateException expected) {
+        }
+
+        // Defining plans means we get to override
+        final SubscriptionPlan plan = buildSubscriptionPlan();
+        mSm.setSubscriptionPlans(mSubId, Arrays.asList(plan));
+        mSm.setSubscriptionOverrideCongested(mSubId, true, 0);
+        mSm.setSubscriptionOverrideCongested(mSubId, false, 0);
+
+        // Now revoke our access
+        setSubPlanOwner(mSubId, null);
+        try {
+            mSm.setSubscriptionOverrideCongested(mSubId, true, 0);
+            fail();
+        } catch (SecurityException | IllegalStateException expected) {
+        }
+    }
+
+    @Test
+    public void testSubscriptionPlansOverrideUnmetered() throws Exception {
+        if (!isSupported()) return;
+
+        final ConnectivityManager cm = InstrumentationRegistry.getContext()
+                .getSystemService(ConnectivityManager.class);
+        final Network net = findCellularNetwork();
+        assertNotNull("Active cellular network required", net);
+
+        // Make ourselves the owner and define some plans
+        setSubPlanOwner(mSubId, mPackageName);
+        mSm.setSubscriptionPlans(mSubId, Arrays.asList(buildSubscriptionPlan()));
+
+        // Cellular is metered by default
+        assertFalse(cm.getNetworkCapabilities(net).hasCapability(NET_CAPABILITY_NOT_METERED));
+
+        // Override should make it go unmetered
+        {
+            final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> {
+                return caps.hasCapability(NET_CAPABILITY_NOT_METERED);
+            });
+            mSm.setSubscriptionOverrideUnmetered(mSubId, true, 0);
+            latch.await(10, TimeUnit.SECONDS);
+        }
+
+        // Clearing override should make it go metered
+        {
+            final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> {
+                return !caps.hasCapability(NET_CAPABILITY_NOT_METERED);
+            });
+            mSm.setSubscriptionOverrideUnmetered(mSubId, false, 0);
+            latch.await(10, TimeUnit.SECONDS);
+        }
+    }
+
+    public static CountDownLatch waitForNetworkCapabilities(Network network,
+            Predicate<NetworkCapabilities> predicate) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ConnectivityManager cm = InstrumentationRegistry.getContext()
+                .getSystemService(ConnectivityManager.class);
+        cm.registerNetworkCallback(new NetworkRequest.Builder().build(),
+                new NetworkCallback() {
+                    @Override
+                    public void onCapabilitiesChanged(Network net, NetworkCapabilities caps) {
+                        if (net.equals(network) && predicate.test(caps)) {
+                            latch.countDown();
+                            cm.unregisterNetworkCallback(this);
+                        }
+                    }
+                });
+        return latch;
+    }
+
+    private static SubscriptionPlan buildSubscriptionPlan() {
+        return SubscriptionPlan.Builder
+                .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"))
+                .setTitle("CTS")
+                .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
+                .setDataUsage(500_000_000, System.currentTimeMillis())
+                .build();
+    }
+
+    private static @Nullable Network findCellularNetwork() {
+        final ConnectivityManager cm = InstrumentationRegistry.getContext()
+                .getSystemService(ConnectivityManager.class);
+        for (Network net : cm.getAllNetworks()) {
+            final NetworkCapabilities caps = cm.getNetworkCapabilities(net);
+            if (caps != null && caps.hasTransport(TRANSPORT_CELLULAR)) {
+                return net;
+            }
+        }
+        return null;
+    }
+
+    private static boolean isSupported() {
+        return InstrumentationRegistry.getContext().getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+    }
+
+    private static void setSubPlanOwner(int subId, String packageName) throws Exception {
+        SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
+                "cmd netpolicy set sub-plan-owner " + subId + " " + packageName);
+    }
 }