Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e471ff32 authored by Hunter Knepshield's avatar Hunter Knepshield Committed by Gerrit Code Review
Browse files

Merge "Update CarrierPrivilegesTracker to cache package names"

parents 25793b59 2602eaa2
Loading
Loading
Loading
Loading
+138 −55
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import android.util.ArraySet;
import android.util.IntArray;
import android.util.LocalLog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.telephony.uicc.UiccPort;
import com.android.internal.telephony.uicc.UiccProfile;
@@ -66,11 +67,15 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;

/**
 * CarrierPrivilegesTracker will track the Carrier Privileges for a specific {@link Phone}.
@@ -134,23 +139,68 @@ public class CarrierPrivilegesTracker extends Handler {
    private final PackageManager mPackageManager;
    private final UserManager mUserManager;
    private final TelephonyManager mTelephonyManager;
    private final RegistrantList mRegistrantList;
    private final LocalLog mLocalLog;

    private final LocalLog mLocalLog = new LocalLog(64);
    private final RegistrantList mRegistrantList = new RegistrantList();
    // Stores rules for Carrier Config-loaded rules
    private final List<UiccAccessRule> mCarrierConfigRules;

    private final List<UiccAccessRule> mCarrierConfigRules = new ArrayList<>();
    // Stores rules for SIM-loaded rules.
    private final List<UiccAccessRule> mUiccRules;

    private final List<UiccAccessRule> mUiccRules = new ArrayList<>();
    // Map of PackageName -> Certificate hashes for that Package
    private final Map<String, Set<String>> mInstalledPackageCerts;

    private final Map<String, Set<String>> mInstalledPackageCerts = new ArrayMap<>();
    // Map of PackageName -> UIDs for that Package
    private final Map<String, Set<Integer>> mCachedUids;
    private final Map<String, Set<Integer>> mCachedUids = new ArrayMap<>();

    private final ReadWriteLock mPrivilegedPackageInfoLock = new ReentrantReadWriteLock();
    // Package names and UIDs of apps that currently hold carrier privileges.
    @GuardedBy({"mPrivilegedPackageInfoLock.readLock()", "mPrivilegedPackageInfoLock.writeLock()"})
    private PrivilegedPackageInfo mPrivilegedPackageInfo = new PrivilegedPackageInfo();

    /** Small snapshot to hold package names and UIDs of privileged packages. */
    private static final class PrivilegedPackageInfo {
        final Set<String> mPackageNames;
        final int[] mUids; // Note: must be kept sorted for equality purposes

        PrivilegedPackageInfo() {
            mPackageNames = Collections.emptySet();
            mUids = new int[0];
        }

        PrivilegedPackageInfo(Set<String> packageNames, Set<Integer> uids) {
            mPackageNames = packageNames;
            IntArray converter = new IntArray(uids.size());
            uids.forEach(converter::add);
            mUids = converter.toArray();
            Arrays.sort(mUids); // for equality purposes
        }

        @Override
        public String toString() {
            return "{packageNames="
                    + getObfuscatedPackages(mPackageNames, pkg -> Rlog.pii(TAG, pkg))
                    + ", uids="
                    + Arrays.toString(mUids)
                    + "}";
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (!(o instanceof PrivilegedPackageInfo)) {
                return false;
            }
            PrivilegedPackageInfo other = (PrivilegedPackageInfo) o;
            return mPackageNames.equals(other.mPackageNames) && Arrays.equals(mUids, other.mUids);
        }

    // Privileged UIDs must be kept in sorted order for update-checks.
    private int[] mPrivilegedUids;
        @Override
        public int hashCode() {
            // Since we have an array, we have to use deepHashCode instead of "regular" Objects.hash
            return Arrays.deepHashCode(new Object[] {mPackageNames, mUids});
        }
    }

    private final BroadcastReceiver mIntentReceiver =
            new BroadcastReceiver() {
@@ -218,7 +268,6 @@ public class CarrierPrivilegesTracker extends Handler {
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        mPhone = phone;
        mLocalLog = new LocalLog(64);

        IntentFilter certFilter = new IntentFilter();
        certFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
@@ -236,13 +285,6 @@ public class CarrierPrivilegesTracker extends Handler {
        packageFilter.addDataScheme("package");
        mContext.registerReceiver(mIntentReceiver, packageFilter);

        mRegistrantList = new RegistrantList();
        mCarrierConfigRules = new ArrayList<>();
        mUiccRules = new ArrayList<>();
        mInstalledPackageCerts = new ArrayMap<>();
        mCachedUids = new ArrayMap<>();
        mPrivilegedUids = new int[0];

        sendMessage(obtainMessage(ACTION_INITIALIZE_TRACKER));
    }

@@ -290,7 +332,14 @@ public class CarrierPrivilegesTracker extends Handler {

    private void handleRegisterListener(Registrant registrant) {
        mRegistrantList.add(registrant);
        registrant.notifyResult(mPrivilegedUids);
        mPrivilegedPackageInfoLock.readLock().lock();
        try {
            registrant.notifyResult(
                    Arrays.copyOf(
                            mPrivilegedPackageInfo.mUids, mPrivilegedPackageInfo.mUids.length));
        } finally {
            mPrivilegedPackageInfoLock.readLock().unlock();
        }
    }

    private void handleUnregisterListener(Handler handler) {
@@ -380,12 +429,15 @@ public class CarrierPrivilegesTracker extends Handler {
        }

        updateCertsForPackage(pkg);
        mCachedUids.put(pkg.packageName, getUidsForPackage(pkg.packageName));
        // Invalidate cache because this may be a package already on the device but getting
        // installed for a user it wasn't installed in before, which means there will be an
        // additional UID.
        getUidsForPackage(pkg.packageName, /* invalidateCache= */ true);
        mLocalLog.log("Package added/replaced:"
                + " pkg=" + Rlog.pii(TAG, pkgName)
                + " cert hashes=" + mInstalledPackageCerts.get(pkgName));

        maybeUpdatePrivilegedUidsAndNotifyRegistrants();
        maybeUpdatePrivilegedPackagesAndNotifyRegistrants();
    }

    private void updateCertsForPackage(PackageInfo pkg) {
@@ -403,15 +455,14 @@ public class CarrierPrivilegesTracker extends Handler {
    }

    private void handlePackageRemoved(String pkgName) {
        if (mInstalledPackageCerts.remove(pkgName) == null) {
        if (mInstalledPackageCerts.remove(pkgName) == null || mCachedUids.remove(pkgName) == null) {
            Rlog.e(TAG, "Unknown package was uninstalled: " + pkgName);
            return;
        }
        mCachedUids.remove(pkgName);

        mLocalLog.log("Package removed: pkg=" + Rlog.pii(TAG, pkgName));

        maybeUpdatePrivilegedUidsAndNotifyRegistrants();
        maybeUpdatePrivilegedPackagesAndNotifyRegistrants();
    }

    private void handleInitializeTracker() {
@@ -431,26 +482,34 @@ public class CarrierPrivilegesTracker extends Handler {
                        flags, UserHandle.SYSTEM.getIdentifier());
        for (PackageInfo pkg : installedPackages) {
            updateCertsForPackage(pkg);
            // We shouldn't have any events coming in before initialization, but invalidate the
            // cache just in case to ensure consistency.
            getUidsForPackage(pkg.packageName, /* invalidateCache= */ true);
        }

        // Okay because no registrants exist yet
        maybeUpdatePrivilegedUidsAndNotifyRegistrants();
        maybeUpdatePrivilegedPackagesAndNotifyRegistrants();

        String msg = "Initializing state:"
                + " CarrierConfig rules=" + mCarrierConfigRules
                + " SIM-loaded rules=" + mUiccRules;
        if (VDBG) {
            msg += " installed pkgs=" + getObfuscatedPackages();
            msg +=
                    " installed pkgs="
                            + getObfuscatedPackages(
                                    mInstalledPackageCerts.entrySet(),
                                    e -> "pkg(" + Rlog.pii(TAG, e.getKey()) + ")=" + e.getValue());
        }
        mLocalLog.log(msg);
    }

    private String getObfuscatedPackages() {
        StringJoiner obfuscatedPkgs = new StringJoiner(",", "{", "}");
        for (Map.Entry<String, Set<String>> pkg : mInstalledPackageCerts.entrySet()) {
            obfuscatedPkgs.add("pkg(" + Rlog.pii(TAG, pkg.getKey()) + ")=" + pkg.getValue());
    private static <T> String getObfuscatedPackages(
            Collection<T> packageNames, Function<T, String> obfuscator) {
        StringJoiner obfuscated = new StringJoiner(", ", "{", "}");
        for (T packageName : packageNames) {
            obfuscated.add(obfuscator.apply(packageName));
        }
        return obfuscatedPkgs.toString();
        return obfuscated.toString();
    }

    private void maybeUpdateRulesAndNotifyRegistrants(
@@ -460,35 +519,48 @@ public class CarrierPrivilegesTracker extends Handler {
        currentRules.clear();
        currentRules.addAll(updatedRules);

        maybeUpdatePrivilegedUidsAndNotifyRegistrants();
        maybeUpdatePrivilegedPackagesAndNotifyRegistrants();
    }

    private void maybeUpdatePrivilegedUidsAndNotifyRegistrants() {
        int[] currentPrivilegedUids = getCurrentPrivilegedUidsForAllUsers();
    private void maybeUpdatePrivilegedPackagesAndNotifyRegistrants() {
        PrivilegedPackageInfo currentPrivilegedPackageInfo =
                getCurrentPrivilegedPackagesForAllUsers();

        // Sort UIDs for the equality check
        Arrays.sort(currentPrivilegedUids);
        if (Arrays.equals(mPrivilegedUids, currentPrivilegedUids)) return;
        mPrivilegedPackageInfoLock.readLock().lock();
        try {
            if (mPrivilegedPackageInfo.equals(currentPrivilegedPackageInfo)) return;
        } finally {
            mPrivilegedPackageInfoLock.readLock().unlock();
        }

        mPrivilegedUids = currentPrivilegedUids;
        mRegistrantList.notifyResult(mPrivilegedUids);
        mPrivilegedPackageInfoLock.writeLock().lock();
        try {
            mPrivilegedPackageInfo = currentPrivilegedPackageInfo;
        } finally {
            mPrivilegedPackageInfoLock.writeLock().unlock();
        }

        mLocalLog.log("Privileged UIDs changed. New UIDs=" + Arrays.toString(mPrivilegedUids));
        mPrivilegedPackageInfoLock.readLock().lock();
        try {
            mLocalLog.log("Privileged packages changed. New state = " + mPrivilegedPackageInfo);
            mRegistrantList.notifyResult(
                    Arrays.copyOf(
                            mPrivilegedPackageInfo.mUids, mPrivilegedPackageInfo.mUids.length));
        } finally {
            mPrivilegedPackageInfoLock.readLock().unlock();
        }
    }

    private int[] getCurrentPrivilegedUidsForAllUsers() {
    private PrivilegedPackageInfo getCurrentPrivilegedPackagesForAllUsers() {
        Set<String> privilegedPackageNames = new ArraySet<>();
        Set<Integer> privilegedUids = new ArraySet<>();
        for (Map.Entry<String, Set<String>> e : mInstalledPackageCerts.entrySet()) {
            if (isPackagePrivileged(e.getKey(), e.getValue())) {
                privilegedUids.addAll(getUidsForPackage(e.getKey()));
                privilegedPackageNames.add(e.getKey());
                privilegedUids.addAll(getUidsForPackage(e.getKey(), /* invalidateCache= */ false));
            }
        }

        IntArray result = new IntArray(privilegedUids.size());
        for (int uid : privilegedUids) {
            result.add(uid);
        }
        return result.toArray();
        return new PrivilegedPackageInfo(privilegedPackageNames, privilegedUids);
    }

    /**
@@ -514,7 +586,10 @@ public class CarrierPrivilegesTracker extends Handler {
        return false;
    }

    private Set<Integer> getUidsForPackage(String pkgName) {
    private Set<Integer> getUidsForPackage(String pkgName, boolean invalidateCache) {
        if (invalidateCache) {
            mCachedUids.remove(pkgName);
        }
        if (mCachedUids.containsKey(pkgName)) {
            return mCachedUids.get(pkgName);
        }
@@ -538,17 +613,25 @@ public class CarrierPrivilegesTracker extends Handler {
     * Dump the local log buffer and other internal state of CarrierPrivilegesTracker.
     */
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("Dump of CarrierPrivilegesTracker");
        pw.println("CarrierPrivilegesTracker - Log Begin ----");
        mLocalLog.dump(fd, pw, args);
        pw.println("CarrierPrivilegesTracker - Log End ----");
        pw.println("CarrierPrivilegesTracker - Privileged UIDs: "
                + Arrays.toString(mPrivilegedUids));
        mPrivilegedPackageInfoLock.readLock().lock();
        try {
            pw.println(
                    "CarrierPrivilegesTracker - Privileged package info: "
                            + mPrivilegedPackageInfo);
        } finally {
            mPrivilegedPackageInfoLock.readLock().unlock();
        }
        pw.println("CarrierPrivilegesTracker - SIM-loaded rules: " + mUiccRules);
        pw.println("CarrierPrivilegesTracker - Carrier config rules: " + mCarrierConfigRules);
        if (VDBG) {
            pw.println("CarrierPrivilegesTracker - Obfuscated Pkgs + Certs: "
                    + getObfuscatedPackages());
            pw.println(
                    "CarrierPrivilegesTracker - Obfuscated Pkgs + Certs: "
                            + getObfuscatedPackages(
                                    mInstalledPackageCerts.entrySet(),
                                    e -> "pkg(" + Rlog.pii(TAG, e.getKey()) + ")=" + e.getValue()));
        }
    }