@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;
  }
  /**
   * Applies a security label to a package based on an seinfo tag taken from a matched policy. All
   * signature based policy stanzas are consulted and, if no match is found, the default seinfo
   * label of 'default' (set in ApplicationInfo object) is used. The security label is attached to
   * the ApplicationInfo instance of the package in the event that a matching policy was found.
   *
   * @param pkg object representing the package to be labeled.
   */
  public static void assignSeinfoValue(PackageParser.Package pkg) {
    synchronized (sPolicies) {
      for (Policy policy : sPolicies) {
        String seinfo = policy.getMatchedSeinfo(pkg);
        if (seinfo != null) {
          pkg.applicationInfo.seinfo = seinfo;
          break;
        }
      }
    }

    if (pkg.applicationInfo.isAutoPlayApp()) pkg.applicationInfo.seinfo += AUTOPLAY_APP_STR;

    if (pkg.applicationInfo.isPrivilegedApp()) pkg.applicationInfo.seinfo += PRIVILEGED_APP_STR;

    if (DEBUG_POLICY_INSTALL) {
      Slog.i(
          TAG,
          "package ("
              + pkg.packageName
              + ") labeled with "
              + "seinfo="
              + pkg.applicationInfo.seinfo);
    }
  }
  /**
   * 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;
  }