Merge "Tests for DocumentsProvider and DocumentsUI." into lmp-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index c01f827..ce67d37 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -36,11 +36,28 @@
     CtsSplitApp_mips \
     CtsSplitAppDiffVersion \
     CtsSplitAppDiffCert \
+    CtsSplitAppFeature \
     CtsTargetInstrumentationApp \
     CtsUsePermissionDiffCert \
     CtsWriteExternalStorageApp \
     CtsMultiUserStorageApp
 
+cts_security_keysets_list := \
+    CtsKeySetTestApp \
+    CtsKeySetPermDefSigningA \
+    CtsKeySetPermDefSigningB\
+    CtsKeySetPermUseSigningA \
+    CtsKeySetPermUseSigningB \
+    CtsKeySetSigningAUpgradeA \
+    CtsKeySetSigningBUpgradeA \
+    CtsKeySetSigningAUpgradeAAndB \
+    CtsKeySetSigningAUpgradeAOrB \
+    CtsKeySetSigningAUpgradeB \
+    CtsKeySetSigningBUpgradeB \
+    CtsKeySetSigningAAndBUpgradeA \
+    CtsKeySetSigningAAndCUpgradeB \
+    CtsKeySetSigningAUpgradeNone
+
 cts_support_packages := \
     CtsAccelerationTestStubs \
     CtsAppTestStubs \
@@ -60,7 +77,8 @@
     TestDeviceSetup \
     CtsUiAutomatorApp \
     CtsUsbSerialTestApp \
-    $(cts_security_apps_list)
+    $(cts_security_apps_list) \
+    $(cts_security_keysets_list)
 
 cts_external_packages := \
     com.replica.replicaisland \
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 503d024..f37e1fa 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1247,6 +1247,7 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_managed_provisioning" />
+            <meta-data android:name="test_required_features" android:value="android.software.managed_users:android.software.device_admin" />
         </activity>
 
 
@@ -1262,6 +1263,7 @@
                 <category android:name="android.intent.category.DEFAULT"></category>
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_managed_provisioning" />
+            <meta-data android:name="test_required_features" android:value="android.software.managed_users:android.software.device_admin" />
         </activity>
 
         <activity android:name=".managedprovisioning.ByodHelperActivity">
@@ -1272,6 +1274,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".managedprovisioning.CrossProfileTestActivity">
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE" />
+                <category android:name="android.intent.category.DEFAULT"></category>
+            </intent-filter>
+        </activity>
+
         <receiver android:name=".managedprovisioning.DeviceAdminTestReceiver"
                 android:label="@string/provisioning_byod_device_admin"
                 android:permission="android.permission.BIND_DEVICE_ADMIN">
diff --git a/apps/CtsVerifier/res/layout/provisioning_byod.xml b/apps/CtsVerifier/res/layout/provisioning_byod.xml
index 5e59558..989266f 100644
--- a/apps/CtsVerifier/res/layout/provisioning_byod.xml
+++ b/apps/CtsVerifier/res/layout/provisioning_byod.xml
@@ -41,7 +41,7 @@
     <ListView
         android:id="@id/android:list"
         android:layout_width="match_parent"
-        android:layout_height="258dp" />
+        android:layout_height="wrap_content" />
 
     <include layout="@layout/pass_fail_buttons" />
 
diff --git a/apps/CtsVerifier/res/layout/provisioning_cross_profile.xml b/apps/CtsVerifier/res/layout/provisioning_cross_profile.xml
new file mode 100644
index 0000000..345e99d
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/provisioning_cross_profile.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical" >
+    <TextView android:id="@+id/text"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <Button
+        android:id="@+id/button_finish"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/provisioning_button_finish" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index bb755cd..22e0cff 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1215,6 +1215,19 @@
     <string name="provisioning_byod_profile_visible">Work profile visible in Settings</string>
     <string name="provisioning_byod_admin_visible">Device administrator visible in Settings</string>
     <string name="provisioning_byod_workapps_visible">Badged work apps visible in Launcher</string>
+    <string name="provisioning_byod_cross_profile">Open app cross profiles</string>
+    <string name="provisioning_byod_cross_profile_app_personal">
+        You selected the CTS Verifier option.
+    </string>
+    <string name="provisioning_byod_cross_profile_app_work">You selected the Work option.</string>
+    <string name="provisioning_byod_cross_profile_instruction">
+        Please press the Go button to start an action.\n
+        \n
+        You should be asked to choose either \"CTS Verifier\" or \"Work\" to complete the action.
+        Pressing either should bring up a page stating your choice.\n
+        \n
+        Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
+    </string>
     <string name="provisioning_byod_profile_visible_instruction">
         Please press the Go button to open the Settings page.
         Navigate to Accounts and confirm that:\n
@@ -1247,6 +1260,8 @@
     <string name="provisioning_byod_profile_deleted">Work profile deleted.</string>
     <string name="provisioning_byod_disabled">Device provisioning is not enabled.</string>
     <string name="provisioning_byod_go">Go</string>
+    <string name="provisioning_button_finish">Finish</string>
+    <string name="provisioning_cross_profile_chooser">Choose an app to complete action</string>
 
     <!-- Strings for DeviceOwnerProvisioningTest -->
     <string name="provisioning_device_owner">Device Owner Provisioning</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
index d71dca2..178a811 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
@@ -69,7 +69,7 @@
     private List<SelectableResolution> mSupportedResolutions;
     private ArrayAdapter<SelectableResolution> mAdapter;
 
-    private int mCameraId;
+    private SelectableResolution mSelectedResolution;
     private Camera mCamera;
     private Size mSurfaceSize;
     private boolean mCameraInitialized = false;
