Commits

Stephen Smalley committed 37db7de

Device admin APIs for SELinux and MMAC.

Comments (0)

Files changed (7)

     field public static final int USES_ENCRYPTED_STORAGE = 7; // 0x7
     field public static final int USES_POLICY_DISABLE_CAMERA = 8; // 0x8
     field public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9; // 0x9
+    field public static final int USES_POLICY_ENFORCE_MMAC = 11; // 0xb
+    field public static final int USES_POLICY_ENFORCE_SELINUX = 10; // 0xa
     field public static final int USES_POLICY_EXPIRE_PASSWORD = 6; // 0x6
     field public static final int USES_POLICY_FORCE_LOCK = 3; // 0x3
     field public static final int USES_POLICY_LIMIT_PASSWORD = 0; // 0x0
     method public boolean getCameraDisabled(android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+    method public boolean getMMACenforcing(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public int getPasswordMinimumSymbols(android.content.ComponentName);
     method public int getPasswordMinimumUpperCase(android.content.ComponentName);
     method public int getPasswordQuality(android.content.ComponentName);
+    method public java.util.List<java.lang.String> getSELinuxBooleanNames(android.content.ComponentName);
+    method public boolean getSELinuxBooleanValue(android.content.ComponentName, java.lang.String);
+    method public boolean getSELinuxEnforcing(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
+    method public boolean isCustomPolicyFile(android.content.ComponentName, int);
+    method public boolean isMMACadmin(android.content.ComponentName);
+    method public boolean isSELinuxAdmin(android.content.ComponentName);
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public void lockNow();
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
+    method public boolean setCustomPolicyFile(android.content.ComponentName, int, byte[]);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
+    method public boolean setMMACadmin(android.content.ComponentName, boolean);
+    method public boolean setMMACenforcing(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordMinimumSymbols(android.content.ComponentName, int);
     method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
     method public void setPasswordQuality(android.content.ComponentName, int);
+    method public boolean setSELinuxAdmin(android.content.ComponentName, boolean);
+    method public boolean setSELinuxBooleanValue(android.content.ComponentName, java.lang.String, boolean);
+    method public boolean setSELinuxEnforcing(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
     field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
     field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
+    field public static final int MMAC_POLICY_FILE = 4; // 0x4
     field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
     field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
     field public static final int PASSWORD_QUALITY_BIOMETRIC_WEAK = 32768; // 0x8000
     field public static final int PASSWORD_QUALITY_SOMETHING = 65536; // 0x10000
     field public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; // 0x0
     field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
+    field public static final int SEPOLICY_FILE_COUNT = 5; // 0x5
+    field public static final int SEPOLICY_FILE_FILECTXS = 2; // 0x2
+    field public static final int SEPOLICY_FILE_PROPCTXS = 1; // 0x1
+    field public static final int SEPOLICY_FILE_SEAPPCTXS = 3; // 0x3
+    field public static final int SEPOLICY_FILE_SEPOLICY = 0; // 0x0
     field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
   }
 

core/java/android/app/admin/DeviceAdminInfo.java

      */
     public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9;
 
+    /**
+     * A type of policy that this device admin can use: enforce SELinux policy.
+     *
+     * <p>To control this policy, the device admin must have a "enforce-selinux"
+     * tag in the "uses-policies" section of its meta-data.
+     */
+    public static final int USES_POLICY_ENFORCE_SELINUX = 10;
+
+    /**
+     * A type of policy that this device admin can use: enforce SE Android MMAC policy.
+     *
+     * <p>To control this policy, the device admin must have a "enforce-mmac" tag in the
+     * "uses-policies" section of its meta-data.
+     */
+    public static final int USES_POLICY_ENFORCE_MMAC = 11;
+
+
     /** @hide */
     public static class PolicyInfo {
         public final int ident;
                 USES_POLICY_DISABLE_KEYGUARD_FEATURES, "disable-keyguard-features",
                 com.android.internal.R.string.policylab_disableKeyguardFeatures,
                 com.android.internal.R.string.policydesc_disableKeyguardFeatures));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_ENFORCE_SELINUX, "enforce-selinux",
+                com.android.internal.R.string.policylab_enforceSelinux,
+                com.android.internal.R.string.policydesc_enforceSelinux));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_ENFORCE_MMAC, "enforce-mmac",
+                com.android.internal.R.string.policylab_enforceMmac,
+                com.android.internal.R.string.policydesc_enforceMmac));
 
         for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
             PolicyInfo pi = sPoliciesDisplayOrder.get(i);
      * {@link #USES_POLICY_RESET_PASSWORD}, {@link #USES_POLICY_FORCE_LOCK},
      * {@link #USES_POLICY_WIPE_DATA},
      * {@link #USES_POLICY_EXPIRE_PASSWORD}, {@link #USES_ENCRYPTED_STORAGE},
-     * {@link #USES_POLICY_DISABLE_CAMERA}.
+     * {@link #USES_POLICY_DISABLE_CAMERA}, {@link #USES_POLICY_ENFORCE_SELINUX},
+     * {@link #USES_POLICY_ENFORCE_MMAC}.
      */
     public boolean usesPolicy(int policyIdent) {
         return (mUsesPolicies & (1<<policyIdent)) != 0;

core/java/android/app/admin/DevicePolicyManager.java

     }
 
     /**
+     * Called by an application that is administering the device to start or stop
+     * controlling SELinux policies, enforcement, booleans, etc. When an admin app
+     * gives up control of SELinux policies, the policy in place prior to the app
+     * taking control will be applied.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * <p>When an application gains control of SELinux settings, it is called an
+     * SELinux administrator. Admistration applications will call this with true and
+     * ensure this method returned true before attempting to toggle SELinux settings.
+     * When apps intend to stop controlling SELinux settings, apps should call this
+     * with false.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated,
+     * must be self
+     * @param control true if the admin wishes to control SELinux, false if the admin
+     * wishes to give back control of SELinux
+     * @return true if the operation succeeded, false if the operation failed or
+     * SELinux was not enabled on the device.
+     */
+    public boolean setSELinuxAdmin(ComponentName admin, boolean control) {
+        return setSELinuxAdmin(admin, control, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean setSELinuxAdmin(ComponentName admin, boolean control, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.setSELinuxAdmin(admin, control, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether an admin app has control over SELinux policy.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated,
+     * must be self
+     * @return true if admin app can control SELinux policy, false otherwise
+     */
+    public boolean isSELinuxAdmin(ComponentName admin) {
+        return isSELinuxAdmin(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean isSELinuxAdmin(ComponentName admin, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.isSELinuxAdmin(admin, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by a SELinux admin to set SELinux into enforcing or permissive mode.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param enforcing true for enforcing mode, false for permissive mode.
+     * @return false if Android was unable to set the desired mode
+     */
+    public boolean setSELinuxEnforcing(ComponentName admin, boolean enforcing) {
+        return setSELinuxEnforcing(admin, enforcing, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean setSELinuxEnforcing(ComponentName admin, boolean enforcing, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.setSELinuxEnforcing(admin, enforcing, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false; // I guess this doesn't fit the spec, but it never happens...
+    }
+
+    /**
+     * Determine whether or not SELinux policies are currently being enforced
+     * by the current admin.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * <p>The returned value is only meaningful if the current admin is a
+     * SELinux admin.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     */
+    public boolean getSELinuxEnforcing(ComponentName admin) {
+        return getSELinuxEnforcing(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean getSELinuxEnforcing(ComponentName admin, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getSELinuxEnforcing(admin, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get a list of the SELinux booleans available on the system.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * <p>The returned value is only meaningful if the current admin is a
+     * SELinux admin.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     */
+    public List<String> getSELinuxBooleanNames(ComponentName admin) {
+        return getSELinuxBooleanNames(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public List<String> getSELinuxBooleanNames(ComponentName admin, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getSELinuxBooleanNames(admin, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get the value of a SELinux boolean.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * <p>The returned value is only meaningful if the current admin is a
+     * SELinux admin.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param name the name of the SELinux boolean
+     * @return the value of the SELinux boolean
+     */
+    public boolean getSELinuxBooleanValue(ComponentName admin, String name) {
+        return getSELinuxBooleanValue(admin, name, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean getSELinuxBooleanValue(ComponentName admin, String name, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getSELinuxBooleanValue(admin, name, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Set the value of a SELinux boolean.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * <p>The returned value is only meaningful if the current admin is a
+     * SELinux admin.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param name the name of the SELinux boolean
+     * @param value the desired value for the boolean
+     * @return false if Android was unable to set the desired mode
+     */
+    public boolean setSELinuxBooleanValue(ComponentName admin, String name,
+            boolean value) {
+        return setSELinuxBooleanValue(admin, name, value, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean setSELinuxBooleanValue(ComponentName admin, String name,
+            boolean value, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.setSELinuxBooleanValue(admin, name, value, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether an admin app has control over SE Android MMAC policy.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_MMAC} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated,
+     * must be self
+     * @return true if admin app can control MMAC policy, false otherwise
+     */
+    public boolean isMMACadmin(ComponentName admin) {
+        return isMMACadmin(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean isMMACadmin(ComponentName admin, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.isMMACadmin(admin, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by an application that is administering the device to start or stop
+     * controlling SE Android MMAC policies, enforcement, etc. When an admin
+     * app gives up control of MMAC policies, the policy in place prior to the app
+     * taking control will be applied.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_MMAC} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * <p>When an application gains control of MMAC settings, it is called an
+     * MMAC administrator. Admistration applications will call this with true and
+     * ensure this method returned true before attempting to toggle MMAC settings.
+     * When apps intend to stop controlling MMAC settings, apps should call this
+     * with false.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated,
+     * must be self
+     * @param control true if the admin wishes to control MMAC, false if the admin
+     * wishes to give back control of MMAC
+     * @return true if the operation succeeded, false if the operation failed or
+     * MMAC was not enabled on the device.
+     */
+    public boolean setMMACadmin(ComponentName admin, boolean control) {
+        return setMMACadmin(admin, control, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean setMMACadmin(ComponentName admin, boolean control, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.setMMACadmin(admin, control, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by an application that is a SEAndroid MMAC admin to set MMAC
+     * protections into enforcing or permissive mode. The system requires a
+     * reboot for the protections to take effect.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_MMAC} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param enforcing true for enforcing mode, false for permissive mode.
+     * @return false if Android was unable to set the desired mode
+     */
+    public boolean setMMACenforcing(ComponentName admin, boolean enforcing) {
+        return setMMACenforcing(admin, enforcing, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean setMMACenforcing(ComponentName admin, boolean enforcing, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.setMMACenforcing(admin, enforcing, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determine whether SE Android MMAC policies are being enforced by the
+     * current admin.
+     *
+     * <p>The calling device admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_MMAC} to be able to call
+     * this method; if it has not, a security exception will be thrown.
+     *
+     * <p>The returned value is only meaningful if the current admin is a
+     * MMAC admin.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     */
+    public boolean getMMACenforcing(ComponentName admin) {
+        return getMMACenforcing(admin, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean getMMACenforcing(ComponentName admin, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getMMACenforcing(admin, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    // Before changing these values, be sure to update
+    // DevicePolicyManagerService.java's POLICY_DESCRIPTIONS array.
+    public static final int SEPOLICY_FILE_SEPOLICY = 0;
+    public static final int SEPOLICY_FILE_PROPCTXS = 1;
+    public static final int SEPOLICY_FILE_FILECTXS = 2;
+    public static final int SEPOLICY_FILE_SEAPPCTXS = 3;
+    public static final int MMAC_POLICY_FILE = 4;
+    public static final int SEPOLICY_FILE_COUNT = MMAC_POLICY_FILE+1;
+
+    /**
+     * Sets a new policy file and reloads it at the proper time.
+     *
+     * <p>For {@link #SEPOLICY_FILE_SEPOLICY}, {@link #SEPOLICY_FILE_PROPCTXS},
+     * {@link #SEPOLICY_FILE_FILECTXS}, and {@link #SEPOLICY_FILE_SEAPPCTXS}, the admin
+     * must have requested {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX}
+     * before calling this method. If it has not, a security exception will be
+     * thrown.
+     *
+     * <p>For {@link #SEPOLICY_FILE_SEPOLICY}, {@link #SEPOLICY_FILE_PROPCTXS},
+     * {@link #SEPOLICY_FILE_FILECTXS}, and {@link #SEPOLICY_FILE_SEAPPCTXS}, these
+     * files are reloaded before returning from the DevicePolicyManager.
+     *
+     * <p>For {@link #SEPOLICY_FILE_SEPOLICY}, {@link #SEPOLICY_FILE_PROPCTXS},
+     * {@link #SEPOLICY_FILE_FILECTXS}, and {@link #SEPOLICY_FILE_SEAPPCTXS}, the
+     * returned value is only meaingful if the current admin is a SELinux
+     * admin.
+     *
+     * <p>For {@link #MMAC_POLICY_FILE}, the admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_MMAC} before calling this
+     * method. If it has not, a security exception will be thrown.
+     *
+     * <p>For {@link #MMAC_POLICY_FILE}, the MMAC policy file is reloaded on
+     * reboot.
+     *
+     * <p>For {@link #MMAC_POLICY_FILE}, the returned value is only meaingful
+     * if the current admin is a MMAC admin.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with
+     * @param policyType one of {@link #SEPOLICY_FILE_SEPOLICY}, {@link #SEPOLICY_FILE_PROPCTXS},
+     * {@link #SEPOLICY_FILE_FILECTXS}, {@link #SEPOLICY_FILE_SEAPPCTXS},
+     * or {@link #MMAC_POLICY_FILE}.
+     * @param policy the new policy file in bytes, or null if you wish to revert to
+     * the default policy
+     * @return false if Android was unable to set the new policy
+     */
+    public boolean setCustomPolicyFile(ComponentName admin, int policyType, byte[] policy) {
+        return setCustomPolicyFile(admin, policyType, policy, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean setCustomPolicyFile(ComponentName admin, int policyType, byte[] policy, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.setCustomPolicyFile(admin, policyType, policy, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determine whether this admin set a custom policy file.
+     *
+     * <p>For {@link #SEPOLICY_FILE_SEPOLICY}, {@link #SEPOLICY_FILE_PROPCTXS},
+     * {@link #SEPOLICY_FILE_FILECTXS}, and {@link #SEPOLICY_FILE_SEAPPCTXS}, the admin
+     * must have requested {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX}
+     * before calling this method. If it has not, a security exception will be
+     * thrown.
+     *
+     * <p>For {@link #SEPOLICY_FILE_SEPOLICY}, {@link #SEPOLICY_FILE_PROPCTXS},
+     * {@link #SEPOLICY_FILE_FILECTXS}, and {@link #SEPOLICY_FILE_SEAPPCTXS}, the
+     * returned value is only meaingful if the current admin is a SELinux
+     * admin.
+     *
+     * <p>For {@link #MMAC_POLICY_FILE}, the admin must have requested
+     * {@link DeviceAdminInfo#USES_POLICY_ENFORCE_MMAC} before calling this
+     * method. If it has not, a security exception will be thrown.
+     *
+     * <p>For {@link #MMAC_POLICY_FILE}, the returned value is only meaingful
+     * if the current admin is a MMAC admin.
+     *
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with
+     * @param policyType one of {@link #SEPOLICY_FILE_SEPOLICY}, {@link #SEPOLICY_FILE_PROPCTXS},
+     * {@link #SEPOLICY_FILE_FILECTXS}, {@link #SEPOLICY_FILE_SEAPPCTXS}, or
+     * {@link #MMAC_POLICY_FILE}
+     * @return true if the admin set a custom policy file
+     */
+    public boolean isCustomPolicyFile(ComponentName admin, int policyType) {
+        return isCustomPolicyFile(admin, policyType, UserHandle.myUserId());
+    }
+
+    /** @hide per-user version */
+    public boolean isCustomPolicyFile(ComponentName admin, int policyType, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.isCustomPolicyFile(admin, policyType, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy server", e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * @hide
      */
     public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) {

core/java/android/app/admin/IDevicePolicyManager.aidl

     void removeActiveAdmin(in ComponentName policyReceiver, int userHandle);
     boolean hasGrantedPolicy(in ComponentName policyReceiver, int usesPolicy, int userHandle);
 
+    boolean setSELinuxAdmin(in ComponentName who, boolean control, int userHandle);
+    boolean isSELinuxAdmin(in ComponentName who, int userHandle);
+
+    boolean setSELinuxEnforcing(in ComponentName who, boolean enforcing, int userHandle);
+    boolean getSELinuxEnforcing(in ComponentName who, int userHandle);
+
+    List<String> getSELinuxBooleanNames(in ComponentName who, int userHandle);
+    boolean getSELinuxBooleanValue(in ComponentName who, String name, int userHandle);
+    boolean setSELinuxBooleanValue(in ComponentName who, String name, boolean value, int userHandle);
+
+    boolean isMMACadmin(in ComponentName who, int userHandle);
+    boolean setMMACadmin(in ComponentName who, boolean control, int userHandle);
+
+    boolean setMMACenforcing(in ComponentName who, boolean enforcing, int userHandle);
+    boolean getMMACenforcing(in ComponentName who, int userHandle);
+
+    boolean setCustomPolicyFile(in ComponentName who, int policyType, in byte[] policy, int userHandle);
+    boolean isCustomPolicyFile(in ComponentName who, int policyType, int userHandle);
+
     void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase,
         int numbers, int symbols, int nonletter, int userHandle);
     void reportFailedPasswordAttempt(int userHandle);

core/res/res/values/strings.xml

     <string name="policylab_disableKeyguardFeatures">Disable features in keyguard</string>
     <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
     <string name="policydesc_disableKeyguardFeatures">Prevent use of some features in keyguard.</string>
+    <!-- Title of policy access to start enforcing SELinux policy [CHAR LIMIT=30]-->
+    <string name="policylab_enforceSelinux">Enforce SELinux</string>
+    <!-- Description of policy access to start enforcing SELinux policy [CHAR LIMIT=110]-->
+    <string name="policydesc_enforceSelinux">Toggle SELinux policy enforcing or permissive mode.</string>
+    <!-- Title of policy access to start enforcing MMAC policy [CHAR LIMIT=30]-->
+    <string name="policylab_enforceMmac">Enforce MMAC</string>
+    <!-- Description of policy access to start enforcing MMAC policy [CHAR LIMIT=110]-->
+    <string name="policydesc_enforceMmac">Toggle MMAC policy enforcing or permissive mode.</string>
 
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->

core/res/res/values/symbols.xml

   <java-symbol type="string" name="media_route_status_available" />
   <java-symbol type="string" name="media_route_status_not_available" />
   <java-symbol type="string" name="owner_name" />
+  <java-symbol type="string" name="policylab_enforceSelinux" />
+  <java-symbol type="string" name="policydesc_enforceSelinux" />
+  <java-symbol type="string" name="policylab_enforceMmac" />
+  <java-symbol type="string" name="policydesc_enforceMmac" />
   <java-symbol type="string" name="config_chooseAccountActivity" />
   <java-symbol type="string" name="config_chooseTypeAndAccountActivity" />
   <java-symbol type="string" name="config_appsAuthorizedForSharedAccounts" />

services/java/com/android/server/DevicePolicyManagerService.java

 import android.os.RecoverySystem;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import java.io.PrintWriter;
 import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
         public DevicePolicyData(int userHandle) {
             mUserHandle = userHandle;
         }
+
+        /** Return the Admin that controls SELinux, or null if there is none. */
+        ActiveAdmin findSELinuxAdminLocked() {
+            final int N = mAdminList.size();
+            for (int i = 0; i < N; ++i) {
+                ActiveAdmin ap = mAdminList.get(i);
+                if (ap.isSELinuxAdmin) {
+                    // Device admin controls SELinux
+                    return ap;
+                }
+            }
+            // No device admin controls SELinux
+            return null;
+        }
+
+        /** Return the admin that controls SE Android MMAC, or null if there is none. */
+        ActiveAdmin findMMACadminLocked() {
+            //Uses very similar code to the SELinux version
+            final int N = mAdminList.size();
+            for (int i = 0; i < N; ++i) {
+                ActiveAdmin ap = mAdminList.get(i);
+                if (ap.isMMACadmin) {
+                    return ap;
+                }
+            }
+            return null;
+        }
     }
 
     final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
 
     Handler mHandler = new Handler();
 
+    Map<String, Boolean> seboolsOrig = null;
+
     BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
         }
     };
 
+    private static abstract class PolicyFileDescription {
+        /** Path to the policy file */
+        final String path;
+
+        /** Admin has to be allowed to use this policy type before calling
+         * these functions. Typically {@link DeviceAdminInfo#USES_POLICY_ENFORCE_SELINUX} */
+        final int reqPolicy;
+
+        PolicyFileDescription(String _path, int _reqPolicy) {
+            path = _path;
+            reqPolicy = _reqPolicy;
+        }
+
+        /** Does this admin have exclusive control of the policy */
+        abstract boolean isPolicyAdmin(ActiveAdmin admin);
+
+        /** Called after policy is written to the file system */
+        abstract boolean doPolicyReload();
+    }
+
+    private static class SELinuxPolicyDescription extends PolicyFileDescription {
+        SELinuxPolicyDescription(String path) {
+            super(path, DeviceAdminInfo.USES_POLICY_ENFORCE_SELINUX);
+        }
+
+        @Override
+        boolean isPolicyAdmin(ActiveAdmin admin) {
+            return admin.isSELinuxAdmin;
+        }
+
+        @Override
+        boolean doPolicyReload() {
+            SystemProperties.set("selinux.reload_policy", "1");
+            return true;
+        }
+    }
+
+    private static class MMACpolicyDescription extends PolicyFileDescription {
+        MMACpolicyDescription(String path) {
+            super(path, DeviceAdminInfo.USES_POLICY_ENFORCE_MMAC);
+        }
+
+        @Override
+        boolean isPolicyAdmin(ActiveAdmin admin) {
+            return admin.isMMACadmin;
+        }
+
+        @Override
+        boolean doPolicyReload() {
+            //policy is reloaded on reboot
+            return true;
+        }
+    }
+
+    private static final String MMAC_ENFORCE_PROPERTY = "persist.mmac.enforce";
+
+    private static final String SEPOLICY_PATH_SEPOLICY = "/data/security/sepolicy";
+
+    private static final String SEPOLICY_PATH_PROPCTXS = "/data/security/property_contexts";
+
+    private static final String SEPOLICY_PATH_FILECTXS = "/data/security/file_contexts";
+
+    private static final String SEPOLICY_PATH_SEAPPCTXS = "/data/security/seapp_contexts";
+
+    private static final String MMAC_POLICY_PATH = "/data/security/mac_permissions.xml";
+
+    private static final PolicyFileDescription[] POLICY_DESCRIPTIONS = {
+        // 0 = SEPOLICY_FILE_SEPOLICY
+        new SELinuxPolicyDescription(SEPOLICY_PATH_SEPOLICY),
+        // 1 = SEPOLICY_FILE_PROPCTXS
+        new SELinuxPolicyDescription(SEPOLICY_PATH_PROPCTXS),
+        // 2 = SEPOLICY_FILE_FILECTXS
+        new SELinuxPolicyDescription(SEPOLICY_PATH_FILECTXS),
+        // 3 = SEPOLICY_FILE_SEAPPCTXS
+        new SELinuxPolicyDescription(SEPOLICY_PATH_SEAPPCTXS),
+        // 4 = MMAC_POLICY_FILE
+        new MMACpolicyDescription(MMAC_POLICY_PATH),
+    };
+
     static class ActiveAdmin {
         final DeviceAdminInfo info;
 
         String globalProxySpec = null;
         String globalProxyExclusionList = null;
 
+        boolean isSELinuxAdmin = false;
+        boolean enforceSELinux = false;
+        Map<String, Boolean> sebools = null;
+
+        boolean isMMACadmin = false;
+        boolean enforceMMAC = false;
+
+        boolean[] isCustomPolicyFile = new boolean[DevicePolicyManager.SEPOLICY_FILE_COUNT];
+
         ActiveAdmin(DeviceAdminInfo _info) {
             info = _info;
+            if (info != null && getUserHandle().getIdentifier() == UserHandle.USER_OWNER) {
+                for (int i = 0; i < isCustomPolicyFile.length; ++i) {
+                    isCustomPolicyFile[i] = false;
+                }
+            } else {
+                isCustomPolicyFile = null;
+            }
         }
 
         int getUid() { return info.getActivityInfo().applicationInfo.uid; }
                 out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
                 out.endTag(null, "disable-keyguard-features");
             }
+            if (isSELinuxAdmin) {
+                out.startTag(null, "selinux-admin");
+                out.attribute(null, "value", Boolean.toString(isSELinuxAdmin));
+                out.endTag(null, "selinux-admin");
+                if (enforceSELinux) {
+                    out.startTag(null, "enforce-selinux");
+                    out.attribute(null, "value", Boolean.toString(enforceSELinux));
+                    out.endTag(null, "enforce-selinux");
+                }
+                Set<String> bools = sebools.keySet();
+                for (String s : bools) {
+                    out.startTag(null, "selinux-boolean");
+                    out.attribute(null, "name", s);
+                    out.attribute(null, "value", sebools.get(s).toString());
+                    out.endTag(null, "selinux-boolean");
+                }
+                boolean isCustomSELinux = isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEPOLICY];
+                if (isCustomSELinux) {
+                    out.startTag(null, "selinux-sepolicy");
+                    out.attribute(null, "value", Boolean.toString(isCustomSELinux));
+                    out.endTag(null, "selinux-sepolicy");
+                }
+                boolean isCustomPropCtxs = isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_PROPCTXS];
+                if (isCustomPropCtxs) {
+                    out.startTag(null, "selinux-propctxs");
+                    out.attribute(null, "value", Boolean.toString(isCustomPropCtxs));
+                    out.endTag(null, "selinux-propctxs");
+                }
+                boolean isCustomFileCtxs = isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_FILECTXS];
+                if (isCustomFileCtxs) {
+                    out.startTag(null, "selinux-filectxs");
+                    out.attribute(null, "value", Boolean.toString(isCustomFileCtxs));
+                    out.endTag(null, "selinux-filectxs");
+                }
+                boolean isCustomSEAppCtxs = isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEAPPCTXS];
+                if (isCustomSEAppCtxs) {
+                    out.startTag(null, "selinux-seappctxs");
+                    out.attribute(null, "value", Boolean.toString(isCustomSEAppCtxs));
+                    out.endTag(null, "selinux-seappctxs");
+                }
+            }
+            if (isMMACadmin) {
+                out.startTag(null, "mmac-admin");
+                out.attribute(null, "value", Boolean.toString(isMMACadmin));
+                out.endTag(null, "mmac-admin");
+                if (enforceMMAC) {
+                    out.startTag(null, "enforce-mmac");
+                    out.attribute(null, "value", Boolean.toString(enforceMMAC));
+                    out.endTag(null, "enforce-mmac");
+                }
+                boolean isCustomMMAC = isCustomPolicyFile[DevicePolicyManager.MMAC_POLICY_FILE];
+                if (isCustomMMAC) {
+                    out.startTag(null, "mmac-macperms");
+                    out.attribute(null, "value", Boolean.toString(isCustomMMAC));
+                    out.endTag(null, "mmac-macperms");
+                }
+            }
         }
 
         void readFromXml(XmlPullParser parser)
                 } else if ("disable-keyguard-features".equals(tag)) {
                     disabledKeyguardFeatures = Integer.parseInt(
                             parser.getAttributeValue(null, "value"));
+                } else if ("selinux-admin".equals(tag)) {
+                    isSELinuxAdmin = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, "value"));
+                    if (isSELinuxAdmin) {
+                        sebools = new HashMap<String, Boolean>();
+                    }
+                } else if ("enforce-selinux".equals(tag)) {
+                    enforceSELinux = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, "value"));
+                } else if ("selinux-boolean".equals(tag)) {
+                    sebools.put(
+                            parser.getAttributeValue(null, "name"),
+                            Boolean.parseBoolean(
+                                    parser.getAttributeValue(null, "value")));
+                } else if ("selinux-sepolicy".equals(tag)) {
+                    this.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEPOLICY] =
+                            Boolean.parseBoolean(parser.getAttributeValue(null, "value"));
+                } else if ("selinux-propctxs".equals(tag)) {
+                    this.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_PROPCTXS] =
+                            Boolean.parseBoolean(parser.getAttributeValue(null, "value"));
+                } else if ("selinux-filectxs".equals(tag)) {
+                    this.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_FILECTXS] =
+                            Boolean.parseBoolean(parser.getAttributeValue(null, "value"));
+                } else if ("selinux-seappctxs".equals(tag)) {
+                    this.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEAPPCTXS] =
+                            Boolean.parseBoolean(parser.getAttributeValue(null, "value"));
+                } else if ("mmac-admin".equals(tag)) {
+                    isMMACadmin = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, "value"));
+                } else if ("enforce-mmac".equals(tag)) {
+                    enforceMMAC = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, "value"));
+                } else if ("mmac-macperms".equals(tag)) {
+                    this.isCustomPolicyFile[DevicePolicyManager.MMAC_POLICY_FILE] =
+                            Boolean.parseBoolean(parser.getAttributeValue(null, "value"));
                 } else {
                     Slog.w(TAG, "Unknown admin tag: " + tag);
                 }
                     pw.println(disableCamera);
             pw.print(prefix); pw.print("disabledKeyguardFeatures=");
                     pw.println(disabledKeyguardFeatures);
+            pw.print(prefix); pw.print("isSELinuxAdmin=");
+                    pw.println(isSELinuxAdmin);
+            pw.print(prefix); pw.print("enforceSELinux=");
+                    pw.println(enforceSELinux);
+            pw.print(prefix); pw.print("sebools=");
+                    pw.println(sebools);
+            pw.print(prefix); pw.print("customSELinuxPolicy=");
+                    pw.println(isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEPOLICY]);
+            pw.print(prefix); pw.print("customPropertyContexts=");
+                    pw.println(isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_PROPCTXS]);
+            pw.print(prefix); pw.print("customFileContexts=");
+                    pw.println(isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_FILECTXS]);
+            pw.print(prefix); pw.print("customSEappContexts=");
+                    pw.println(isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEAPPCTXS]);
+            pw.print(prefix); pw.print("isMMACadmin=");
+                    pw.println(isMMACadmin);
+            pw.print(prefix); pw.print("enforceMMAC=");
+                    pw.println(enforceMMAC);
+            pw.print(prefix); pw.print("customMMACpolicy=");
+                    pw.println(isCustomPolicyFile[DevicePolicyManager.MMAC_POLICY_FILE]);
+
         }
     }
 
                                 DevicePolicyData policy = getUserData(userHandle);
                                 boolean doProxyCleanup = admin.info.usesPolicy(
                                         DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
+                                boolean doSELinuxCleanup = admin.isSELinuxAdmin;
+                                boolean doMMACcleanup = admin.isMMACadmin;
                                 policy.mAdminList.remove(admin);
                                 policy.mAdminMap.remove(adminReceiver);
                                 validatePasswordOwnerLocked(policy);
                                 if (doProxyCleanup) {
                                     resetGlobalProxyLocked(getUserData(userHandle));
                                 }
+                                if (doSELinuxCleanup) {
+                                    syncSELinuxPolicyLocked(policy,
+                                            admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEPOLICY],
+                                            admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_PROPCTXS],
+                                            admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_FILECTXS],
+                                            admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEAPPCTXS]);
+                                }
+                                if (doMMACcleanup) {
+                                    syncMMACpolicyLocked(policy, admin.isCustomPolicyFile[DevicePolicyManager.MMAC_POLICY_FILE]);
+                                }
                                 saveSettingsLocked(userHandle);
                                 updateMaximumTimeToLockLocked(policy);
                             }
         validatePasswordOwnerLocked(policy);
         syncDeviceCapabilitiesLocked(policy);
         updateMaximumTimeToLockLocked(policy);
+        syncSELinuxPolicyLocked(policy, false, true);
+        syncMMACpolicyLocked(policy, false, true);
     }
 
     static void validateQualityConstant(int quality) {
     }
 
     public void systemReady() {
+        assert DevicePolicyManager.SEPOLICY_FILE_COUNT == POLICY_DESCRIPTIONS.length;
         synchronized (this) {
+            saveOriginalSELinuxSettings();
             loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
             loadDeviceOwner();
         }
      */
     public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
         enforceCrossUserPermission(userHandle);
+
         synchronized (this) {
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
             }
+
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
             if (ap.disabledKeyguardFeatures != which) {
         }
     }
 
+    private void saveOriginalSELinuxSettings() {
+        // SELinux booleans
+        String[] seboolNames = SELinux.getBooleanNames();
+        seboolsOrig = new HashMap<String, Boolean>(seboolNames.length);
+        for (String sebool : seboolNames) {
+            boolean value = SELinux.getBooleanValue(sebool);
+            seboolsOrig.put(sebool, value);
+        }
+        seboolsOrig = Collections.unmodifiableMap(seboolsOrig);
+    }
+
+    // Possible SELinux Admin API states:
+    //  1: Caller has ENFORCE_SELINUX = {T,F}
+    //  2: Caller is a SELinux admin = {T,F}
+    //  3: There is a SELinux admin on the system = {T,F}
+    // Invariants:
+    //  a) 1=F -> 2=F
+    //  b) 3=F -> 2=F for all admin apps
+    // States:
+    //  TTT, TTF, TFT, TFF, FTT, FTF, FFT, FFF
+    //  TTT,      TFT, TFF,           FFT, FFF
+    //       TTF fails b,
+    //                      FTT fails a
+    //                           FTF fails a,b
+
+    /** Resets the state the SELinux values in an ActiveAdmin to the current state of system */
+    private static void resetSELinuxAdmin(ActiveAdmin admin) {
+        String[] seboolsnames = SELinux.getBooleanNames();
+        admin.enforceSELinux = SELinux.isSELinuxEnforced();
+        admin.sebools = new HashMap<String, Boolean>(seboolsnames.length);
+        for (String bool : seboolsnames) {
+            admin.sebools.put(bool, SELinux.getBooleanValue(bool));
+        }
+    }
+
+    private boolean syncSELinuxPolicyLocked(DevicePolicyData policy, boolean removeAllPolicy) {
+        return syncSELinuxPolicyLocked(policy, removeAllPolicy, removeAllPolicy,
+                                       removeAllPolicy, removeAllPolicy);
+    }
+
+    private boolean syncSELinuxPolicyLocked(DevicePolicyData policy, boolean removeSELinuxPolicy,
+                                            boolean removePropertyContexts,
+                                            boolean removeFileContexts, boolean removeSEappContexts) {
+        return syncSELinuxPolicyLocked(policy, removeSELinuxPolicy, removePropertyContexts,
+                                       removeFileContexts, removeSEappContexts, false);
+    }
+
+    private boolean syncSELinuxPolicyLocked(DevicePolicyData policy, boolean removeAllPolicy, boolean firstBoot) {
+            return syncSELinuxPolicyLocked(policy, removeAllPolicy, removeAllPolicy,
+                                           removeAllPolicy, removeAllPolicy, firstBoot);
+    }
+
+    /**
+     * Sync's the current SELinux admin's policies to the device. If there is
+     * no SELinux admin, then this will set SELinux to permissive mode,
+     * restore the SELinux boolean values from when the system booted,
+     * and may remove the {@link SELINUX_POLICY_PATH},
+     * {@link PROPERTY_CONTEXTS_PATH}, {@link FILE_CONTEXTS_PATH}, and
+     * {@link SEAPP_CONTEXTS_PATH} files.
+     * @return true if policies were synced successfully
+     */
+    private boolean syncSELinuxPolicyLocked(DevicePolicyData policy,
+            boolean removeSELinuxPolicy, boolean removePropertyContexts,
+            boolean removeFileContexts, boolean removeSEappContexts,
+            boolean firstBoot) {
+        if (!SELinux.isSELinuxEnabled() || policy.mUserHandle != UserHandle.USER_OWNER) {
+            return false;
+        }
+
+        ActiveAdmin selinuxAdmin = policy.findSELinuxAdminLocked();
+        if (selinuxAdmin == null) {
+            return false;
+        }
+
+        boolean systemState = SELinux.isSELinuxEnforced();
+        boolean desiredState = selinuxAdmin.enforceSELinux;
+        if (!firstBoot || !systemState) {
+            if (systemState != desiredState) {
+                Slog.v(TAG, "SELinux enforcing was " + systemState + ", to be set to " + desiredState);
+                boolean res = SELinux.setSELinuxEnforce(desiredState);
+                Slog.v(TAG, "Change in SELinux enforcing state " + (res ? "succeeded" : "failed"));
+                if (res == false) {
+                    // this really shouldn't ever happen
+                    resetSELinuxAdmin(selinuxAdmin);
+                    return false;
+                }
+            }
+        }
+
+        Set<String> sebools = selinuxAdmin.sebools.keySet();
+        for (String sebool : sebools) {
+            systemState = SELinux.getBooleanValue(sebool);
+            desiredState = selinuxAdmin.sebools.get(sebool);
+            if (systemState != desiredState) {
+                Slog.v(TAG, "SELinux boolean [" + sebool + "] : " + systemState + " -> " + desiredState);
+                boolean res = SELinux.setBooleanValue(sebool, desiredState);
+                Slog.v(TAG, "SELinux boolean " + sebool + " " + (res ? "succeeded" : "failed"));
+                if (res == false) {
+                    // this really shouldn't ever happen
+                    resetSELinuxAdmin(selinuxAdmin);
+                    return false;
+                }
+            }
+        }
+
+        boolean ret = true;
+        if (removeSELinuxPolicy || removePropertyContexts
+            || removeFileContexts || removeSEappContexts) {
+            File polfile;
+            polfile = new File(SEPOLICY_PATH_SEPOLICY);
+            if (removeSELinuxPolicy && polfile.exists() && !polfile.delete()) {
+                ret = false;
+            }
+            polfile = new File(SEPOLICY_PATH_PROPCTXS);
+            if (removePropertyContexts && polfile.exists() && !polfile.delete()) {
+                ret = false;
+            }
+            polfile = new File(SEPOLICY_PATH_FILECTXS);
+            if (removeFileContexts && polfile.exists() && !polfile.delete()) {
+                ret = false;
+            }
+            polfile = new File(SEPOLICY_PATH_SEAPPCTXS);
+            if (removeSEappContexts && polfile.exists() && !polfile.delete()) {
+                ret = false;
+            }
+            SystemProperties.set("selinux.reload_policy", "1");
+        }
+        return ret;
+    }
+
+    // Cases = 8
+    @Override
+    public boolean isSELinuxAdmin(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set SELinux settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set SELinux settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            //Case F** = 4
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_SELINUX);
+            //Case T** = 4
+            return admin.isSELinuxAdmin;
+        }
+    }
+
+    // Cases = 16
+    @Override
+    public boolean setSELinuxAdmin(ComponentName who, boolean control, int userHandle) {
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set SELinux settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set SELinux settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            // Case F**(*) = 8
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_SELINUX);
+
+            // Case TT*(T) = 2
+            // Case TF*(F) = 2
+            if (admin.isSELinuxAdmin == control) {
+                return true;
+            }
+
+            DevicePolicyData policy = getUserData(userHandle);
+            ActiveAdmin curAdmin = policy.findSELinuxAdminLocked();
+
+            // Case TFF(T) = 1
+            if (control && curAdmin == null) {
+                Slog.v(TAG, "SELinux admin set to " + admin.info.getComponent());
+                admin.isSELinuxAdmin = true;
+
+                admin.sebools = new HashMap<String, Boolean>(seboolsOrig.size());
+                Set<String> seboolnames = seboolsOrig.keySet();
+                for (String sebool : seboolnames) {
+                    boolean value = seboolsOrig.get(sebool);
+                    admin.sebools.put(sebool, value);
+                }
+
+                saveSettingsLocked(userHandle);
+                return true;
+            }
+
+            // Case TTT(F) = 1
+            if (!control && curAdmin.equals(admin)) {
+                boolean setSEpolicyFile = admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEPOLICY];
+                boolean setPropertyContextsFile = admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_PROPCTXS];
+                boolean setFileContextsFile = admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_FILECTXS];
+                boolean setSEappContextsFile = admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEAPPCTXS];
+
+                Slog.v(TAG, admin.info.getComponent() + " is no longer a SELinux admin");
+
+                admin.isSELinuxAdmin = false;
+                admin.enforceSELinux = false;
+                admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEPOLICY] = false;
+                admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_PROPCTXS] = false;
+                admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_FILECTXS] = false;
+                admin.isCustomPolicyFile[DevicePolicyManager.SEPOLICY_FILE_SEAPPCTXS] = false;
+
+                saveSettingsLocked(userHandle);
+                syncSELinuxPolicyLocked(policy, setSEpolicyFile,
+                        setPropertyContextsFile, setFileContextsFile,
+                        setSEappContextsFile);
+                return true;
+            }
+
+            //Case TTF(F) = 1
+            //Case TFT(T) = 1
+            return false;
+        }
+    }
+
+    @Override
+    public boolean getSELinuxEnforcing(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set SELinux settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set SELinux settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            // Case: F** = 4
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_SELINUX);
+            // Case: T** = 4
+            return admin.isSELinuxAdmin && admin.enforceSELinux;
+        }
+    }
+
+    @Override
+    public boolean setSELinuxEnforcing(ComponentName who, boolean enforcing, int userHandle) {
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set SELinux settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set SELinux settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            // Case F**(*) = 8
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_SELINUX);
+
+            // Case TF*(*) = 4
+            if (!admin.isSELinuxAdmin) {
+                return false;
+            }
+
+            // Case TT*(*) = 4
+            if (admin.enforceSELinux != enforcing) {
+                admin.enforceSELinux = enforcing;
+                saveSettingsLocked(userHandle);
+            }
+            DevicePolicyData policy = getUserData(userHandle);
+            return syncSELinuxPolicyLocked(policy, false);
+        }
+    }
+
+    @Override
+    public List<String> getSELinuxBooleanNames(ComponentName who, int userHandle) {
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set SELinux settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set SELinux settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return null;
+            }
+            // Case F** = 4
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_SELINUX);
+
+            // Case TF* = 2
+            if (!admin.isSELinuxAdmin) {
+                return null;
+            }
+
+            // Case TT* = 2
+            return new ArrayList<String>(admin.sebools.keySet());
+        }
+    }
+
+    @Override
+    public boolean getSELinuxBooleanValue(ComponentName who, String name, int userHandle) {
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set SELinux settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set SELinux settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            // Case F** = 4
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_SELINUX);
+
+            // Case TF* = 2
+            if (!admin.isSELinuxAdmin) {
+                return false;
+            }
+
+            // Case TT* = 2
+            return admin.sebools.containsKey(name) && admin.sebools.get(name);
+        }
+    }
+
+    @Override
+    public boolean setSELinuxBooleanValue(ComponentName who, String name, boolean value,
+            int userHandle) {
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set SELinux settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set SELinux settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_SELINUX);
+
+            if (!admin.isSELinuxAdmin) {
+                return false;
+            }
+
+            if (!admin.sebools.containsKey(name)) {
+                throw new IllegalArgumentException(name + " is not a valid SELinux boolean");
+            }
+
+            if (value != admin.sebools.put(name, value)) {
+                saveSettingsLocked(userHandle);
+            }
+            DevicePolicyData policy = getUserData(userHandle);
+            return syncSELinuxPolicyLocked(policy, false);
+        }
+    }
+
+    // Possible MMAC Admin API states:
+    //  1: Caller has ENFORCE_MMAC = {T,F}
+    //  2: Caller is a MMAC admin = {T,F}
+    //  3: There is a MMAC admin on the system = {T,F}
+    // Invariants:
+    //  a) 1=F -> 2=F
+    //  b) 3=F -> 2=F for all admin apps
+    // States:
+    //  TTT, TTF, TFT, TFF, FTT, FTF, FFT, FFF
+    //  TTT,      TFT, TFF,           FFT, FFF
+    //       TTF fails b,
+    //                      FTT fails a
+    //                           FTF fails a,b
+
+    private boolean syncMMACpolicyLocked(DevicePolicyData policy, boolean removePolicy) {
+        return syncMMACpolicyLocked(policy, removePolicy, false);
+    }
+
+    /**
+     * Sync's the current MMAC admin's policies to the device. If there is
+     * no MMAC admin, then this will set MMAC to permissive mode
+     * and may remove the {@link MMAC_POLICY_PATH} file.
+     * @return true if policies were synced successfully
+     */
+    private boolean syncMMACpolicyLocked(DevicePolicyData policy, boolean removePolicy,
+                                         boolean firstBoot) {
+        if (policy.mUserHandle != UserHandle.USER_OWNER) {
+            return false;
+        }
+
+        ActiveAdmin mmacAdmin = policy.findMMACadminLocked();
+        if (mmacAdmin == null) {
+            return false;
+        }
+
+        boolean systemState = SystemProperties.getBoolean(MMAC_ENFORCE_PROPERTY, false);
+        boolean enforceMMAC = mmacAdmin.enforceMMAC;
+        if (!firstBoot || !systemState) {
+            if (systemState != enforceMMAC) {
+                Slog.v(TAG, "Changed MMAC enforcing status " + systemState + " to " + enforceMMAC);
+                SystemProperties.set(MMAC_ENFORCE_PROPERTY, enforceMMAC ? "true" : "false");
+            }
+        }
+
+        boolean ret = true;
+        if (removePolicy) {
+            File polFile;
+            polFile = new File(MMAC_POLICY_PATH);
+            if (polFile.exists() && !polFile.delete()) {
+                ret = false;
+            }
+        }
+        return ret;
+    }
+
+    // Cases = 8
+    @Override
+    public boolean isMMACadmin(ComponentName who, int userHandle) {
+        //Uses very similar code to the SELinux version
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set MMAC settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set MMAC settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            // Case F** = 4
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_MMAC);
+            // Case T** = 4
+            return admin.isMMACadmin;
+        }
+    }
+
+    // Cases = 16
+    @Override
+    public boolean setMMACadmin(ComponentName who, boolean control, int userHandle) {
+        //Uses very similar code to the SELinux version
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set MMAC settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set MMAC settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            // Case F**(*) = 8
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_MMAC);
+
+            // Case TT*(T) = 2
+            // Case TF*(F) = 2
+            if (admin.isMMACadmin == control) {
+                return true;
+            }
+
+            DevicePolicyData policy = getUserData(userHandle);
+            ActiveAdmin curAdmin = policy.findMMACadminLocked();
+
+            // Case TFF(T) = 1
+            if (control && curAdmin == null) {
+                Slog.v(TAG, "SE Android MMAC admin set to " + admin.info.getComponent());
+                admin.isMMACadmin = true;
+                saveSettingsLocked(userHandle);
+                return true;
+            }
+
+            // Case TTT(F) = 1
+            if (!control && curAdmin.equals(admin)) {
+                boolean setMMACpolicyFile = admin.isCustomPolicyFile[DevicePolicyManager.MMAC_POLICY_FILE];
+                Slog.v(TAG, admin.info.getComponent() + " is no longer a SE Android MMAC admin");
+
+                admin.isMMACadmin = false;
+                admin.enforceMMAC = false;
+                admin.isCustomPolicyFile[DevicePolicyManager.MMAC_POLICY_FILE] = false;
+
+                saveSettingsLocked(userHandle);
+                syncMMACpolicyLocked(policy, setMMACpolicyFile);
+                return true;
+            }
+        }
+
+        // Case TTF(F) = 1
+        // Case TFT(T) = 1
+        return false;
+    }
+
+    @Override
+    public boolean getMMACenforcing(ComponentName who, int userHandle) {
+        //Uses very similar code to the SELinux version
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set MMAC settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set MMAC settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            // Case: F** = 4
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_MMAC);
+            // Case: T** = 4
+            return admin.isMMACadmin && admin.enforceMMAC;
+        }
+    }
+
+    @Override
+    public boolean setMMACenforcing(ComponentName who, boolean enforcing, int userHandle) {
+        //Uses very similar code to the SELinux version
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Only owner can set MMAC settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set MMAC settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            // Case F**(*) = 8
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_ENFORCE_MMAC);
+
+            // Case TF*(*) = 4
+            if (!admin.isMMACadmin) {
+                return false;
+            }
+
+            // Case TT*(*) = 4
+            if (admin.enforceMMAC != enforcing) {
+                admin.enforceMMAC = enforcing;
+                saveSettingsLocked(userHandle);
+            }
+            DevicePolicyData policy = getUserData(userHandle);
+            return syncMMACpolicyLocked(policy, false);
+        }
+    }
+
+    @Override
+    public boolean isCustomPolicyFile(ComponentName who, int policyType, int userHandle) {
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            if (policyType >= DevicePolicyManager.SEPOLICY_FILE_COUNT) {
+                throw new IllegalArgumentException("policyType is unknown");
+            }
+            // Only owner can set SELinux settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set SELinux settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+            PolicyFileDescription desc = POLICY_DESCRIPTIONS[policyType];
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who, desc.reqPolicy);
+            return desc.isPolicyAdmin(admin) && admin.isCustomPolicyFile[policyType];
+        }
+    }
+
+    @Override
+    public boolean setCustomPolicyFile(ComponentName who, int policyType, byte[] policy,
+            int userHandle) {
+        enforceCrossUserPermission(userHandle);
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            if (policyType >= DevicePolicyManager.SEPOLICY_FILE_COUNT) {
+                throw new IllegalArgumentException("policyType is unknown");
+            }
+            // Only owner can set SELinux settings
+            if (userHandle != UserHandle.USER_OWNER
+                    || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                Slog.w(TAG, "Only owner is allowed to set SELinux settings. User "
+                        + UserHandle.getCallingUserId() + " is not permitted.");
+                return false;
+            }
+
+            PolicyFileDescription desc = POLICY_DESCRIPTIONS[policyType];
+            File polFile = new File(desc.path);
+            File polFileTmp = new File(desc.path + ".tmp");
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    desc.reqPolicy);
+            if (!desc.isPolicyAdmin(admin)) {
+                return false;
+            }
+
+            boolean newPolicy = policy != null;
+            if (newPolicy != admin.isCustomPolicyFile[policyType]) {
+                admin.isCustomPolicyFile[policyType] = newPolicy;
+                saveSettingsLocked(userHandle);
+            }
+            boolean ret = writePolicyFile(polFile, polFileTmp, policy);
+            if (ret) {
+                desc.doPolicyReload();
+            }
+            return ret;
+        }
+    }
+
+    /* Are there better ways than passing a byte[]? This might involve a lot
+     * of copying. Can we pass file descriptors? Can we pass a path (and what
+     * are the security implications)? If SELinux is enforcing, can system
+     * domain access another app's files?
+     *
+     * byte[] allows admin apps to set a policy without ever having to write
+     * the file to to storage, eg an admin app receiving a new policy file over
+     * data connection.
+     *
+     * We don't need to save this policy file somewhere in the ActiveAdmin/xml
+     * because it's written to /data/system, which is persistent.
+     */
+    private boolean writePolicyFile(File policyFile, File tempPolicyFile, byte[] policy) {
+        if (policy == null) {
+            if (policyFile.exists() && !policyFile.delete()) {
+                return false;
+            }
+            return true;
+        } else {
+            if (policy.length == 0) {
+                return false;
+            }
+            JournaledFile journal = new JournaledFile(policyFile, tempPolicyFile);
+            FileOutputStream stream = null;
+            try {
+                stream = new FileOutputStream(journal.chooseForWrite(), false);
+                stream.write(policy);
+                stream.flush();
+                stream.close();
+                journal.commit();
+            } catch (IOException err) {
+                if (stream != null) {
+                    try {
+                        stream.close();
+                    } catch (IOException ex) {
+                        //ignore
+                    }
+                }
+                journal.rollback();
+                Slog.w(TAG, err.toString());
+                return false;
+            }
+            return true;
+	}
+    }
+
     private void enableIfNecessary(String packageName, int userId) {
         try {
             IPackageManager ipm = AppGlobals.getPackageManager();