Anonymous avatar Anonymous committed 8aa441d

Implement Device Admin API for 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
     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 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 void lockNow();
     method public void removeActiveAdmin(android.content.ComponentName);
     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);
     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 = 4; // 0x4
+    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

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

      */
     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;
         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_ENFORCE_SELINUX}.
+     * {@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

         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 SEPOLICY_FILE_COUNT = SEPOLICY_FILE_SEAPPCTXS+1;
+    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.
      * 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}, or {@link #SEPOLICY_FILE_SEAPPCTXS}
+     * {@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
      * 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}, or {@link #SEPOLICY_FILE_SEAPPCTXS}
+     * {@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) {

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

     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);
 

core/res/res/values/strings.xml

     <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 SE Android MMAC policy [CHAR LIMIT=30]-->
+    <string name="policylab_enforceMmac">Enforce SE Android MMAC</string>
+    <!-- Description of policy access to start enforcing SE Android MMAC policy [CHAR LIMIT=110]-->
+    <string name="policydesc_enforceMmac">Toggle SE Android 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="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="plurals" name="abbrev_in_num_days" />
   <java-symbol type="plurals" name="abbrev_in_num_hours" />

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

             // 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>();
         }
     }
 
+    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 SEPOLICY_PATH_SEPOLICY = "/data/system/sepolicy";
 
     private static final String SEPOLICY_PATH_PROPCTXS = "/data/system/property_contexts";
 
     private static final String SEPOLICY_PATH_SEAPPCTXS = "/data/system/seapp_contexts";
 
+    private static final String MMAC_POLICY_PATH = "/data/system/mac_permissions.xml";
+
     private static final PolicyFileDescription[] POLICY_DESCRIPTIONS = {
         // 0 = SEPOLICY_FILE_SEPOLICY
         new SELinuxPolicyDescription(SEPOLICY_PATH_SEPOLICY),
         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 {
         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) {
                     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 ("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(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]);
+
         }
     }
 
                                 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);
                                             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);
                             }
         syncDeviceCapabilitiesLocked(policy);
         updateMaximumTimeToLockLocked(policy);
         syncSELinuxPolicyLocked(policy, false);
+        syncMMACpolicyLocked(policy, false);
     }
 
     static void validateQualityConstant(int quality) {
         }
     }
 
+    // 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
+
+    /**
+     * This system property is used to share the state of the MAC enforcing mode.
+     * SE Android MAC protection layer is expected to read this property and act accordingly.
+     */
+    public static final String SYSTEM_PROP_ENFORCE_MAC = "persist.mac_enforcing_mode";
+
+    /**
+     * 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) {
+        if (policy.mUserHandle == UserHandle.USER_OWNER) {
+            ActiveAdmin mmacAdmin = policy.findMMACadminLocked();
+            if (mmacAdmin == null) {
+                // No admin, so create a fake one and restore it.
+                mmacAdmin = new ActiveAdmin(null);
+                mmacAdmin.enforceMMAC = false;
+            }
+
+            boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_ENFORCE_MAC, false);
+            boolean enforceMMAC = mmacAdmin.enforceMMAC;
+            if (systemState != enforceMMAC) {
+                Slog.v(TAG, SYSTEM_PROP_ENFORCE_MAC + " was " + systemState + ", to be set to " + enforceMMAC);
+                String value = enforceMMAC ? "1" : "0";
+                SystemProperties.set(SYSTEM_PROP_ENFORCE_MAC, value);
+            }
+
+            if (removePolicy) {
+                boolean ret = true;
+                File polFile;
+                polFile = new File(MMAC_POLICY_PATH);
+                if (polFile.exists() && !polFile.delete()) {
+                    ret = false;
+                }
+                return ret;
+
+            } else { //Not removing any policy files
+                return true;
+            }
+
+        } else { //User is not owner
+            return false;
+        }
+    }
+
+    // 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);
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.