@@ -165,12 +165,7 @@
                     AdapterView<?> parent, View view, int position, long id) {
                 if (mSupportedResolutions != null) {
                     SelectableResolution resolution = mSupportedResolutions.get(position);
-
-                    switchToCamera(resolution.cameraId, false);
-
-                    Camera.Parameters params = mCamera.getParameters();
-                    params.setPictureSize(resolution.width, resolution.height);
-                    mCamera.setParameters(params);
+                    switchToCamera(resolution, false);
 
                     // It should be guaranteed that the FOV is correctly updated after setParameters().
                     mReportedFovPrePictureTaken = mCamera.getParameters().getHorizontalViewAngle();
@@ -376,7 +371,7 @@
                     public void onCancel(DialogInterface arg0) {
                         // User cancelled preview size selection.
                         mPreviewSizes = null;
-                        switchToCamera(mCameraId, true);
+                        switchToCamera(mSelectedResolution, true);
                     }
                 }).
                 setSingleChoiceItems(choices, 0, new DialogInterface.OnClickListener() {
@@ -389,7 +384,7 @@
 
                         if (mPreviewSizeCamerasToProcess.isEmpty()) {
                             // We're done, re-initialize camera.
-                            switchToCamera(mCameraId, true);
+                            switchToCamera(mSelectedResolution, true);
                         } else {
                             // Process other cameras.
                             showNextDialogToChoosePreviewSize();
@@ -415,7 +410,7 @@
 
         // Either use chosen preview size for current camera or automatically
         // choose preview size based on view dimensions.
-        Size selectedPreviewSize = (mPreviewSizes != null) ? mPreviewSizes[mCameraId] :
+        Size selectedPreviewSize = (mPreviewSizes != null) ? mPreviewSizes[mSelectedResolution.cameraId] :
             getBestPreviewSize(mSurfaceSize.width, mSurfaceSize.height, params);
         if (selectedPreviewSize != null) {
             params.setPreviewSize(selectedPreviewSize.width, selectedPreviewSize.height);
@@ -427,19 +422,20 @@
 
     private void startPreview() {
         if (mCameraInitialized && mCamera != null) {
-            setCameraDisplayOrientation(this, mCameraId, mCamera);
+            setCameraDisplayOrientation(this, mSelectedResolution.cameraId, mCamera);
             mCamera.startPreview();
             mPreviewActive = true;
         }
     }
 
-    private void switchToCamera(int cameraId, boolean initializeCamera) {
+    private void switchToCamera(SelectableResolution resolution, boolean initializeCamera) {
         if (mCamera != null) {
             mCamera.stopPreview();
             mCamera.release();
         }
-        mCameraId = cameraId;
-        mCamera = Camera.open(cameraId);
+
+        mSelectedResolution = resolution;
+        mCamera = Camera.open(mSelectedResolution.cameraId);
 
         if (initializeCamera){
           initializeCamera();
@@ -472,7 +468,7 @@
      * Set the common camera parameters on the given camera and returns the
      * parameter object for further modification, if needed.
      */
-    private static Camera.Parameters setCameraParams(Camera camera) {
+    private Camera.Parameters setCameraParams(Camera camera) {
         // The picture size is taken and set from the spinner selection
         // callback.
         Camera.Parameters params = camera.getParameters();
@@ -480,6 +476,7 @@
         params.setJpegQuality(100);
         params.setFocusMode(getFocusMode(camera));
         params.setZoom(0);
+        params.setPictureSize(mSelectedResolution.width, mSelectedResolution.height);
         return params;
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index 69071f6..da823e8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -73,6 +73,7 @@
     private TestItem mProfileVisibleTest;
     private TestItem mDeviceAdminVisibleTest;
     private TestItem mWorkAppVisibleTest;
+    private TestItem mCrossProfileIntentFiltersTest;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -173,11 +174,19 @@
                 R.string.provisioning_byod_workapps_visible_instruction,
                 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME));
 
+        Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
+        Intent chooser = Intent.createChooser(intent, getResources().getString(R.string.provisioning_cross_profile_chooser));
+        mCrossProfileIntentFiltersTest = new TestItem(this,
+                R.string.provisioning_byod_cross_profile,
+                R.string.provisioning_byod_cross_profile_instruction,
+                chooser);
+
         mTests.add(mDiskEncryptionTest);
         mTests.add(mProfileOwnerInstalled);
         mTests.add(mProfileVisibleTest);
         mTests.add(mDeviceAdminVisibleTest);
         mTests.add(mWorkAppVisibleTest);
+        mTests.add(mCrossProfileIntentFiltersTest);
     }
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
new file mode 100644
index 0000000..6c38e12
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 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 com.android.cts.verifier.managedprovisioning;
+//package com.android.cts.verifier.managedprovisioning;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserManager;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import com.android.cts.verifier.R;
+
+/**
+ * Test activity for cross profile intents.
+ */
+public class CrossProfileTestActivity extends Activity {
+    // Intent for app in both profiles
+    public static final String ACTION_CROSS_PROFILE = "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.provisioning_cross_profile);
+        TextView textView = (TextView) findViewById(R.id.text);
+
+        // Check if we are running in the work or personal side, by testing if currently we are the
+        // profile owner or not.
+        textView.setText(isProfileOwner() ? R.string.provisioning_byod_cross_profile_app_work
+                : R.string.provisioning_byod_cross_profile_app_personal);
+
+        findViewById(R.id.button_finish).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                CrossProfileTestActivity.this.finish();
+            }
+        });
+    }
+
+    private boolean isProfileOwner() {
+        ComponentName adminReceiver = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
+        DevicePolicyManager dpm = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
+        return dpm.isAdminActive(adminReceiver) && dpm.isProfileOwnerApp(adminReceiver.getPackageName());
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index 861bca2..8dccac3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -26,6 +26,8 @@
 import android.util.Log;
 import android.widget.Toast;
 
+import com.android.cts.verifier.managedprovisioning.ByodHelperActivity;
+
 /**
  * Profile owner receiver for BYOD flow test.
  * Setup cross-profile intent filter after successful provisioning.
@@ -48,6 +50,7 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
             filter.addAction(ByodHelperActivity.ACTION_REMOVE_PROFILE_OWNER);
+            filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
             dpm.addCrossProfileIntentFilter(getWho(context), filter,
                     DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
 
diff --git a/hostsidetests/appsecurity/certs/keysets/README b/hostsidetests/appsecurity/certs/keysets/README
new file mode 100644
index 0000000..251dab1
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/README
@@ -0,0 +1,9 @@
+# Generated with:
+development/tools/make_key cts-keyset-test-a         '/CN=unit_test_a'
+development/tools/make_key cts-keyset-test-b         '/CN=unit_test_b'
+development/tools/make_key cts-keyset-test-c         '/CN=unit_test_c'
+
+# Display public key (for use in Manifest) with:
+openssl x509 -in cts-keyset-test-a.x509.pem -inform PEM -pubkey
+openssl x509 -in cts-keyset-test-b.x509.pem -inform PEM -pubkey
+openssl x509 -in cts-keyset-test-c.x509.pem -inform PEM -pubkey
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a.pk8 b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a.pk8
new file mode 100644
index 0000000..b0dd6a3
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a.x509.pem b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a.x509.pem
new file mode 100644
index 0000000..cee8227
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a.x509.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCzCCAfOgAwIBAgIJAJ126KYAFwgTMA0GCSqGSIb3DQEBBQUAMBwxGjAYBgNV
+BAMMEWN0cy1rZXlzZXQtdGVzdC1hMB4XDTE0MDkxMTAwNDQ0OFoXDTQyMDEyNzAw
+NDQ0OFowHDEaMBgGA1UEAwwRY3RzLWtleXNldC10ZXN0LWEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDB/nMluW9hIHtibuiv/saCAAC7uantGvKQ8mxe
+Gh3x2gWFVPmzt4XcDgwITnm+8A0/se/AzDZv5PqrHs+rRUm1ttIO2UEcG0hzjs+O
+rQKwODn3QFRyAqns90n0npRWC3MOdXpwYSleZJqDexj6WqJbTjK0+EJXDNhNYZ1h
+735MiXjtwGu95F8s6Uaty4VB77MJOYMWrMEoJEcr1vuXk8Na9dfKDrlS78wFQD9N
+lY7R8So6XFkb+efoNQpAuE92YlFdYndaow0yEkYP6cq2SZ1fvTfFGqaDiH7qDRLs
+z1jchDY1QbLDTkBjMKC4cH8y/q5UiJbrn3ClvJvjlOAobdSFAgMBAAGjUDBOMB0G
+A1UdDgQWBBTev2AuCLdXO85IFqwy6rIV+wUokjAfBgNVHSMEGDAWgBTev2AuCLdX
+O85IFqwy6rIV+wUokjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCS
+8bjQglLYCNMFHc6AeAvSfu/j9rbZNTmK+0SCCUYbb4s1LoMNQ1hmHhs+nrmrOTe9
+3VgaKPUz2h6+toOM5KhMpkxDUHxe+VKJF4V+TRxMWZbPaz0wgj21FKcV7u5wnWnj
+i08O9dzksIzkD9UrOaxlExG20YFJE9kizoR0i2mZJWhR+1g6SeNc7PeaUnEI344G
+LfSDGt27EqZhmZ1BhJ4lRRUMq3TJFEfdFeVc3z+AgtyrZnxc7jNQ0PFdOXDtzz6B
+iC6AmFsMC/mRettVxjTeOpLo+12UE7FwO+wRa57pNGtljzlKz+DGBAZxi+gLcRDf
+i0TJhPAB4dFqrDgxr+4Y
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b.pk8 b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b.pk8
new file mode 100644
index 0000000..bf6dee1
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b.x509.pem b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b.x509.pem
new file mode 100644
index 0000000..912861f
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b.x509.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCzCCAfOgAwIBAgIJAOZwpbLsHooSMA0GCSqGSIb3DQEBBQUAMBwxGjAYBgNV
+BAMMEWN0cy1rZXlzZXQtdGVzdC1iMB4XDTE0MDkxMTAwNDQ0MVoXDTQyMDEyNzAw
+NDQ0MVowHDEaMBgGA1UEAwwRY3RzLWtleXNldC10ZXN0LWIwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCh4VmoypNtmKjMVNcyRe1IolHOfao4NmC9VcAD
+ApOLnTFhxs9wdN8rG2J/z6rs4Kn/nQlgMffZuDrCRS6efn50RoeTFljx3u7Djq1C
+2Xl00aL7pxzgx7NUsJLqeSo0O6wCB2+AtToWXpIaLTYpOnW+S3oLAs73vtgk/uS3
+2i4NFMbsBImKrc7JFGg6pgeEP2CmxtSrjD7VtcZ+65m6MDV1fKi9e2+sdQY50UgQ
+Fg5VgZ8JzCHeVc+aM0kyUe0pCS6urz8sftrUHmhyhcIazJHxgd2VZ+upEB/OA4HU
+oKc02ZaqyRT0s5yLe5Cf0gN4wQWYB3wWoXxLBX7gu52T/FYZAgMBAAGjUDBOMB0G
+A1UdDgQWBBTM1NnUfcwYiJ3Loy3jfmVwyI+BCTAfBgNVHSMEGDAWgBTM1NnUfcwY
+iJ3Loy3jfmVwyI+BCTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBh
+lRz5yaYpswtWDVPWKnJ5btyXsLIQtWeFkxGxRXSrsFLvCMq7CxjO9VF1l+q+6UmK
+B6BEcrjm7uhmjAXS/ygUGjY1FZNVHwydJ/60Nn/Q0jx242A1+dBtLSS0FnEg+r3P
+3fvocr0SemAt6FY61gJ+4Zr8IQZc8C1qr5e/eDiMPBKectGzH1cniWqq1/5nc/vC
+hTTokZSnXh7PZLzF+iKOceO+nvx4yzm7q/YOM0tAP8PknrWcNAeIPRDvsERwp9fR
+IRTnyd3Ds4H/xD6OioMO+lk45H7vDU3TmoAYbDtCNvgS9Sd1lB/h3XPVH29QqwkW
+4xScMf6rzziGC+RdETpU
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c.pk8 b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c.pk8
new file mode 100644
index 0000000..303f1ad
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c.x509.pem b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c.x509.pem
new file mode 100644
index 0000000..324f218
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c.x509.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCzCCAfOgAwIBAgIJAI8ugk5OF4ENMA0GCSqGSIb3DQEBBQUAMBwxGjAYBgNV
+BAMMEWN0cy1rZXlzZXQtdGVzdC1jMB4XDTE0MDkxMTAwNDQyMloXDTQyMDEyNzAw
+NDQyMlowHDEaMBgGA1UEAwwRY3RzLWtleXNldC10ZXN0LWMwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCvAgn+n3NnqkZ7uHWUElQsTmVthsLeaHkbjc6w
+n4HQJ5s3grMQrJWD7CaS4ZK8bbFdSnUGVuKlKOdMnltS3aIG7AHzUu+6aD0Y58Kl
+MEa18ThriKC1+jt7ZTwhtHMRhuFpmUESYLUENS91MV0xEZk+6FRwyTCK3hGkeQvq
+u22459p6gnCyASNsQvLOByb7Vnj0N6f8maZc0YzDX9AyJsEUa8aSG7aseD9JiIqm
+6lyVTgUh4Atw5Kc+Sutjou5IBMcOdi+68rdWG7QQEogP6sC/mPoE2+e7blIB/caB
+Ls8u7JWWGITmneFN69efmD/u2MmVdrQWxsyWcV/ndbI/2lFbAgMBAAGjUDBOMB0G
+A1UdDgQWBBQbgTfHOXShdjNob5N5in97g4W97TAfBgNVHSMEGDAWgBQbgTfHOXSh
+djNob5N5in97g4W97TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAn
+bOLKe3ixKqLkMsgocHWvkeUqFahYbiPN11JKTFrgQVYwfpUnXN/YQfLSjAWDyzZ3
+niXYSai2COtIqEpQICp4JceEfoZUCbHdATA7Wxvfr+yrv+HG7F8wzhyxa5Pbcu9y
+b3ekjKT1rF4SxK0Ixt9vv34VSO98qAzx2Yq7VQwOKLJG6MDxqXX/tiTxpK7sEfAb
+pgJjHVZkX1rgQtv2e0RLFgcRyiYpxFbFzBLi/1b6EzK2kkg9FNLm+44CYkYFj7WC
+bjlY7o94DQ/CuEDVHCu/DSTp4QjvHC2ewTeXu05XkzSWKKLdsqecnZxXNueuqT5F
+Uhj9Fi4KQqT7tKqd+CuK
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java
new file mode 100644
index 0000000..dae5ee7
--- /dev/null
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2014 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.appsecurity;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.ddmlib.testrunner.TestResult;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.ddmlib.testrunner.TestRunResult;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Map;
+
+/**
+ * Tests for Keyset based features.
+ */
+public class KeySetHostTest extends DeviceTestCase implements IBuildReceiver {
+
+    private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
+
+    /* package with device-side tests */
+    private static final String KEYSET_TEST_PKG = "com.android.cts.keysets.testapp";
+    private static final String KEYSET_TEST_APP_APK = "CtsKeySetTestApp.apk";
+
+    /* plain test apks with different signing and upgrade keysets */
+    private static final String KEYSET_PKG = "com.android.cts.keysets";
+    private static final String A_SIGNED_NO_UPGRADE =
+            "CtsKeySetSigningAUpgradeNone.apk";
+    private static final String A_SIGNED_A_UPGRADE =
+            "CtsKeySetSigningAUpgradeA.apk";
+    private static final String A_SIGNED_B_UPGRADE =
+            "CtsKeySetSigningAUpgradeB.apk";
+    private static final String A_SIGNED_A_OR_B_UPGRADE =
+            "CtsKeySetSigningAUpgradeAOrB.apk";
+    private static final String B_SIGNED_A_UPGRADE =
+            "CtsKeySetSigningBUpgradeA.apk";
+    private static final String B_SIGNED_B_UPGRADE =
+            "CtsKeySetSigningBUpgradeB.apk";
+    private static final String A_AND_B_SIGNED_A_UPGRADE =
+            "CtsKeySetSigningAAndBUpgradeA.apk";
+    private static final String A_AND_B_SIGNED_B_UPGRADE =
+            "CtsKeySetSigningAAndBUpgradeB.apk";
+    private static final String A_AND_C_SIGNED_B_UPGRADE =
+            "CtsKeySetSigningAAndCUpgradeB.apk";
+
+    /* package which defines the KEYSET_PERM_NAME signature permission */
+    private static final String KEYSET_PERM_DEF_PKG =
+            "com.android.cts.keysets_permdef";
+
+    /* The apks defining and using the permission have both A and B as upgrade keys */
+    private static final String PERM_DEF_A_SIGNED =
+            "CtsKeySetPermDefSigningA.apk";
+    private static final String PERM_DEF_B_SIGNED =
+            "CtsKeySetPermDefSigningB.apk";
+    private static final String PERM_USE_A_SIGNED =
+            "CtsKeySetPermUseSigningA.apk";
+    private static final String PERM_USE_B_SIGNED =
+            "CtsKeySetPermUseSigningB.apk";
+
+    private static final String PERM_TEST_CLASS =
+        "com.android.cts.keysets.KeySetPermissionsTest";
+
+    private static final String LOG_TAG = "AppsecurityHostTests";
+
+    private File getTestAppFile(String fileName) throws FileNotFoundException {
+        return mCtsBuild.getTestApp(fileName);
+    }
+
+    /**
+     * Helper method that checks that all tests in given result passed, and attempts to generate
+     * a meaningful error message if they failed.
+     *
+     * @param result
+     */
+    private void assertDeviceTestsPass(TestRunResult result) {
+        assertFalse(String.format("Failed to successfully run device tests for %s. Reason: %s",
+                result.getName(), result.getRunFailureMessage()), result.isRunFailure());
+
+        if (result.hasFailedTests()) {
+
+            /* build a meaningful error message */
+            StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
+            for (Map.Entry<TestIdentifier, TestResult> resultEntry :
+                result.getTestResults().entrySet()) {
+                if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
+                    errorBuilder.append(resultEntry.getKey().toString());
+                    errorBuilder.append(":\n");
+                    errorBuilder.append(resultEntry.getValue().getStackTrace());
+                }
+            }
+            fail(errorBuilder.toString());
+        }
+    }
+
+    /**
+     * Helper method that checks that all tests in given result passed, and attempts to generate
+     * a meaningful error message if they failed.
+     *
+     * @param result
+     */
+    private void assertDeviceTestsFail(String msg, TestRunResult result) {
+        assertFalse(String.format("Failed to successfully run device tests for %s. Reason: %s",
+                result.getName(), result.getRunFailureMessage()), result.isRunFailure());
+
+        if (!result.hasFailedTests()) {
+            fail(msg);
+        }
+    }
+
+    /**
+     * Helper method that will run the specified packages tests on device.
+     *
+     * @param pkgName Android application package for tests
+     * @return <code>true</code> if all tests passed.
+     * @throws DeviceNotAvailableException if connection to device was lost.
+     */
+    private boolean runDeviceTests(String pkgName) throws DeviceNotAvailableException {
+        return runDeviceTests(pkgName, null, null);
+    }
+
+    /**
+     * Helper method that will run the specified packages tests on device.
+     *
+     * @param pkgName Android application package for tests
+     * @return <code>true</code> if all tests passed.
+     * @throws DeviceNotAvailableException if connection to device was lost.
+     */
+    private boolean runDeviceTests(String pkgName, String testClassName, String testMethodName)
+            throws DeviceNotAvailableException {
+        TestRunResult runResult = doRunTests(pkgName, testClassName, testMethodName);
+        return !runResult.hasFailedTests();
+    }
+
+    /**
+     * Helper method to run tests and return the listener that collected the results.
+     *
+     * @param pkgName Android application package for tests
+     * @return the {@link TestRunResult}
+     * @throws DeviceNotAvailableException if connection to device was lost.
+     */
+    private TestRunResult doRunTests(String pkgName, String testClassName,
+            String testMethodName) throws DeviceNotAvailableException {
+
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(pkgName,
+                RUNNER, getDevice().getIDevice());
+        if (testClassName != null && testMethodName != null) {
+            testRunner.setMethodName(testClassName, testMethodName);
+        }
+        CollectingTestListener listener = new CollectingTestListener();
+        getDevice().runInstrumentationTests(testRunner, listener);
+        return listener.getCurrentRunResults();
+    }
+
+    /**
+     * Helper method which installs a package and an upgrade to it.
+     *
+     * @param pkgName - package name of apk.
+     * @param firstApk - first apk to install
+     * @param secondApk - apk to which we attempt to upgrade
+     * @param expectedResult - null if successful, otherwise expected error.
+     */
+    private String testPackageUpgrade(String pkgName, String firstApk,
+             String secondApk) throws Exception {
+        String installResult;
+        try {
+
+            /* cleanup test apps that might be installed from previous partial test run */
+            mDevice.uninstallPackage(pkgName);
+
+            installResult = mDevice.installPackage(getTestAppFile(firstApk),
+                    false);
+            /* we should always succeed on first-install */
+            assertNull(String.format("failed to install %s, Reason: %s", pkgName,
+                       installResult), installResult);
+
+            /* attempt to install upgrade */
+            installResult = mDevice.installPackage(getTestAppFile(secondApk),
+                    true);
+        } finally {
+            mDevice.uninstallPackage(pkgName);
+        }
+        return installResult;
+    }
+    /**
+     * A reference to the device under test.
+     */
+    private ITestDevice mDevice;
+
+    private CtsBuildHelper mCtsBuild;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+    }
+
+    @Override
+        protected void setUp() throws Exception {
+        super.setUp();
+        mDevice = getDevice();
+        assertNotNull(mCtsBuild);
+    }
+
+    /**
+     * Tests for KeySet based key rotation
+     */
+
+    /*
+     * Check if an apk which does not specify an upgrade-key-set may be upgraded
+     * to an apk which does.
+     */
+    public void testNoKSToUpgradeKS() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_NO_UPGRADE, A_SIGNED_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from no specified upgrade-key-set"
+                + "to version with specified upgrade-key-set, Reason: %s", installResult),
+                installResult);
+    }
+
+    /*
+     * Check if an apk which does specify an upgrade-key-set may be upgraded
+     * to an apk which does not.
+     */
+    public void testUpgradeKSToNoKS() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE, A_SIGNED_NO_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from specified upgrade-key-set"
+                + "to version without specified upgrade-key-set, Reason: %s", installResult),
+                installResult);
+    }
+
+    /*
+     * Check if an apk signed by a key other than the upgrade keyset can update
+     * an app
+     */
+    public void testUpgradeKSWithWrongKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE, B_SIGNED_A_UPGRADE);
+        assertNotNull("upgrade to improperly signed app succeeded!", installResult);
+    }
+
+    /*
+     * Check if an apk signed by its signing key, which is not an upgrade key,
+     * can upgrade an app.
+     */
+    public void testUpgradeKSWithWrongSigningKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_B_UPGRADE, A_SIGNED_B_UPGRADE);
+         assertNotNull("upgrade to improperly signed app succeeded!",
+                 installResult);
+    }
+
+    /*
+     * Check if an apk signed by its upgrade key, which is not its signing key,
+     * can upgrade an app.
+     */
+    public void testUpgradeKSWithUpgradeKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_B_UPGRADE, B_SIGNED_B_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                 + "to version signed by upgrade-key-set key-b, Reason: %s", installResult),
+                 installResult);
+    }
+
+    /*
+     * Check if an apk signed by its upgrade key, which is its signing key, can
+     * upgrade an app.
+     */
+    public void testUpgradeKSWithSigningUpgradeKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE, A_SIGNED_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                    + "to version signed by upgrade-key-set key-b, Reason: %s", installResult),
+                    installResult);
+    }
+
+    /*
+     * Check if an apk signed by multiple keys, one of which is its upgrade key,
+     * can upgrade an app.
+     */
+    public void testMultipleUpgradeKSWithUpgradeKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_UPGRADE,
+                A_AND_B_SIGNED_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                + "to version signed by upgrade-key-set key-b, Reason: %s", installResult),
+                installResult);
+    }
+
+    /*
+     * Check if an apk signed by multiple keys, its signing keys,
+     * but none of which is an upgrade key, can upgrade an app.
+     */
+    public void testMultipleUpgradeKSWithSigningKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_AND_C_SIGNED_B_UPGRADE,
+                A_AND_C_SIGNED_B_UPGRADE);
+        assertNotNull("upgrade to improperly signed app succeeded!", installResult);
+    }
+
+    /*
+     * Check if an apk which defines multiple (two) upgrade keysets is
+     * upgrade-able by either.
+     */
+    public void testUpgradeKSWithMultipleUpgradeKeySetsFirstKey() throws Exception {
+        String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_OR_B_UPGRADE,
+                A_SIGNED_A_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                + "to one signed by first upgrade keyset key-a, Reason: %s", installResult),
+                installResult);
+        installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_A_OR_B_UPGRADE,
+                B_SIGNED_B_UPGRADE);
+        assertNull(String.format("failed to upgrade keyset app from one signed by key-a"
+                + "to one signed by second upgrade keyset key-b, Reason: %s", installResult),
+                installResult);
+    }
+
+    /**
+     * Helper method which installs a package defining a permission and a package
+     * using the permission, and then rotates the signing keys for one of them.
+     * A device-side test is then used to ascertain whether or not the permission
+     * was appropriately gained or lost.
+     *
+     * @param permDefApk - apk to install which defines the sig-permissoin
+     * @param permUseApk - apk to install which declares it uses the permission
+     * @param upgradeApk - apk to install which upgrades one of the first two
+     * @param hasPermBeforeUpgrade - whether we expect the consuming app to have
+     *        the permission before the upgrade takes place.
+     * @param hasPermAfterUpgrade - whether we expect the consuming app to have
+     *        the permission after the upgrade takes place.
+     */
+    private void testKeyRotationPerm(String permDefApk, String permUseApk,
+            String upgradeApk, boolean hasPermBeforeUpgrade,
+            boolean hasPermAfterUpgrade) throws Exception {
+        try {
+
+            /* cleanup test apps that might be installed from previous partial test run */
+            mDevice.uninstallPackage(KEYSET_PKG);
+            mDevice.uninstallPackage(KEYSET_PERM_DEF_PKG);
+            mDevice.uninstallPackage(KEYSET_TEST_PKG);
+
+            /* install PERM_DEF, KEYSET_APP and KEYSET_TEST_APP */
+            String installResult = mDevice.installPackage(
+                    getTestAppFile(permDefApk), false);
+            assertNull(String.format("failed to install keyset perm-def app, Reason: %s",
+                       installResult), installResult);
+            installResult = getDevice().installPackage(
+                    getTestAppFile(permUseApk), false);
+            assertNull(String.format("failed to install keyset test app. Reason: %s",
+                    installResult), installResult);
+            installResult = getDevice().installPackage(
+                    getTestAppFile(KEYSET_TEST_APP_APK), false);
+            assertNull(String.format("failed to install keyset test app. Reason: %s",
+                    installResult), installResult);
+
+            /* verify package does have perm */
+            TestRunResult result = doRunTests(KEYSET_TEST_PKG, PERM_TEST_CLASS,
+                    "testHasPerm");
+            if (hasPermBeforeUpgrade) {
+                assertDeviceTestsPass(result);
+            } else {
+                assertDeviceTestsFail(" has permission permission it should not have.", result);
+            }
+
+            /* rotate keys */
+            installResult = mDevice.installPackage(getTestAppFile(upgradeApk),
+                    true);
+            result = doRunTests(KEYSET_TEST_PKG, PERM_TEST_CLASS,
+                    "testHasPerm");
+            if (hasPermAfterUpgrade) {
+                assertDeviceTestsPass(result);
+            } else {
+                assertDeviceTestsFail(KEYSET_PKG + " has permission it should not have.", result);
+            }
+        } finally {
+            mDevice.uninstallPackage(KEYSET_PKG);
+            mDevice.uninstallPackage(KEYSET_PERM_DEF_PKG);
+            mDevice.uninstallPackage(KEYSET_TEST_PKG);
+        }
+    }
+
+    /*
+     * Check if an apk gains signature-level permission after changing to a new
+     * signature, for which a permission should be granted.
+     */
+    public void testUpgradeSigPermGained() throws Exception {
+        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_B_SIGNED, PERM_USE_A_SIGNED,
+                false, true);
+    }
+
+    /*
+     * Check if an apk loses signature-level permission after changing to a new
+     * signature, from one for which a permission was previously granted.
+     */
+    public void testUpgradeSigPermLost() throws Exception {
+        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_A_SIGNED, PERM_USE_B_SIGNED,
+                true, false);
+    }
+
+    /*
+     * Check if an apk gains signature-level permission after the app defining
+     * it rotates to the same signature.
+     */
+    public void testUpgradeDefinerSigPermGained() throws Exception {
+        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_B_SIGNED, PERM_DEF_B_SIGNED,
+                false, true);
+    }
+
+    /*
+     * Check if an apk loses signature-level permission after the app defining
+     * it rotates to a different signature.
+     */
+    public void testUpgradeDefinerSigPermLost() throws Exception {
+        testKeyRotationPerm(PERM_DEF_A_SIGNED, PERM_USE_A_SIGNED, PERM_DEF_B_SIGNED,
+                true, false);
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java
index c6aa56b..264c0b1 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java
@@ -60,6 +60,9 @@
     private static final String APK_DIFF_VERSION_v7 = "CtsSplitAppDiffVersion_v7.apk";
     private static final String APK_DIFF_CERT_v7 = "CtsSplitAppDiffCert_v7.apk";
 
+    private static final String APK_FEATURE = "CtsSplitAppFeature.apk";
+    private static final String APK_FEATURE_v7 = "CtsSplitAppFeature_v7.apk";
+
     private static final HashMap<String, String> ABI_TO_APK = new HashMap<>();
 
     static {
@@ -231,8 +234,14 @@
         new InstallMultiple().inheritFrom(PKG).addApk(APK_DIFF_VERSION_v7).runExpectingFailure();
     }
 
-    public void testInheritNewSplit() throws Exception {
-        // TODO: flesh out this test
+    public void testFeatureBase() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_FEATURE).run();
+        runDeviceTests(PKG, ".SplitAppTest", "testFeatureBase");
+    }
+
+    public void testFeatureApi() throws Exception {
+        new InstallMultiple().addApk(APK).addApk(APK_FEATURE).addApk(APK_FEATURE_v7).run();
+        runDeviceTests(PKG, ".SplitAppTest", "testFeatureApi");
     }
 
     public void testInheritUpdatedBase() throws Exception {
@@ -243,10 +252,6 @@
         // TODO: flesh out this test
     }
 
