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

Commit 3b30aa7a authored by Cody Kesting's avatar Cody Kesting
Browse files

Update CarrierConfig Certs when CarrierConfigs change.

When CarrierConfigs are updated, get the current certs for this Phone's
subId. Compare the certs against the installed packages on the user's
device. If the CarrierConfig change results in changes to the carrier
privileged UIDs, all registered CarrierPrivilegesListeners will be
notified.

Bug: 147391402
Test: Tested on crosshatch build
Change-Id: I4597d06077916bbf69d6a9d94708037e21c6ac8b
parent 25f8df2d
Loading
Loading
Loading
Loading
+160 −1
Original line number Diff line number Diff line
@@ -16,14 +16,39 @@

package com.android.internal.telephony;

import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
import static android.telephony.CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;

import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.UserManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Log;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * CarrierPrivilegesTracker will track the Carrier Privileges for a specific {@link Phone}.
 * Registered Telephony entities will receive notifications when the UIDs with these privileges
@@ -44,12 +69,66 @@ public class CarrierPrivilegesTracker extends Handler {
     */
    private static final int ACTION_UNREGISTER_LISTENER = 2;

    /**
     * Action for tracking when Carrier Configs are updated.
     * arg1: Subscription Id for the Carrier Configs update being broadcast
     * arg2: Slot Index for the Carrier Configs update being broadcast
     */
    private static final int ACTION_CARRIER_CONFIG_CERTS_UPDATED = 3;

    private final Context mContext;
    private final Phone mPhone;
    private final CarrierConfigManager mCarrierConfigManager;
    private final PackageManager mPackageManager;
    private final UserManager mUserManager;
    private final RegistrantList mRegistrantList;
    private final Set<String> mCarrierConfigCerts;

    // Map of PackageName -> Certificate hashes for that Package
    private final Map<String, Set<String>> mInstalledPackageCerts;
    private int[] mPrivilegedUids;

    public CarrierPrivilegesTracker(@NonNull Looper looper) {
    private final BroadcastReceiver mIntentReceiver =
            new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction();
                    if (action == null) return;

                    switch (action) {
                        case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: {
                            Bundle extras = intent.getExtras();
                            int slotIndex = extras.getInt(EXTRA_SLOT_INDEX);
                            int subId =
                                    extras.getInt(
                                            EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID);
                            sendMessage(
                                    obtainMessage(
                                            ACTION_CARRIER_CONFIG_CERTS_UPDATED,
                                            subId,
                                            slotIndex));
                            break;
                        }
                    }
                }
            };

    public CarrierPrivilegesTracker(
            @NonNull Looper looper, @NonNull Phone phone, @NonNull Context context) {
        super(looper);
        mContext = context;
        mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
        mPackageManager = context.getSystemService(PackageManager.class);
        mUserManager = context.getSystemService(UserManager.class);
        mPhone = phone;

        IntentFilter filter = new IntentFilter();
        filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
        mContext.registerReceiver(mIntentReceiver, filter);

        mRegistrantList = new RegistrantList();
        mCarrierConfigCerts = new ArraySet<>();
        mInstalledPackageCerts = new ArrayMap<>();
        mPrivilegedUids = new int[0];
    }

@@ -64,6 +143,10 @@ public class CarrierPrivilegesTracker extends Handler {
                handleUnregisterListener((Handler) msg.obj);
                break;
            }
            case ACTION_CARRIER_CONFIG_CERTS_UPDATED: {
                handleCarrierConfigUpdated(msg.arg1, msg.arg2);
                break;
            }
            default: {
                Log.e(TAG, "Received unknown msg type: " + msg.what);
                break;
@@ -80,6 +163,82 @@ public class CarrierPrivilegesTracker extends Handler {
        mRegistrantList.remove(handler);
    }

    private void handleCarrierConfigUpdated(int subId, int slotIndex) {
        if (slotIndex != mPhone.getPhoneId()) return;

        Set<String> updatedCarrierConfigCerts = new ArraySet<>();

        // Carrier Config broadcasts with INVALID_SUBSCRIPTION_ID when the SIM is removed. This is
        // an expected event. When this happens, clear the certificates from the previous configs.
        if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
            PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
            if (mCarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) {
                String[] carrierConfigCerts =
                        carrierConfigs.getStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY);

                if (carrierConfigCerts != null) {
                    for (String cert : carrierConfigCerts) {
                        updatedCarrierConfigCerts.add(cert.toUpperCase());
                    }
                }
            }
        }

        maybeUpdateCertsAndNotifyRegistrants(mCarrierConfigCerts, updatedCarrierConfigCerts);
    }

    private void maybeUpdateCertsAndNotifyRegistrants(
            Set<String> currentCerts, Set<String> updatedCerts) {
        if (!currentCerts.equals(updatedCerts)) {
            currentCerts.clear();
            currentCerts.addAll(updatedCerts);

            int[] currentPrivilegedUids = getCurrentPrivilegedUids();

            // Sort UIDs for the equality check
            Arrays.sort(currentPrivilegedUids);
            if (!Arrays.equals(mPrivilegedUids, currentPrivilegedUids)) {
                mPrivilegedUids = currentPrivilegedUids;
                mRegistrantList.notifyResult(mPrivilegedUids);
            }
        }
    }

    private int[] getCurrentPrivilegedUids() {
        Set<Integer> privilegedUids = new ArraySet<>();
        for (Map.Entry<String, Set<String>> e : mInstalledPackageCerts.entrySet()) {
            if (isPackagePrivileged(e.getValue())) {
                List<UserInfo> users = mUserManager.getUsers();
                for (UserInfo user : users) {
                    try {
                        int uid =
                                mPackageManager.getPackageUidAsUser(
                                        e.getKey(), user.getUserHandle().getIdentifier());
                        privilegedUids.add(uid);
                    } catch (NameNotFoundException exception) {
                        // Didn't find package. Continue looking at other packages
                        Log.e(TAG, "Unable to find uid for package: " + e.getKey());
                    }
                }
            }
        }

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

    private boolean isPackagePrivileged(Set<String> certs) {
        for (String cert : certs) {
            if (mCarrierConfigCerts.contains(cert)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Registers the given Registrant with this tracker.
     *