@Override
  public int compare(Policy p1, Policy p2) {

    // Give precedence to stanzas with inner package mappings
    if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
      return p1.hasInnerPackages() ? -1 : 1;
    }

    // Check for duplicate entries
    if (p1.getSignatures().equals(p2.getSignatures())) {
      // Checks if signer w/o inner package names
      if (p1.hasGlobalSeinfo()) {
        duplicateFound = true;
        Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
      }

      // Look for common inner package name mappings
      final Map<String, String> p1Packages = p1.getInnerPackages();
      final Map<String, String> p2Packages = p2.getInnerPackages();
      if (!Collections.disjoint(p1Packages.keySet(), p2Packages.keySet())) {
        duplicateFound = true;
        Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
      }
    }

    return 0;
  }
  /**
   * Load the mac_permissions.xml file containing all seinfo assignments used to label apps. The
   * loaded mac_permissions.xml file is determined by the MAC_PERMISSIONS class variable which is
   * set at class load time which itself is based on the USE_OVERRIDE_POLICY class variable. For
   * further guidance on the proper structure of a mac_permissions.xml file consult the source code
   * located at system/sepolicy/mac_permissions.xml.
   *
   * @return boolean indicating if policy was correctly loaded. A value of false typically indicates
   *     a structural problem with the xml or incorrectly constructed policy stanzas. A value of
   *     true means that all stanzas were loaded successfully; no partial loading is possible.
   */
  public static boolean readInstallPolicy() {
    // Temp structure to hold the rules while we parse the xml file
    List<Policy> policies = new ArrayList<>();

    FileReader policyFile = null;
    XmlPullParser parser = Xml.newPullParser();
    try {
      policyFile = new FileReader(MAC_PERMISSIONS);
      Slog.d(TAG, "Using policy file " + MAC_PERMISSIONS);

      parser.setInput(policyFile);
      parser.nextTag();
      parser.require(XmlPullParser.START_TAG, null, "policy");

      while (parser.next() != XmlPullParser.END_TAG) {
        if (parser.getEventType() != XmlPullParser.START_TAG) {
          continue;
        }

        switch (parser.getName()) {
          case "signer":
            policies.add(readSignerOrThrow(parser));
            break;
          default:
            skip(parser);
        }
      }
    } catch (IllegalStateException | IllegalArgumentException | XmlPullParserException ex) {
      StringBuilder sb = new StringBuilder("Exception @");
      sb.append(parser.getPositionDescription());
      sb.append(" while parsing ");
      sb.append(MAC_PERMISSIONS);
      sb.append(":");
      sb.append(ex);
      Slog.w(TAG, sb.toString());
      return false;
    } catch (IOException ioe) {
      Slog.w(TAG, "Exception parsing " + MAC_PERMISSIONS, ioe);
      return false;
    } finally {
      IoUtils.closeQuietly(policyFile);
    }

    // Now sort the policy stanzas
    PolicyComparator policySort = new PolicyComparator();
    Collections.sort(policies, policySort);
    if (policySort.foundDuplicate()) {
      Slog.w(TAG, "ERROR! Duplicate entries found parsing " + MAC_PERMISSIONS);
      return false;
    }

    synchronized (sPolicies) {
      sPolicies = policies;

      if (DEBUG_POLICY_ORDER) {
        for (Policy policy : sPolicies) {
          Slog.d(TAG, "Policy: " + policy.toString());
        }
      }
    }

    return true;
  }