-    public void testSplitOrdering() throws Exception {
-        // TODO: flesh out this test
-    }
-
     class InstallMultiple {
         private List<String> mArgs = new ArrayList<>();
         private List<File> mApks = new ArrayList<>();
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
index fc24aee..bc3acaf 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsSplitApp
 LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 v7 fr de
@@ -47,7 +47,7 @@
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsSplitAppDiffVersion
 LOCAL_PACKAGE_SPLITS := v7
@@ -70,7 +70,7 @@
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsSplitAppDiffCert
 LOCAL_PACKAGE_SPLITS := v7
@@ -85,5 +85,5 @@
 
 
 ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call all-makefiles-under,$(LOCAL_PATH)/libs)
+include $(LOCAL_PATH)/libs/Android.mk $(LOCAL_PATH)/feature/Android.mk
 endif
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
new file mode 100644
index 0000000..9965f60
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2014 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-subdir-java-files)
+LOCAL_PACKAGE_NAME := CtsSplitAppFeature
+LOCAL_PACKAGE_SPLITS := v7
+
+LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
+
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
+LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version -c mdpi
+
+LOCAL_MODULE_TAGS := tests
+
+featureOf := CtsSplitApp
+featureOfApk := $(call intermediates-dir-for,APPS,$(featureOf))/package.apk
+localRStamp := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src/R.stamp
+$(localRStamp): $(featureOfApk)
+
+LOCAL_AAPT_FLAGS += --feature-of $(featureOfApk)
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature/AndroidManifest.xml
new file mode 100644
index 0000000..8ba3c2f
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/AndroidManifest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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="com.android.cts.splitapp"
+        featureName="feature">
+
+    <!-- New permission should be ignored -->
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <!-- New application flag should be ignored -->
+    <application android:largeHeap="true">
+        <activity android:name=".FeatureActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <meta-data android:name="android.service.wallpaper" android:resource="@xml/my_activity_meta" />
+        </activity>
+        <receiver android:name=".FeatureReceiver"
+                android:enabled="@bool/feature_receiver_enabled">
+            <intent-filter>
+                <action android:name="android.intent.action.DATE_CHANGED" />
+            </intent-filter>
+        </receiver>
+        <service android:name=".FeatureService">
+            <intent-filter>
+                <action android:name="com.android.cts.splitapp.service" />
+            </intent-filter>
+        </service>
+        <provider android:name=".FeatureProvider" android:authorities="com.android.cts.splitapp.provider" />
+    </application>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/dir/dirfile2.txt b/hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/dir/dirfile2.txt
new file mode 100644
index 0000000..c4a2fff
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/dir/dirfile2.txt
@@ -0,0 +1 @@
+DIRFILE2
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/file2.txt b/hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/file2.txt
new file mode 100644
index 0000000..d77231c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/file2.txt
@@ -0,0 +1 @@
+FILE2
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values-v7/values.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values-v7/values.xml
new file mode 100644
index 0000000..8d91234
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values-v7/values.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources>
+    <bool name="feature_receiver_enabled">false</bool>
+    <integer name="feature_integer">321</integer>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values/values.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values/values.xml
new file mode 100644
index 0000000..7d670cf
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values/values.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<resources>
+    <bool name="feature_receiver_enabled">true</bool>
+    <string name="feature_string">red</string>
+    <integer name="feature_integer">123</integer>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureActivity.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureActivity.java
new file mode 100644
index 0000000..a4df004
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 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 com.android.cts.splitapp;
+
+import android.app.Activity;
+
+public class FeatureActivity extends Activity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureLogic.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureLogic.java
new file mode 100644
index 0000000..0481546
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureLogic.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 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 com.android.cts.splitapp;
+
+import android.util.Log;
+
+public class FeatureLogic {
+    private static final String TAG = "FeatureLogic";
+
+    public static int mult(int a, int b) {
+        Log.d(TAG, "FeatureLogic.mult(" + a + ", " + b + ")");
+        return a * b;
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureProvider.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureProvider.java
new file mode 100644
index 0000000..087aeb7
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureProvider.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 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 com.android.cts.splitapp;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+
+public class FeatureProvider extends ContentProvider {
+    private static final String TAG = "FeatureProvider";
+
+    public static boolean sCreated = false;
+
+    @Override
+    public boolean onCreate() {
+        Log.d(TAG, "FeatureProvider.onCreate()");
+
+        sCreated = true;
+
+        try {
+            // Just reach out and touch
+            final Class<?> test = Class.forName("com.android.cts.splitapp.SplitAppTest");
+            final Field touched = test.getDeclaredField("sFeatureTouched");
+            touched.set(null, true);
+
+            // Also make sure we can read a resource from the base; we just
+            // stash the value we saw over on the test for them to verify.
+            final Class<?> baseR = Class.forName("com.android.cts.splitapp.BaseR");
+            final int stringId = (int) baseR.getDeclaredField("my_string1").get(null);
+            final Field value = test.getDeclaredField("sFeatureValue");
+            value.set(null, getContext().getResources().getString(stringId));
+
+        } catch (Throwable t) {
+            // We're okay if anything above fails, since the test later verifies
+            // that we actually touched the boolean.
+            Log.e(TAG, "Failed to communicate back to base", t);
+        }
+
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureR.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureR.java
new file mode 100644
index 0000000..3dbd83b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureR.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 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 com.android.cts.splitapp;
+
+public class FeatureR {
+    public static final int feature_receiver_enabled = R.bool.feature_receiver_enabled;
+    public static final int feature_integer = R.integer.feature_integer;
+    public static final int feature_string = R.string.feature_string;
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureReceiver.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureReceiver.java
new file mode 100644
index 0000000..49559f3
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureReceiver.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 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 com.android.cts.splitapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class FeatureReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // Ignored
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureService.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureService.java
new file mode 100644
index 0000000..b07297f
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureService.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 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 com.android.cts.splitapp;
+
+import android.app.IntentService;
+import android.content.Intent;
+
+public class FeatureService extends IntentService {
+    public FeatureService() {
+        super("Feature1Service");
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        // Ignored
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BaseR.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BaseR.java
new file mode 100644
index 0000000..ecf6975
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BaseR.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 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 com.android.cts.splitapp;
+
+public class BaseR {
+    public static final int my_string1 = R.string.my_string1;
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
index 9eb17cd..277a1a2 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
@@ -20,7 +20,9 @@
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -37,11 +39,17 @@
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.List;
 import java.util.Locale;
 
 public class SplitAppTest extends AndroidTestCase {
     private static final String TAG = "SplitAppTest";
+    private static final String PKG = "com.android.cts.splitapp";
+
+    public static boolean sFeatureTouched = false;
+    public static String sFeatureValue = null;
 
     public void testSingleBase() throws Exception {
         final Resources r = getContext().getResources();
@@ -78,7 +86,7 @@
         // Should only have base manifest items
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(Intent.CATEGORY_LAUNCHER);
-        intent.setPackage("com.android.cts.splitapp");
+        intent.setPackage(PKG);
 
         List<ResolveInfo> result = pm.queryIntentActivities(intent, 0);
         assertEquals(1, result.size());
@@ -86,7 +94,7 @@
 
         // Receiver disabled by default in base
         intent = new Intent(Intent.ACTION_DATE_CHANGED);
-        intent.setPackage("com.android.cts.splitapp");
+        intent.setPackage(PKG);
 
         result = pm.queryBroadcastReceivers(intent, 0);
         assertEquals(0, result.size());
@@ -157,7 +165,7 @@
 
         // Receiver should be enabled now
         Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
-        intent.setPackage("com.android.cts.splitapp");
+        intent.setPackage(PKG);
 
         List<ResolveInfo> result = pm.queryBroadcastReceivers(intent, 0);
         assertEquals(1, result.size());
@@ -187,6 +195,121 @@
         assertEquals(11642, Native.add(4933, 6709));
     }
 
+    public void testFeatureBase() throws Exception {
+        final Resources r = getContext().getResources();
+        final PackageManager pm = getContext().getPackageManager();
+
+        // Should have untouched resources from base
+        assertEquals(false, r.getBoolean(R.bool.my_receiver_enabled));
+
+        assertEquals("blue", r.getString(R.string.my_string1));
+        assertEquals("purple", r.getString(R.string.my_string2));
+
+        assertEquals(0xff00ff00, r.getColor(R.color.my_color));
+        assertEquals(123, r.getInteger(R.integer.my_integer));
+
+        assertEquals("base", getXmlTestValue(r.getXml(R.xml.my_activity_meta)));
+
+        // And that we can access resources from feature
+        // TODO: enable these once 17924027 is fixed
+//        assertEquals("red", r.getString(r.getIdentifier("feature_string", "string", PKG)));
+//        assertEquals(123, r.getInteger(r.getIdentifier("feature_integer", "integer", PKG)));
+
+        final Class<?> featR = Class.forName("com.android.cts.splitapp.FeatureR");
+        final int boolId = (int) featR.getDeclaredField("feature_receiver_enabled").get(null);
+        final int intId = (int) featR.getDeclaredField("feature_integer").get(null);
+        final int stringId = (int) featR.getDeclaredField("feature_string").get(null);
+        assertEquals(true, r.getBoolean(boolId));
+        assertEquals(123, r.getInteger(intId));
+        assertEquals("red", r.getString(stringId));
+
+        // Should have both base and feature assets
+        assertAssetContents(r, "file1.txt", "FILE1");
+        assertAssetContents(r, "file2.txt", "FILE2");
+        assertAssetContents(r, "dir/dirfile1.txt", "DIRFILE1");
+        assertAssetContents(r, "dir/dirfile2.txt", "DIRFILE2");
+
+        // Should have both base and feature components
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        intent.setPackage(PKG);
+        List<ResolveInfo> result = pm.queryIntentActivities(intent, 0);
+        assertEquals(2, result.size());
+        assertEquals("com.android.cts.splitapp.MyActivity", result.get(0).activityInfo.name);
+        assertEquals("com.android.cts.splitapp.FeatureActivity", result.get(1).activityInfo.name);
+
+        // Receiver only enabled in feature
+        intent = new Intent(Intent.ACTION_DATE_CHANGED);
+        intent.setPackage(PKG);
+        result = pm.queryBroadcastReceivers(intent, 0);
+        assertEquals(1, result.size());
+        assertEquals("com.android.cts.splitapp.FeatureReceiver", result.get(0).activityInfo.name);
+
+        // And we should have a service
+        intent = new Intent("com.android.cts.splitapp.service");
+        intent.setPackage(PKG);
+        result = pm.queryIntentServices(intent, 0);
+        assertEquals(1, result.size());
+        assertEquals("com.android.cts.splitapp.FeatureService", result.get(0).serviceInfo.name);
+
+        // And a provider too
+        ProviderInfo info = pm.resolveContentProvider("com.android.cts.splitapp.provider", 0);
+        assertEquals("com.android.cts.splitapp.FeatureProvider", info.name);
+
+        // And assert that we spun up the provider in this process
+        final Class<?> provider = Class.forName("com.android.cts.splitapp.FeatureProvider");
+        final Field field = provider.getDeclaredField("sCreated");
+        assertTrue("Expected provider to have been created", (boolean) field.get(null));
+        assertTrue("Expected provider to have touched us", sFeatureTouched);
+        assertEquals(r.getString(R.string.my_string1), sFeatureValue);
+
+        // Finally ensure that we can execute some code from split
+        final Class<?> logic = Class.forName("com.android.cts.splitapp.FeatureLogic");
+        final Method method = logic.getDeclaredMethod("mult", new Class[] {
+                Integer.TYPE, Integer.TYPE });
+        assertEquals(72, (int) method.invoke(null, 12, 6));
+
+        // Make sure we didn't get an extra flag from feature split
+        assertTrue("Someone parsed application flag!",
+                (getContext().getApplicationInfo().flags & ApplicationInfo.FLAG_LARGE_HEAP) == 0);
+
+        // Make sure we have permission from base APK
+        getContext().enforceCallingOrSelfPermission(android.Manifest.permission.CAMERA, null);
+
+        try {
+            // But no new permissions from the feature APK
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, null);
+            fail("Whaaa, we somehow gained permission from feature?");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testFeatureApi() throws Exception {
+        final Resources r = getContext().getResources();
+        final PackageManager pm = getContext().getPackageManager();
+
+        // Should have untouched resources from base
+        assertEquals(false, r.getBoolean(R.bool.my_receiver_enabled));
+
+        // And that we can access resources from feature
+        // TODO: enable these once 17924027 is fixed
+//        assertEquals(321, r.getInteger(r.getIdentifier("feature_integer", "integer", PKG)));
+
+        final Class<?> featR = Class.forName("com.android.cts.splitapp.FeatureR");
+        final int boolId = (int) featR.getDeclaredField("feature_receiver_enabled").get(null);
+        final int intId = (int) featR.getDeclaredField("feature_integer").get(null);
+        final int stringId = (int) featR.getDeclaredField("feature_string").get(null);
+        assertEquals(false, r.getBoolean(boolId));
+        assertEquals(321, r.getInteger(intId));
+        assertEquals("red", r.getString(stringId));
+
+        // And now both receivers should be disabled
+        Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
+        intent.setPackage(PKG);
+        List<ResolveInfo> result = pm.queryBroadcastReceivers(intent, 0);
+        assertEquals(0, result.size());
+    }
+
     private static void updateDpi(Resources r, int densityDpi) {
         final Configuration c = new Configuration(r.getConfiguration());
         c.densityDpi = densityDpi;
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
new file mode 100644
index 0000000..eb71540
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 2014 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)
+
+#apks signed cts-keyset-test-a
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetPermDefSigningA
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+#apks signed cts-keyset-test-b
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetPermDefSigningB
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permDef/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/keysets/permDef/AndroidManifest.xml
new file mode 100644
index 0000000..7b84f6a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/permDef/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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="com.android.cts.keysets_permdef">
+    <application android:hasCode="false">
+    </application>
+    <permission android:description="@string/keysets_perm_desc"
+                android:label="@string/keysets_perm_label"
+                android:name="com.android.cts.keysets_permdef.keysets_perm"
+                android:protectionLevel="signature" />
+    <key-sets>
+        <key-set android:name="A" >
+          <public-key android:name="keyA"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwf5zJblvYSB7Ym7or/7GggAAu7mp7RrykPJsXhod8doFhVT5s7eF3A4MCE55vvANP7HvwMw2b+T6qx7Pq0VJtbbSDtlBHBtIc47Pjq0CsDg590BUcgKp7PdJ9J6UVgtzDnV6cGEpXmSag3sY+lqiW04ytPhCVwzYTWGdYe9+TIl47cBrveRfLOlGrcuFQe+zCTmDFqzBKCRHK9b7l5PDWvXXyg65Uu/MBUA/TZWO0fEqOlxZG/nn6DUKQLhPdmJRXWJ3WqMNMhJGD+nKtkmdX703xRqmg4h+6g0S7M9Y3IQ2NUGyw05AYzCguHB/Mv6uVIiW659wpbyb45TgKG3UhQIDAQAB" />
+        </key-set>
+        <key-set android:name="B" >
+          <public-key android:name="keyB"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoeFZqMqTbZiozFTXMkXtSKJRzn2qODZgvVXAAwKTi50xYcbPcHTfKxtif8+q7OCp/50JYDH32bg6wkUunn5+dEaHkxZY8d7uw46tQtl5dNGi+6cc4MezVLCS6nkqNDusAgdvgLU6Fl6SGi02KTp1vkt6CwLO977YJP7kt9ouDRTG7ASJiq3OyRRoOqYHhD9gpsbUq4w+1bXGfuuZujA1dXyovXtvrHUGOdFIEBYOVYGfCcwh3lXPmjNJMlHtKQkurq8/LH7a1B5ocoXCGsyR8YHdlWfrqRAfzgOB1KCnNNmWqskU9LOci3uQn9IDeMEFmAd8FqF8SwV+4Ludk/xWGQIDAQAB" />
+        </key-set>
+        <upgrade-key-set android:name="A"/>
+        <upgrade-key-set android:name="B"/>
+    </key-sets>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permDef/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/keysets/permDef/res/values/strings.xml
new file mode 100644
index 0000000..4e5e870
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/permDef/res/values/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Just need this dummy file to have something to build. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string name="keysets_perm_desc">keysets_perm_description</string>
+  <string name="keysets_perm_label">keysets_perm_label</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
new file mode 100644
index 0000000..000b12a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 2014 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)
+
+#apks signed cts-keyset-test-a
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetPermUseSigningA
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+#apks signed cts-keyset-test-b
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetPermUseSigningB
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permUse/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/keysets/permUse/AndroidManifest.xml
new file mode 100644
index 0000000..40ca1cb
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/permUse/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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="com.android.cts.keysets">
+    <application android:hasCode="false">
+    </application>
+    <uses-permission android:name="com.android.cts.keysets_permdef.keysets_perm" />
+    <key-sets>
+        <key-set android:name="A">
+          <public-key android:name="keyA"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwf5zJblvYSB7Ym7or/7GggAAu7mp7RrykPJsXhod8doFhVT5s7eF3A4MCE55vvANP7HvwMw2b+T6qx7Pq0VJtbbSDtlBHBtIc47Pjq0CsDg590BUcgKp7PdJ9J6UVgtzDnV6cGEpXmSag3sY+lqiW04ytPhCVwzYTWGdYe9+TIl47cBrveRfLOlGrcuFQe+zCTmDFqzBKCRHK9b7l5PDWvXXyg65Uu/MBUA/TZWO0fEqOlxZG/nn6DUKQLhPdmJRXWJ3WqMNMhJGD+nKtkmdX703xRqmg4h+6g0S7M9Y3IQ2NUGyw05AYzCguHB/Mv6uVIiW659wpbyb45TgKG3UhQIDAQAB" />
+        </key-set>
+        <key-set android:name="B">
+          <public-key android:name="keyB"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoeFZqMqTbZiozFTXMkXtSKJRzn2qODZgvVXAAwKTi50xYcbPcHTfKxtif8+q7OCp/50JYDH32bg6wkUunn5+dEaHkxZY8d7uw46tQtl5dNGi+6cc4MezVLCS6nkqNDusAgdvgLU6Fl6SGi02KTp1vkt6CwLO977YJP7kt9ouDRTG7ASJiq3OyRRoOqYHhD9gpsbUq4w+1bXGfuuZujA1dXyovXtvrHUGOdFIEBYOVYGfCcwh3lXPmjNJMlHtKQkurq8/LH7a1B5ocoXCGsyR8YHdlWfrqRAfzgOB1KCnNNmWqskU9LOci3uQn9IDeMEFmAd8FqF8SwV+4Ludk/xWGQIDAQAB" />
+        </key-set>
+        <upgrade-key-set android:name="A"/>
+        <upgrade-key-set android:name="B"/>
+    </key-sets>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permUse/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/keysets/permUse/res/values/strings.xml
new file mode 100644
index 0000000..4e5e870
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/permUse/res/values/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Just need this dummy file to have something to build. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string name="keysets_perm_desc">keysets_perm_description</string>
+  <string name="keysets_perm_label">keysets_perm_label</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
new file mode 100644
index 0000000..ed6db69
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2014 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_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetTestApp
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/testApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/keysets/testApp/AndroidManifest.xml
new file mode 100644
index 0000000..38edf5f
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/testApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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="com.android.cts.keysets.testapp">
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:targetPackage="com.android.cts.keysets.testapp"
+        android:name="android.support.test.runner.AndroidJUnitRunner" />
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/keysets/testApp/src/com/android/cts/keysets/KeySetPermissionsTest.java b/hostsidetests/appsecurity/test-apps/keysets/testApp/src/com/android/cts/keysets/KeySetPermissionsTest.java
new file mode 100644
index 0000000..467a212
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/testApp/src/com/android/cts/keysets/KeySetPermissionsTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 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 com.android.cts.keysets;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+import android.test.AndroidTestCase;
+
+import java.lang.Override;
+
+/**
+ * KeySets device-side tests involving permissions
+ */
+public class KeySetPermissionsTest extends AndroidTestCase {
+
+    private static final String KEYSET_APP_PKG = "com.android.cts.keysets";
+    private static final String KEYSET_PERM_DEF_PKG = "com.android.cts.keysets_permdef";
+    private static final String KEYSET_PERM_NAME = "com.android.cts.keysets_permdef.keysets_perm";
+
+    public void testHasPerm() throws Exception {
+        PackageManager pm = getContext().getPackageManager();
+        assertTrue(KEYSET_PERM_NAME + " not granted to " + KEYSET_APP_PKG,
+                pm.checkPermission(KEYSET_PERM_NAME, KEYSET_APP_PKG) == PackageManager.PERMISSION_GRANTED);
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
new file mode 100644
index 0000000..6220790
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
@@ -0,0 +1,53 @@
+# Copyright (C) 2014 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)
+
+#apks signed by cts-keyset-test-a
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningAUpgradeA
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+#apks signed by cts-keyset-test-b
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningBUpgradeA
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+#apks signed by cts-keyset-test-a and cts-keyset-test-b
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningAAndBUpgradeA
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_ADDITIONAL_CERTIFICATES := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
+LOCAL_DEX_PREOPT := false
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uA/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/keysets/uA/AndroidManifest.xml
new file mode 100644
index 0000000..8813c37
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uA/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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="com.android.cts.keysets">
+    <application android:hasCode="false">
+    </application>
+    <key-sets>
+        <key-set android:name="A" >
+          <public-key android:name="keyA"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwf5zJblvYSB7Ym7or/7GggAAu7mp7RrykPJsXhod8doFhVT5s7eF3A4MCE55vvANP7HvwMw2b+T6qx7Pq0VJtbbSDtlBHBtIc47Pjq0CsDg590BUcgKp7PdJ9J6UVgtzDnV6cGEpXmSag3sY+lqiW04ytPhCVwzYTWGdYe9+TIl47cBrveRfLOlGrcuFQe+zCTmDFqzBKCRHK9b7l5PDWvXXyg65Uu/MBUA/TZWO0fEqOlxZG/nn6DUKQLhPdmJRXWJ3WqMNMhJGD+nKtkmdX703xRqmg4h+6g0S7M9Y3IQ2NUGyw05AYzCguHB/Mv6uVIiW659wpbyb45TgKG3UhQIDAQAB" />
+        </key-set>
+        <upgrade-key-set android:name="A"/>
+    </key-sets>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
new file mode 100644
index 0000000..534dba3
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2014 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)
+
+#apks signed cts-keyset-test-a
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningAUpgradeAAndB
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAB/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/keysets/uAB/AndroidManifest.xml
new file mode 100644
index 0000000..65f78e3
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAB/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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="com.android.cts.keysets">
+    <application android:hasCode="false">
+    </application>
+    <key-sets>
+        <key-set android:name="AB" >
+          <public-key android:name="keyA"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwf5zJblvYSB7Ym7or/7GggAAu7mp7RrykPJsXhod8doFhVT5s7eF3A4MCE55vvANP7HvwMw2b+T6qx7Pq0VJtbbSDtlBHBtIc47Pjq0CsDg590BUcgKp7PdJ9J6UVgtzDnV6cGEpXmSag3sY+lqiW04ytPhCVwzYTWGdYe9+TIl47cBrveRfLOlGrcuFQe+zCTmDFqzBKCRHK9b7l5PDWvXXyg65Uu/MBUA/TZWO0fEqOlxZG/nn6DUKQLhPdmJRXWJ3WqMNMhJGD+nKtkmdX703xRqmg4h+6g0S7M9Y3IQ2NUGyw05AYzCguHB/Mv6uVIiW659wpbyb45TgKG3UhQIDAQAB" />
+          <public-key android:name="keyB"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoeFZqMqTbZiozFTXMkXtSKJRzn2qODZgvVXAAwKTi50xYcbPcHTfKxtif8+q7OCp/50JYDH32bg6wkUunn5+dEaHkxZY8d7uw46tQtl5dNGi+6cc4MezVLCS6nkqNDusAgdvgLU6Fl6SGi02KTp1vkt6CwLO977YJP7kt9ouDRTG7ASJiq3OyRRoOqYHhD9gpsbUq4w+1bXGfuuZujA1dXyovXtvrHUGOdFIEBYOVYGfCcwh3lXPmjNJMlHtKQkurq8/LH7a1B5ocoXCGsyR8YHdlWfrqRAfzgOB1KCnNNmWqskU9LOci3uQn9IDeMEFmAd8FqF8SwV+4Ludk/xWGQIDAQAB" />
+        </key-set>
+        <upgrade-key-set android:name="AB"/>
+    </key-sets>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
new file mode 100644
index 0000000..75729e0
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2014 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)
+
+#apks signed cts-keyset-test-a
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningAUpgradeAOrB
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAuB/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/keysets/uAuB/AndroidManifest.xml
new file mode 100644
index 0000000..546c5fe
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAuB/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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="com.android.cts.keysets">
+    <application android:hasCode="false">
+    </application>
+    <key-sets>
+        <key-set android:name="A" >
+          <public-key android:name="keyA"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwf5zJblvYSB7Ym7or/7GggAAu7mp7RrykPJsXhod8doFhVT5s7eF3A4MCE55vvANP7HvwMw2b+T6qx7Pq0VJtbbSDtlBHBtIc47Pjq0CsDg590BUcgKp7PdJ9J6UVgtzDnV6cGEpXmSag3sY+lqiW04ytPhCVwzYTWGdYe9+TIl47cBrveRfLOlGrcuFQe+zCTmDFqzBKCRHK9b7l5PDWvXXyg65Uu/MBUA/TZWO0fEqOlxZG/nn6DUKQLhPdmJRXWJ3WqMNMhJGD+nKtkmdX703xRqmg4h+6g0S7M9Y3IQ2NUGyw05AYzCguHB/Mv6uVIiW659wpbyb45TgKG3UhQIDAQAB" />
+        </key-set>
+        <key-set android:name="B" >
+          <public-key android:name="keyB"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoeFZqMqTbZiozFTXMkXtSKJRzn2qODZgvVXAAwKTi50xYcbPcHTfKxtif8+q7OCp/50JYDH32bg6wkUunn5+dEaHkxZY8d7uw46tQtl5dNGi+6cc4MezVLCS6nkqNDusAgdvgLU6Fl6SGi02KTp1vkt6CwLO977YJP7kt9ouDRTG7ASJiq3OyRRoOqYHhD9gpsbUq4w+1bXGfuuZujA1dXyovXtvrHUGOdFIEBYOVYGfCcwh3lXPmjNJMlHtKQkurq8/LH7a1B5ocoXCGsyR8YHdlWfrqRAfzgOB1KCnNNmWqskU9LOci3uQn9IDeMEFmAd8FqF8SwV+4Ludk/xWGQIDAQAB" />
+        </key-set>
+        <upgrade-key-set android:name="A"/>
+        <upgrade-key-set android:name="B"/>
+    </key-sets>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
new file mode 100644
index 0000000..121c342
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
@@ -0,0 +1,55 @@
+# Copyright (C) 2014 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)
+
+#apks signed cts-keyset-test-a
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningAUpgradeB
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+#apks signed cts-keyset-test-b
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningBUpgradeB
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+#apks signed by cts-keyset-test-a and cts-keyset-test-c
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningAAndCUpgradeB
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_ADDITIONAL_CERTIFICATES := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uB/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/keysets/uB/AndroidManifest.xml
new file mode 100644
index 0000000..9c837bc
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uB/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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="com.android.cts.keysets">
+    <application android:hasCode="false">
+    </application>
+    <key-sets>
+        <key-set android:name="B" >
+          <public-key android:name="keyB"
+                      android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoeFZqMqTbZiozFTXMkXtSKJRzn2qODZgvVXAAwKTi50xYcbPcHTfKxtif8+q7OCp/50JYDH32bg6wkUunn5+dEaHkxZY8d7uw46tQtl5dNGi+6cc4MezVLCS6nkqNDusAgdvgLU6Fl6SGi02KTp1vkt6CwLO977YJP7kt9ouDRTG7ASJiq3OyRRoOqYHhD9gpsbUq4w+1bXGfuuZujA1dXyovXtvrHUGOdFIEBYOVYGfCcwh3lXPmjNJMlHtKQkurq8/LH7a1B5ocoXCGsyR8YHdlWfrqRAfzgOB1KCnNNmWqskU9LOci3uQn9IDeMEFmAd8FqF8SwV+4Ludk/xWGQIDAQAB" />
+        </key-set>
+        <upgrade-key-set android:name="B"/>
+    </key-sets>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
new file mode 100644
index 0000000..a8746ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2014 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)
+
+#apks signed cts-keyset-test-a
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningAUpgradeNone
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uNone/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/keysets/uNone/AndroidManifest.xml
new file mode 100644
index 0000000..55304f4
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uNone/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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="com.android.cts.keysets">
+    <application android:hasCode="false">
+    </application>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/AndroidManifest.xml b/hostsidetests/devicepolicy/app/IntentReceiver/AndroidManifest.xml
index ab01ffb..e1f6886 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/AndroidManifest.xml
@@ -19,11 +19,14 @@
 
     <uses-sdk android:minSdkVersion="19"/>
 
+    <uses-permission android:name="com.android.cts.managedprofile.permission.SAMPLE"/>
+
     <application>
         <activity android:name="com.android.cts.intent.receiver.IntentReceiverActivity">
             <intent-filter>
                 <action android:name="com.android.cts.action.READ_FROM_URI" />
                 <action android:name="com.android.cts.action.WRITE_TO_URI" />
+                <action android:name="com.android.cts.action.TAKE_PERSISTABLE_URI_PERMISSION" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
index 2389402..17dc3f1 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
@@ -40,24 +40,48 @@
 
     private static final String ACTION_WRITE_TO_URI = "com.android.cts.action.WRITE_TO_URI";
 
+    private static final String ACTION_TAKE_PERSISTABLE_URI_PERMISSION =
+            "com.android.cts.action.TAKE_PERSISTABLE_URI_PERMISSION";
+
+    private static final String EXTRA_CAUGHT_SECURITY_EXCEPTION = "extra_caught_security_exception";
+
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Intent received = getIntent();
         String action = received.getAction();
-
+        Uri uri = getIntent().getClipData().getItemAt(0).getUri();
         if (ACTION_READ_FROM_URI.equals(action)) {
             Intent result = new Intent();
-            String message = getFirstLineFromUri(getIntent().getClipData().getItemAt(0).getUri());
-            Log.i(TAG, "message received in reading test: " + message);
+            String message = null;
+            try {
+                message = getFirstLineFromUri(uri);
+            } catch (SecurityException e) {
+                Log.i(TAG, "Caught a SecurityException while trying to read " + uri, e);
+                result.putExtra(EXTRA_CAUGHT_SECURITY_EXCEPTION, true);
+            } catch (IOException e) {
+                Log.i(TAG, "Caught a IOException while trying to read " + uri, e);
+            }
+            Log.i(TAG, "Message received in reading test: " + message);
             result.putExtra("extra_response", message);
-            setResult(message != null ? Activity.RESULT_OK : Activity.RESULT_CANCELED, result);
+            setResult(Activity.RESULT_OK, result);
         } else if (ACTION_WRITE_TO_URI.equals(action)) {
             Intent result = new Intent();
             String message = received.getStringExtra("extra_message");
-            Log.i(TAG, "message received in writing test: " + message);
-            Uri uri = getIntent().getClipData().getItemAt(0).getUri();
-            boolean succeded = writeToUri(uri, message);
-            setResult(succeded ? Activity.RESULT_OK : Activity.RESULT_CANCELED);
+            Log.i(TAG, "Message received in writing test: " + message);
+            try {
+                writeToUri(uri, message);
+            } catch (SecurityException e) {
+                Log.i(TAG, "Caught a SecurityException while trying to write to " + uri, e);
+                result.putExtra(EXTRA_CAUGHT_SECURITY_EXCEPTION, true);
+            } catch (IOException e) {
+                Log.i(TAG, "Caught a IOException while trying to write to " + uri, e);
+            }
+            setResult(Activity.RESULT_OK, result);
+        } else if (ACTION_TAKE_PERSISTABLE_URI_PERMISSION.equals(action)) {
+            Log.i(TAG, "Taking persistable uri permission to " + uri);
+            getContentResolver().takePersistableUriPermission(uri,
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            setResult(Activity.RESULT_OK);
         }
         finish();
     }
@@ -65,28 +89,17 @@
     /**
      * Returns the first line of the file associated with uri.
      */
-    private String getFirstLineFromUri(Uri uri) {
-        try {
-            InputStream is = getContentResolver().openInputStream(uri);
-            BufferedReader r = new BufferedReader(new InputStreamReader(is));
-            return r.readLine();
-        } catch (IOException e) {
-            Log.e(TAG, "could not read the uri " + uri, e);
-            return null;
-        }
+    private String getFirstLineFromUri(Uri uri) throws IOException {
+        InputStream is = getContentResolver().openInputStream(uri);
+        BufferedReader r = new BufferedReader(new InputStreamReader(is));
+        return r.readLine();
     }
 
-    private boolean writeToUri(Uri uri, String text) {
-        try {
-            OutputStreamWriter writer = new OutputStreamWriter(
-                    getContentResolver().openOutputStream(uri));
-            writer.write(text);
-            writer.flush();
-            writer.close();
-            return true;
-        } catch (IOException e) {
-            Log.e(TAG, "could not write to the uri " + uri, e);
-            return false;
-        }
+    private void writeToUri(Uri uri, String text) throws IOException {
+        OutputStreamWriter writer = new OutputStreamWriter(
+                getContentResolver().openOutputStream(uri));
+        writer.write(text);
+        writer.flush();
+        writer.close();
     }
 }
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index 643400b..56b3671 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -19,6 +19,9 @@
 
     <uses-sdk android:minSdkVersion="20"/>
 
+    <permission android:name="com.android.cts.managedprofile.permission.SAMPLE"
+                android:label="Sample Permission"/>
+
     <application>
         <uses-library android:name="android.test.runner" />
         <receiver
@@ -67,6 +70,13 @@
                 <action android:name="android.intent.action.MAIN"/>
             </intent-filter>
         </activity>
+        <activity android:name=".UserRestrictionActivity" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+        <activity android:name=".TestActivity" />
         <provider
             android:name="android.support.v4.content.FileProvider"
             android:authorities="com.android.cts.managedprofile.fileprovider"
@@ -76,7 +86,13 @@
                 android:name="android.support.FILE_PROVIDER_PATHS"
                 android:resource="@xml/filepaths" />
         </provider>
-        <activity android:name=".TestActivity" />
+        <provider
+            android:name="com.android.cts.managedprofile.crossprofilecontent.BasicContentProvider"
+            android:authorities="com.android.cts.managedprofile.basiccontentProvider"
+            android:grantUriPermissions="true"
+            android:exported="true"
+            android:permission="com.android.cts.managedprofile.permission.SAMPLE"
+            />
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserRestrictionActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserRestrictionActivity.java
new file mode 100644
index 0000000..e8decf8
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserRestrictionActivity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 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 com.android.cts.managedprofile;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Process;
+import android.util.Log;
+
+import com.android.cts.managedprofile.BaseManagedProfileTest;
+
+/**
+ * Simple activity that adds or clears a user restriction depending on the value of the extras.
+ */
+public class UserRestrictionActivity extends Activity {
+
+    private static final String TAG = UserRestrictionActivity.class.getName();
+
+    private static final String EXTRA_RESTRICTION_KEY = "extra-restriction-key";
+    private static final String EXTRA_COMMAND = "extra-command";
+
+    private static final String ADD_COMMAND = "add-restriction";
+    private static final String CLEAR_COMMAND = "clear-restriction";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        handleIntent(getIntent());
+    }
+
+    // Overriding this method in case another intent is sent to this activity before finish()
+    @Override
+    public void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        handleIntent(intent);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        // Calling finish() here because doing it in onCreate(), onStart() or onResume() makes
+        // "adb shell am start" timeout if using the -W option.
+        finish();
+    }
+
+    private void handleIntent(Intent intent) {
+        DevicePolicyManager dpm = (DevicePolicyManager)
+                getSystemService(Context.DEVICE_POLICY_SERVICE);
+        String restrictionKey = intent.getStringExtra(EXTRA_RESTRICTION_KEY);
+        String command = intent.getStringExtra(EXTRA_COMMAND);
+        Log.i(TAG, "Command: \"" + command + "\". Restriction: \"" + restrictionKey + "\"");
+
+        if (ADD_COMMAND.equals(command)) {
+            dpm.addUserRestriction(BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
+            Log.i(TAG, "Added user restriction " + restrictionKey
+                    + " for user " + Process.myUserHandle());
+        } else if (CLEAR_COMMAND.equals(command)) {
+            dpm.clearUserRestriction(
+                    BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
+            Log.i(TAG, "Cleared user restriction " + restrictionKey
+                    + " for user " + Process.myUserHandle());
+        } else {
+            Log.e(TAG, "Invalid command: " + command);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/BasicContentProvider.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/BasicContentProvider.java
new file mode 100644
index 0000000..f91d404
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/BasicContentProvider.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 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 com.android.cts.managedprofile.crossprofilecontent;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * Empty content provider, all permissions are enforced in manifest
+ */
+public class BasicContentProvider extends ContentProvider {
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        // do nothing
+        return 0;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return "";
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public boolean onCreate() {
+        return false;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection,
+            String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+        return ParcelFileDescriptor.open(
+                new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY);
+    }
+}
+
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java
index aa9506b..85e7d1b 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java
@@ -18,33 +18,194 @@
 import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
 
 import android.app.admin.DevicePolicyManager;
+import android.content.ClipData;
+import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.support.v4.content.FileProvider;
 import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
 
 public class CrossProfileContentTest extends
         ActivityInstrumentationTestCase2<IntentSenderActivity> {
 
     private static final String MESSAGE = "Sample Message";
 
+    private static final String ACTION_READ_FROM_URI = "com.android.cts.action.READ_FROM_URI";
+
+    private static final String ACTION_WRITE_TO_URI = "com.android.cts.action.WRITE_TO_URI";
+
+    private static final String ACTION_TAKE_PERSISTABLE_URI_PERMISSION =
+            "com.android.cts.action.TAKE_PERSISTABLE_URI_PERMISSION";
+
+    private static final String TAG = "CrossProfileContentTest";
+
+    private static final String BASIC_CONTENT_PROVIDER_AUTHORITY =
+            "com.android.cts.managedprofile.basiccontentProvider";
+
+
+    private DevicePolicyManager mDpm;
+
+    private Context mContext;
+
     public CrossProfileContentTest() {
         super(IntentSenderActivity.class);
     }
 
     @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getTargetContext();
+        mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ACTION_READ_FROM_URI);
+        intentFilter.addAction(ACTION_WRITE_TO_URI);
+        intentFilter.addAction(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
+        mDpm.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, intentFilter,
+                DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
+    }
+
+    @Override
     protected void tearDown() throws Exception {
-        DevicePolicyManager dpm = (DevicePolicyManager)
-               getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
-        dpm.clearCrossProfileIntentFilters(ADMIN_RECEIVER_COMPONENT);
+        mDpm.clearCrossProfileIntentFilters(ADMIN_RECEIVER_COMPONENT);
         super.tearDown();
     }
 
+    /**
+     * This method will send an intent to a receiver in another profile.
+     * This intent will have, in the ClipData, a uri whose associated file stores a message.
+     * The receiver will read the message from the uri, and put it inside the result intent.
+     */
     public void testReceiverCanRead() {
-        String response = getActivity().testReceiverCanRead(MESSAGE);
-        assertEquals(response, MESSAGE);
+        Uri uri = getUriWithTextInFile("reading_test", MESSAGE);
+        assertTrue(uri != null);
+        Intent intent = new Intent(ACTION_READ_FROM_URI);
+        intent.setClipData(ClipData.newRawUri("", uri));
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        Intent result = getActivity().getResultForIntent(intent);
+        assertTrue(result != null);
+        assertEquals(MESSAGE, result.getStringExtra("extra_response"));
     }
 
+    /**
+     * This method will send an intent to a receiver in another profile.
+     * This intent will have a message in an extra, and a uri specified by the ClipData.
+     * The receiver will read the message from the extra, and write it to the uri in
+     * the ClipData.
+     */
     public void testReceiverCanWrite() {
-        String response = getActivity().testReceiverCanWrite(MESSAGE);
-        assertEquals(response, MESSAGE);
+        // It's the receiver of the intent that should write to the uri, not us. So, for now, we
+        // write an empty string.
+        Uri uri = getUriWithTextInFile("writing_test", "");
+        assertTrue(uri != null);
+        Intent intent = new Intent(ACTION_WRITE_TO_URI);
+        intent.setClipData(ClipData.newRawUri("", uri));
+        intent.putExtra("extra_message", MESSAGE);
+        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        getActivity().getResultForIntent(intent);
+        assertEquals(MESSAGE, getFirstLineFromUri(uri));
+    }
+
+    public void testPersistablePermission() {
+        Uri uri = getUriWithTextInFile("persistable_test", MESSAGE);
+        grantPersistableReadPermission(uri);
+
+        // Now checking if the receiver can read this uri, without re-granting the read permission.
+        Intent intent = new Intent(ACTION_READ_FROM_URI);
+        intent.setClipData(ClipData.newRawUri("", uri));
+        Intent result = getActivity().getResultForIntent(intent);
+        assertTrue(result != null);
+        assertEquals(MESSAGE, result.getStringExtra("extra_response"));
+    }
+
+    /**
+     * The intent receiver will try to read uriNotGranted.
+     * Inside the same user, this uri can be read if the receiver has the
+     * com.android.cts.managedprofile.permission.SAMPLE permission. But since we cross
+     * user-boundaries, it should not be able to (only uri grants work accross users for apps
+     * without special permission).
+     * We also grant uriGranted to the receiver (this uri belongs to the same content provider as
+     * uriNotGranted), to enforce that even if an app has permission to one uri of a
+     * ContentProvider, it still cannot access a uri it does not have access to.
+     */
+    public void testAppPermissionsDontWorkAcrossProfiles() {
+        // The FileProvider does not allow to use app permissions. So we need to use another
+        // ContentProvider.
+        Uri uriGranted = getBasicContentProviderUri("uri_granted");
+        Uri uriNotGranted = getBasicContentProviderUri("uri_not_granted");
+
+        // Granting uriGranted to the receiver
+        // Using a persistable permission so that it is kept even after we restart the receiver
+        // activity with another intent.
+        grantPersistableReadPermission(uriGranted);
+
+        Intent notGrant = new Intent(ACTION_READ_FROM_URI);
+        notGrant.setClipData(ClipData.newRawUri("", uriNotGranted));
+
+        Intent result = getActivity().getResultForIntent(notGrant);
+        assertTrue(result != null);
+        // The receiver did not have permission to read the uri. So it should have caught a security
+        // exception.
+        assertTrue(result.getBooleanExtra("extra_caught_security_exception", false));
+    }
+
+    private void grantPersistableReadPermission(Uri uri) {
+        Intent grantPersistable = new Intent(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
+        grantPersistable.setClipData(ClipData.newRawUri("", uri));
+        grantPersistable.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+        getActivity().getResultForIntent(grantPersistable);
+    }
+
+    private Uri getBasicContentProviderUri(String path) {
+        // The uris created here are not associated with any data. But this does not prevent us from
+        // granting these uris to other apps, or these apps from trying to access these uris.
+        return new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(BASIC_CONTENT_PROVIDER_AUTHORITY)
+                .path(path)
+                .build();
+    }
+
+    private Uri getUriWithTextInFile(String name, String text) {
+        String filename = mContext.getFilesDir() + File.separator + "texts" + File.separator
+                + name + ".txt";
+        Log.i(TAG, "Creating file " + filename + " with text \"" + text + "\"");
+        final File file = new File(filename);
+        file.getParentFile().mkdirs(); // If the folder doesn't exists it is created
+        try {
+            FileWriter writer = new FileWriter(file);
+            writer.write(text);
+            writer.close();
+        } catch(IOException e) {
+            Log.e(TAG, "Could not create file " + filename + " with text " + text);
+            return null;
+        }
+        return FileProvider.getUriForFile(mContext, "com.android.cts.managedprofile.fileprovider",
+                file);
+    }
+
+    /**
+     * Returns the first line of the file associated with uri.
+     */
+    private String getFirstLineFromUri(Uri uri) {
+        try {
+            InputStream is = mContext.getContentResolver().openInputStream(uri);
+            BufferedReader r = new BufferedReader(new InputStreamReader(is));
+            return r.readLine();
+        } catch (IOException e) {
+            Log.e(TAG, "could not read the uri " + uri);
+            return null;
+        }
     }
 }
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java
index 6c8020f..e4c8ddf 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java
@@ -17,152 +17,36 @@
 
 import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
 
-import android.app.admin.DevicePolicyManager;
 import android.app.Activity;
-import android.content.ClipData;
-import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.Uri;
-import android.os.Bundle;
 import android.util.Log;
-import android.support.v4.content.FileProvider;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.IOException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 public class IntentSenderActivity extends Activity {
 
-    private final static String TAG = "IntentSenderActivity";
-
-    private final CountDownLatch mLatch = new CountDownLatch(1);
-
-    private static final String ACTION_READ_FROM_URI = "com.android.cts.action.READ_FROM_URI";
-
-    private static final String ACTION_WRITE_TO_URI = "com.android.cts.action.WRITE_TO_URI";
-
-    private static final int TEST_RECEIVER_CAN_READ = 1;
-    private static final int TEST_RECEIVER_CAN_WRITE = 2;
+    private CountDownLatch mLatch;
 
     private static final int WAIT_FOR_RESPONSE_TIMEOUT_SECONDS = 5;
 
-    private String mResponse;
+    private Intent mResult;
 
-    private Uri mUriToWrite;
-
-    private DevicePolicyManager mDevicePolicyManager;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mDevicePolicyManager = (DevicePolicyManager)
-                getSystemService(Context.DEVICE_POLICY_SERVICE);
-    }
-
-    /**
-     * This method will send an intent to a receiver in another profile.
-     * This intent will have, in the ClipData, a uri whose associated file stores this message.
-     * The receiver will read the message from the uri, and put it inside the result intent.
-     * This method returns the response in the result intent, or null if no response was received.
-     */
-    String testReceiverCanRead(String message) {
-        IntentFilter testIntentFilter = new IntentFilter();
-        testIntentFilter.addAction(ACTION_READ_FROM_URI);
-        mDevicePolicyManager.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, testIntentFilter,
-                DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
-
-        Intent intent = new Intent(ACTION_READ_FROM_URI);
-        intent.setClipData(ClipData.newRawUri("", getUriWithTextInFile("reading_test", message)));
-        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        startActivityForResult(intent, TEST_RECEIVER_CAN_READ);
+    Intent getResultForIntent(Intent intent) {
+        mLatch = new CountDownLatch(1);
+        mResult = null;
+        startActivityForResult(intent, 0);
         try {
             mLatch.await(WAIT_FOR_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
         } catch (InterruptedException e) {
-            return null;
         }
-        return mResponse;
-    }
-
-    /**
-     * This method will send an intent to a receiver in another profile.
-     * This intent will have a message in an extra, and a uri specified by the ClipData.
-     * The receiver will read the message from the extra, and write it to the uri in
-     * the ClipData.
-     * This method returns what has been written in the uri.
-     */
-    String testReceiverCanWrite(String message) {
-        IntentFilter testIntentFilter = new IntentFilter();
-        testIntentFilter.addAction(ACTION_WRITE_TO_URI);
-        mDevicePolicyManager.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, testIntentFilter,
-                DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
-        // It's the receiver of the intent that should write to the uri, not us. So, for now, we
-        // write an empty string.
-        mUriToWrite = getUriWithTextInFile("writing_test", "");
-        Intent intent = new Intent(ACTION_WRITE_TO_URI);
-        intent.setClipData(ClipData.newRawUri("", mUriToWrite));
-        intent.putExtra("extra_message", message);
-        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
-                | Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        startActivityForResult(intent, TEST_RECEIVER_CAN_WRITE);
-        try {
-            mLatch.await(WAIT_FOR_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-        } catch (InterruptedException e) {
-            return null;
-        }
-        return mResponse;
+        return mResult;
     }
 
     @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == TEST_RECEIVER_CAN_READ) {
-            if (resultCode == Activity.RESULT_OK) {
-                mResponse = data.getStringExtra("extra_response");
-                Log.i(TAG, "response received in reading test: " + mResponse);
-            }
-        } else if (requestCode == TEST_RECEIVER_CAN_WRITE) {
-            if (resultCode == Activity.RESULT_OK) {
-                mResponse = getFirstLineFromUri(mUriToWrite);
-                Log.i(TAG, "response received in writing test: " + mResponse);
-            }
+    protected void onActivityResult(int requestCode, int resultCode, Intent result) {
+        if (resultCode == Activity.RESULT_OK) {
+            mResult = result;
         }
         mLatch.countDown();
-        finish();
-    }
-
-    private Uri getUriWithTextInFile(String name, String text) {
-        String filename = getFilesDir() + File.separator + "texts" + File.separator + name + ".txt";
-        Log.i(TAG, "Creating file " + filename + " with text \"" + text + "\"");
-        final File file = new File(filename);
-        file.getParentFile().mkdirs(); // If the folder doesn't exists it is created
-        try {
-            FileWriter writer = new FileWriter(file);
-            writer.write(text);
-            writer.close();
-        } catch(IOException e) {
-            Log.e(TAG, "Could not create file " + filename + " with text " + text);
-            return null;
-        }
-        return FileProvider.getUriForFile(this,
-                "com.android.cts.managedprofile.fileprovider", file);
-    }
-
-    /**
-     * Returns the first line of the file associated with uri.
-     */
-    private String getFirstLineFromUri(Uri uri) {
-        try {
-            InputStream is = getContentResolver().openInputStream(uri);
-            BufferedReader r = new BufferedReader(new InputStreamReader(is));
-            return r.readLine();
-        } catch (IOException e) {
-            Log.e(TAG, "could not read the uri " + uri);
-            return null;
-        }
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 4e57b28..88a3b70 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -124,16 +124,55 @@
         }
     }
 
+    // TODO: This test is not specific to managed profiles, but applies to multi-user in general.
+    // Move it to a MultiUserTest class when there is one. Should probably move
+    // UserRestrictionActivity to a more generic apk too as it might be useful for different kinds
+    // of tests (same applies to ComponentDisablingActivity).
+    public void testNoDebuggingFeaturesRestriction() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        String restriction = "no_debugging_features";  // UserManager.DISALLOW_DEBUGGING_FEATURES
+        String command = "add-restriction";
+
+        String addRestrictionCommandOutput =
+                changeUserRestrictionForUser(restriction, command, mUserId);
+        assertTrue("Command was expected to succeed " + addRestrictionCommandOutput,
+                addRestrictionCommandOutput.contains("Status: ok"));
+
+        // This should now fail, as the shell is not available to start activities under a different
+        // user once the restriction is in place.
+        addRestrictionCommandOutput =
+                changeUserRestrictionForUser(restriction, command, mUserId);
+        assertTrue(
+                "Expected SecurityException when starting the activity "
+                        + addRestrictionCommandOutput,
+                addRestrictionCommandOutput.contains("SecurityException"));
+    }
+
     private void disableActivityForUser(String activityName, int userId)
             throws DeviceNotAvailableException {
         String command = "am start -W --user " + userId
                 + " --es extra-package " + MANAGED_PROFILE_PKG
-                + " --es extra-class-name " + MANAGED_PROFILE_PKG + "." + activityName + " "
-                + MANAGED_PROFILE_PKG + "/.ComponentDisablingActivity ";
+                + " --es extra-class-name " + MANAGED_PROFILE_PKG + "." + activityName
+                + " " + MANAGED_PROFILE_PKG + "/.ComponentDisablingActivity ";
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": "
                 + getDevice().executeShellCommand(command));
     }
 
+    private String changeUserRestrictionForUser(String key, String command, int userId)
+            throws DeviceNotAvailableException {
+        String adbCommand = "am start -W --user " + userId
+                + " -c android.intent.category.DEFAULT "
+                + " --es extra-command " + command
+                + " --es extra-restriction-key " + key
+                + " " + MANAGED_PROFILE_PKG + "/.UserRestrictionActivity";
+        String commandOutput = getDevice().executeShellCommand(adbCommand);
+        CLog.logAndDisplay(LogLevel.INFO,
+                "Output for command " + adbCommand + ": " + commandOutput);
+        return commandOutput;
+    }
+
     private int createManagedProfile() throws DeviceNotAvailableException {
         String command =
                 "pm create-user --profileOf 0 --managed TestProfile_" + System.currentTimeMillis();
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index b4c9ebb..40a66d2 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -91,19 +91,6 @@
   bug: 17496766
 },
 {
-  description: "As per new CTS test case adding policy",
-  names: [
-    "com.android.cts.managedprofile.PrimaryUserTest#testAddCrossProfileIntentFilter_primary",
-    "com.android.cts.managedprofile.PrimaryUserTest#testAddCrossProfileIntentFilter_all",
-    "com.android.cts.managedprofile.PrimaryUserTest#testAddCrossProfileIntentFilter_managed",
-    "com.android.cts.managedprofile.ManagedProfile#testClearCrossProfileIntentFilters",
-    "com.android.cts.managedprofile.ManagedProfile#testAddCrossProfileIntentFilter_primary",
-    "com.android.cts.managedprofile.ManagedProfile#testAddCrossProfileIntentFilter_all",
-    "com.android.cts.managedprofile.ManagedProfile#testAddCrossProfileIntentFilter_managed"
-  ],
-  bug: 15900074
-},
-{
   description: "these tests locks the screen with an emtpy password or swipe-to-unlock, blocking subsequent test to dismiss keyguard",
   names: [
     "com.android.cts.devicepolicy.DeviceOwnerTest#testKeyManagement"
@@ -128,7 +115,8 @@
     "com.android.cts.devicepolicy.ManagedProfileTest#testManagedProfileSetup",
     "com.android.cts.devicepolicy.ManagedProfileTest#testWipeData",
     "com.android.cts.devicepolicy.ManagedProfileTest#testCrossProfileIntentFilters",
-    "com.android.cts.devicepolicy.ManagedProfileTest#testCrossProfileContent"
+    "com.android.cts.devicepolicy.ManagedProfileTest#testCrossProfileContent",
+    "com.android.cts.devicepolicy.ManagedProfileTest#testNoDebuggingFeaturesRestriction"
   ]
 },
 {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
index a68f78d..61f25fb 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -88,6 +88,10 @@
             try {
                 Log.v(TAG, "Testing jpeg capture for Camera " + id);
                 openDevice(id);
+                if (mStaticInfo.isHardwareLevelLegacy()) {
+                    Log.i(TAG, "Skipping test on legacy devices");
+                    continue;
+                }
                 bufferFormatTestByCamera(ImageFormat.JPEG, /*repeating*/false);
             } finally {
                 closeDevice(id);
@@ -113,6 +117,10 @@
             try {
                 Log.v(TAG, "Testing repeating jpeg capture for Camera " + id);
                 openDevice(id);
+                if (mStaticInfo.isHardwareLevelLegacy()) {
+                    Log.i(TAG, "Skipping test on legacy devices");
+                    continue;
+                }
                 bufferFormatTestByCamera(ImageFormat.JPEG, /*repeating*/true);
             } finally {
                 closeDevice(id);
@@ -148,7 +156,10 @@
             try {
                 Log.v(TAG, "YUV and JPEG testing for camera " + id);
                 openDevice(id);
-
+                if (mStaticInfo.isHardwareLevelLegacy()) {
+                    Log.i(TAG, "Skipping test on legacy devices");
+                    continue;
+                }
                 bufferFormatWithYuvTestByCamera(ImageFormat.JPEG);
             } finally {
                 closeDevice(id);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index 7a6e088..ea15c19 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -497,6 +497,11 @@
 
                     openDevice(id);
 
+                    if (mStaticInfo.isHardwareLevelLegacy()) {
+                        Log.i(TAG, "Skipping test on legacy devices");
+                        continue;
+                    }
+
                     initSupportedVideoSize(id);
 
                     videoSnapshotTestByCamera(burstTest);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
index 11ba02c..7960200 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -185,6 +185,11 @@
 
             final StaticMetadata staticInfo = new StaticMetadata(cc);
 
+            if (staticInfo.isHardwareLevelLegacy()) {
+                Log.i(TAG, "Skipping test on legacy devices");
+                continue;
+            }
+
             openDevice(id);
 
             // Always run legacy-level tests