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

Commit 42acc3dc authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Added addSubInfo support"

parents 6231102f 363f99b5
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.metrics.CarrierIdMatchStats;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.subscription.SubscriptionManagerService;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.util.TelephonyUtils;
@@ -548,9 +549,14 @@ public class CarrierResolver extends Handler {
        // subscriptioninfo db to make sure we have correct carrier id set.
        if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId()) && !isSimOverride) {
            // only persist carrier id to simInfo db when subId is valid.
            if (mPhone.isSubscriptionManagerServiceEnabled()) {
                SubscriptionManagerService.getInstance().setCarrierId(mPhone.getSubId(),
                        mCarrierId);
            } else {
                SubscriptionController.getInstance().setCarrierId(mCarrierId, mPhone.getSubId());
            }
        }
    }

    private static CarrierMatchingRule makeCarrierMatchingRule(Cursor cursor) {
        String certs = cursor.getString(
+13 −2
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
import com.android.internal.telephony.imsphone.ImsPhoneMmiCode;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.metrics.VoiceCallSessionStats;
import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback;
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
import com.android.internal.telephony.uicc.IccCardStatus;
@@ -349,8 +350,18 @@ public class GsmCdmaPhone extends Phone {
        mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
        mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null);

        if (isSubscriptionManagerServiceEnabled()) {
            mSubscriptionManagerService.registerCallback(new SubscriptionManagerServiceCallback(
                    this::post) {
                @Override
                public void onUiccApplicationsEnabled(int subId) {
                    reapplyUiccAppsEnablementIfNeeded(ENABLE_UICC_APPS_MAX_RETRIES);
                }
            });
        } else {
            SubscriptionController.getInstance().registerForUiccAppsEnabled(this,
                    EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false);
        }

        mLinkBandwidthEstimator = mTelephonyComponentFactory
                .inject(LinkBandwidthEstimator.class.getName())
+5 −0
Original line number Diff line number Diff line
@@ -444,6 +444,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface {
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    protected final Context mContext;

    protected SubscriptionManagerService mSubscriptionManagerService;

    /**
     * PhoneNotifier is an abstraction for all system-wide
     * state change notification. DefaultPhoneNotifier is
@@ -616,6 +618,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface {

        mIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_using_subscription_manager_service);
        if (isSubscriptionManagerServiceEnabled()) {
            mSubscriptionManagerService = SubscriptionManagerService.getInstance();
        }

        // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
        mTelephonyComponentFactory = telephonyComponentFactory;
+217 −153
Original line number Diff line number Diff line
@@ -49,7 +49,9 @@ import com.android.telephony.Rlog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -77,45 +79,6 @@ public class SubscriptionDatabaseManager extends Handler {
    /** Invalid database row index. */
    private static final int INVALID_ROW_INDEX = -1;

    /** The context */
    @NonNull
    private final Context mContext;

    /** The callback used for passing events back to {@link SubscriptionManagerService}. */
    @NonNull
    private final SubscriptionDatabaseManagerCallback mCallback;

    /** Telephony manager */
    private final TelephonyManager mTelephonyManager;

    /** UICC controller */
    private final UiccController mUiccController;

    /**
     * The read/write lock to protect the entire database access. Using a Re-entrant read lock as
     * much more read requests are expected than the write requests. All the access to
     * {@link #mAllSubscriptionInfoInternalCache} needs to be protected by this lock.
     */
    @NonNull
    private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();

    /** Local log for most important debug messages. */
    @NonNull
    private final LocalLog mLocalLog = new LocalLog(128);

    /**
     * The entire subscription database, including subscriptions from inserted, previously inserted
     * SIMs. This is the full memory cache of the subscription database. The key is the subscription
     * id. Note all the access to this map needs to be protected by the re-entrant lock
     * {@link #mReadWriteLock}.
     *
     * @see SimInfo
     */
    @GuardedBy("mReadWriteLock")
    @NonNull
    private final Map<Integer, SubscriptionInfoInternal> mAllSubscriptionInfoInternalCache =
            new HashMap<>(16);

    /** The mapping from {@link SimInfo} table to {@link SubscriptionInfoInternal} get methods. */
    private static final Map<String, Function<SubscriptionInfoInternal, ?>>
            SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries(
@@ -265,6 +228,45 @@ public class SubscriptionDatabaseManager extends Handler {
                    SubscriptionInfoInternal::getUserId)
    );

    /** The context */
    @NonNull
    private final Context mContext;

    /** The callback used for passing events back to {@link SubscriptionManagerService}. */
    @NonNull
    private final SubscriptionDatabaseManagerCallback mCallback;

    /** UICC controller */
    private final UiccController mUiccController;

    /**
     * The read/write lock to protect the entire database access. Using a Re-entrant read lock as
     * much more read requests are expected than the write requests. All the access to
     * {@link #mAllSubscriptionInfoInternalCache} needs to be protected by this lock.
     */
    @NonNull
    private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();

    /** Local log for most important debug messages. */
    @NonNull
    private final LocalLog mLocalLog = new LocalLog(128);

    /**
     * The entire subscription database, including subscriptions from inserted, previously inserted
     * SIMs. This is the full memory cache of the subscription database. The key is the subscription
     * id. Note all the access to this map needs to be protected by the re-entrant lock
     * {@link #mReadWriteLock}.
     *
     * @see SimInfo
     */
    @GuardedBy("mReadWriteLock")
    @NonNull
    private final Map<Integer, SubscriptionInfoInternal> mAllSubscriptionInfoInternalCache =
            new HashMap<>(16);

    /** Whether database has been loaded into the cache after boot up. */
    private boolean mDatabaseLoaded = false;

    /**
     * This is the callback used for listening events from {@link SubscriptionDatabaseManager}.
     */
@@ -298,12 +300,25 @@ public class SubscriptionDatabaseManager extends Handler {
            mExecutor.execute(runnable);
        }

        /**
         * Called when database has been loaded into the cache.
         */
        public abstract void onDatabaseLoaded();

        /**
         * Called when subscription changed.
         *
         * @param subId The subscription id.
         */
        public abstract void onSubscriptionChanged(int subId);

        /**
         * Called when {@link SubscriptionInfoInternal#areUiccApplicationsEnabled()}
         * changed.
         *
         * @param subId The subscription id.
         */
        public abstract void onUiccApplicationsEnabled(int subId);
    }

    /**
@@ -318,7 +333,6 @@ public class SubscriptionDatabaseManager extends Handler {
        super(looper);
        mContext = context;
        mCallback = callback;
        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
        mUiccController = UiccController.getInstance();
        loadFromDatabase();
    }
@@ -414,6 +428,11 @@ public class SubscriptionDatabaseManager extends Handler {
                    + "insert. subInfo=" + subInfo);
        }

        if (!mDatabaseLoaded) {
            throw new IllegalStateException("Database has not been loaded. Can't insert new "
                    + "record at this point.");
        }

        int subId;
        // Grab the write lock so no other threads can read or write the cache.
        mReadWriteLock.writeLock().lock();
@@ -447,6 +466,12 @@ public class SubscriptionDatabaseManager extends Handler {
    private void updateDatabaseAsync(int subId, @NonNull ContentValues contentValues) {
        logv("updateDatabaseAsync: prepare to update sub " + subId);
        // Perform the update in the handler thread asynchronously.

        if (!mDatabaseLoaded) {
            throw new IllegalStateException("Database has not been loaded. Can't update "
                    + "database at this point. contentValues=" + contentValues);
        }

        post(() -> {
            int rowsUpdated = mContext.getContentResolver().update(Uri.withAppendedPath(
                    SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null);
@@ -535,6 +560,10 @@ public class SubscriptionDatabaseManager extends Handler {
            if (oldSubInfo.equals(newSubInfo)) return;
            mAllSubscriptionInfoInternalCache.put(subId, newSubInfo);
            mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
            if (oldSubInfo.areUiccApplicationsEnabled()
                    != newSubInfo.areUiccApplicationsEnabled()) {
                mCallback.invokeFromExecutor(() -> mCallback.onUiccApplicationsEnabled(subId));
            }
            // Writing into the database is slow. So do this asynchronously.
            updateDatabaseAsync(subId, createDeltaContentValues(oldSubInfo, newSubInfo));
        } finally {
@@ -1176,6 +1205,8 @@ public class SubscriptionDatabaseManager extends Handler {
                                    .put(subInfo.getSubscriptionId(), subInfo);
                        }
                    }
                    mDatabaseLoaded = true;
                    mCallback.invokeFromExecutor(mCallback::onDatabaseLoaded);
                    log("Loaded " + mAllSubscriptionInfoInternalCache.size()
                            + " records from the subscription database.");
                } finally {
@@ -1311,7 +1342,7 @@ public class SubscriptionDatabaseManager extends Handler {
    /**
     * Get the subscription info by subscription id.
     *
     * @param subId The subscription id
     * @param subId The subscription id.
     *
     * @return The subscription info. {@code null} if not found.
     */
@@ -1325,6 +1356,39 @@ public class SubscriptionDatabaseManager extends Handler {
        }
    }

    /**
     * @return All subscription infos in the database.
     */
    @NonNull
    public List<SubscriptionInfoInternal> getAllSubscriptions() {
        return new ArrayList<>(mAllSubscriptionInfoInternalCache.values());
    }

    /**
     * Get subscription info by ICCID.
     *
     * @param iccId The ICCID of the SIM card.
     * @return The subscription info if found. {@code null} if not found.
     */
    @Nullable
    public SubscriptionInfoInternal getSubscriptionInfoInternalByIccId(@NonNull String iccId) {
        mReadWriteLock.readLock().lock();
        try {
            return mAllSubscriptionInfoInternalCache.values().stream()
                    .filter(subInfo -> subInfo.getIccId().equals(iccId))
                    .findFirst()
                    .orElse(null);
        } finally {
            mReadWriteLock.readLock().unlock();
        }
    }

    /**
     * @return {@code true} if the database has been loaded into the cache.
     */
    public boolean isDatabaseLoaded() {
        return mDatabaseLoaded;
    }
    /**
     * Log debug messages.
     *
+241 −8
Original line number Diff line number Diff line
@@ -16,9 +16,13 @@

package com.android.internal.telephony.subscription;

import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -30,14 +34,19 @@ import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.SubscriptionManager.SubscriptionType;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyRegistryManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.ISetOpportunisticDataCallback;
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.MultiSimSettingController;
import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback;
import com.android.internal.telephony.uicc.IccUtils;
import com.android.telephony.Rlog;

import java.io.FileDescriptor;
@@ -47,6 +56,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

/**
 * The subscription manager service is the backend service of {@link SubscriptionManager}.
@@ -58,18 +68,34 @@ public class SubscriptionManagerService extends ISub.Stub {
    /** Whether enabling verbose debugging message or not. */
    private static final boolean VDBG = false;

    /** Instance of subscription manager service. */
    @NonNull
    private static SubscriptionManagerService sInstance;

    /** The context */
    @NonNull
    private final Context mContext;

    /** The main handler of subscription manager service. */
    @NonNull
    private final Handler mHandler;

    /** Local log for most important debug messages. */
    @NonNull
    private final LocalLog mLocalLog = new LocalLog(128);

    /** The subscription database manager. */
    @NonNull
    private final SubscriptionDatabaseManager mSubscriptionDatabaseManager;

    @NonNull
    private final WatchedSlotIndexToSubId mSlotIndexToSubId = new WatchedSlotIndexToSubId();

    /** Subscription manager service callbacks. */
    @NonNull
    private final Set<SubscriptionManagerServiceCallback> mSubscriptionManagerServiceCallbacks =
            new ArraySet<>();

    /**
     * Watched slot index to sub id map.
     */
@@ -142,7 +168,55 @@ public class SubscriptionManagerService extends ISub.Stub {
        }
    }

    private final WatchedSlotIndexToSubId mSlotIndexToSubId = new WatchedSlotIndexToSubId();
    /**
     * This is the callback used for listening events from {@link SubscriptionManagerService}.
     */
    public static class SubscriptionManagerServiceCallback {
        /** The executor of the callback. */
        @NonNull
        private final Executor mExecutor;

        /**
         * Constructor
         *
         * @param executor The executor of the callback.
         */
        public SubscriptionManagerServiceCallback(@NonNull @CallbackExecutor Executor executor) {
            mExecutor = executor;
        }

        /**
         * @return The executor of the callback.
         */
        @NonNull
        @VisibleForTesting
        public Executor getExecutor() {
            return mExecutor;
        }

        /**
         * Invoke the callback from executor.
         *
         * @param runnable The callback method to invoke.
         */
        public void invokeFromExecutor(@NonNull Runnable runnable) {
            mExecutor.execute(runnable);
        }

        /**
         * Called when subscription changed.
         *
         * @param subId The subscription id.
         */
        public void onSubscriptionChanged(int subId) {}

        /**
         * Called when {@link SubscriptionInfoInternal#areUiccApplicationsEnabled()} changed.
         *
         * @param subId The subscription id.
         */
        public void onUiccApplicationsEnabled(int subId) {}
    }

    /**
     * The constructor
@@ -151,13 +225,16 @@ public class SubscriptionManagerService extends ISub.Stub {
     * @param looper The looper for the handler.
     */
    public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) {
        sInstance = this;
        mContext = context;
        mHandler = new Handler(looper);
        TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer =
                TelephonyFrameworkInitializer
                        .getTelephonyServiceManager()
                        .getSubscriptionServiceRegisterer();
        if (subscriptionServiceRegisterer.get() == null) {
            subscriptionServiceRegisterer.register(this);
        }

        // Create a separate thread for subscription database manager. The database will be updated
        // from a different thread.
@@ -165,6 +242,14 @@ public class SubscriptionManagerService extends ISub.Stub {
        handlerThread.start();
        mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(context,
                handlerThread.getLooper(), new SubscriptionDatabaseManagerCallback(mHandler::post) {
                    /**
                     * Called when database has been loaded into the cache.
                     */
                    @Override
                    public void onDatabaseLoaded() {
                        log("Subscription database has been loaded.");
                    }

                    /**
                     * Called when subscription changed.
                     *
@@ -172,6 +257,10 @@ public class SubscriptionManagerService extends ISub.Stub {
                     */
                    @Override
                    public void onSubscriptionChanged(int subId) {
                        mSubscriptionManagerServiceCallbacks.forEach(
                                callback -> callback.invokeFromExecutor(
                                        () -> callback.onSubscriptionChanged(subId)));

                        MultiSimSettingController.getInstance().notifySubscriptionInfoChanged();

                        TelephonyRegistryManager telephonyRegistryManager =
@@ -190,9 +279,43 @@ public class SubscriptionManagerService extends ISub.Stub {
                        // TODO: Call TelephonyMetrics.updateActiveSubscriptionInfoList when active
                        //  subscription changes.
                    }

                    /**
                     * Called when {@link SubscriptionInfoInternal#areUiccApplicationsEnabled()}
                     * changed.
                     *
                     * @param subId The subscription id.
                     */
                    @Override
                    public void onUiccApplicationsEnabled(int subId) {
                        log("onUiccApplicationsEnabled: subId=" + subId);
                        mSubscriptionManagerServiceCallbacks.forEach(
                                callback -> callback.invokeFromExecutor(
                                        () -> callback.onUiccApplicationsEnabled(subId)));
                    }
                });
    }

    /**
     * @return The singleton instance of {@link SubscriptionManagerService}.
     */
    @NonNull
    public static SubscriptionManagerService getInstance() {
        return sInstance;
    }

    /**
     * Set the subscription carrier id.
     *
     * @param subId Subscription id.
     * @param carrierId The carrier id.
     *
     * @see TelephonyManager#getSimCarrierId()
     */
    public void setCarrierId(int subId, int carrierId) {
        mSubscriptionDatabaseManager.setCarrierId(subId, carrierId);
    }

    /**
     * @param callingPackage The package making the call.
     * @param callingFeatureId The feature in the package
@@ -330,20 +453,70 @@ public class SubscriptionManagerService extends ISub.Stub {
    }

    /**
     * Add a new subscription info record, if needed.
     * Add a new subscription info record, if needed. This should be only used for remote SIM.
     *
     * @param uniqueId This is the unique identifier for the subscription within the specific
     * subscription type
     * @param displayName human-readable name of the device the subscription corresponds to
     * @param slotIndex the slot assigned to this device
     * @param iccId ICCID of the SIM card.
     * @param displayName human-readable name of the device the subscription corresponds to.
     * @param slotIndex the logical SIM slot index assigned to this device.
     * @param subscriptionType the type of subscription to be added
     *
     * @return 0 if success, < 0 on error
     */
    @Override
    public int addSubInfo(@NonNull String uniqueId, @NonNull String displayName, int slotIndex,
    public int addSubInfo(@NonNull String iccId, @NonNull String displayName, int slotIndex,
            @SubscriptionType int subscriptionType) {
        log("addSubInfo: iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + ", slotIndex="
                + slotIndex + ", displayName=" + displayName + ", type="
                + SubscriptionManager.subscriptionTypeToString(subscriptionType));
        enforceModifyPhoneState("addSubInfo");

        // Now that all security checks passes, perform the operation as ourselves.
        final long identity = Binder.clearCallingIdentity();
        try {
            if (TextUtils.isEmpty(iccId)) {
                loge("addSubInfo: null or empty iccId");
                return -1;
            }

            if (subscriptionType != SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM
                    || !mContext.getPackageManager().hasSystemFeature(
                            PackageManager.FEATURE_AUTOMOTIVE)) {
                loge("addSubInfo: remote SIM is only supported when FEATURE_AUTOMOTIVE is "
                        + "enabled.");
                return -1;
            }

            if (slotIndex != SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB) {
                loge("addSubInfo: This API can only be used for remote SIM. slotIndex="
                        + slotIndex);
                return -1;
            }

            iccId = IccUtils.stripTrailingFs(iccId);
            SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager
                    .getSubscriptionInfoInternalByIccId(iccId);

            // Check if the record exists or not.
            if (subInfo == null) {
                // Record does not exist.
                mSubscriptionDatabaseManager.insertSubscriptionInfo(
                        new SubscriptionInfoInternal.Builder()
                                .setIccId(iccId)
                                .setSimSlotIndex(slotIndex)
                                .setDisplayName(displayName)
                                .setType(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM)
                                .build()
                );
            } else {
                // Record already exists.
                loge("Subscription record already existed.");
                return -1;
            }
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
        return 0;

    }

    /**
@@ -700,6 +873,66 @@ public class SubscriptionManagerService extends ISub.Stub {
        return null;
    }

    /**
     * Register the callback for receiving information from {@link SubscriptionManagerService}.
     *
     * @param callback The callback.
     */
    public void registerCallback(@NonNull SubscriptionManagerServiceCallback callback) {
        mSubscriptionManagerServiceCallbacks.add(callback);
    }

    /**
     * Unregister the previously registered {@link SubscriptionManagerServiceCallback}.
     *
     * @param callback The callback to unregister.
     */
    public void unregisterCallback(@NonNull SubscriptionManagerServiceCallback callback) {
        mSubscriptionManagerServiceCallbacks.remove(callback);
    }

    /**
     * Enforce {@link android.Manifest.permission#MODIFY_PHONE_STATE} permission
     *
     * @param message Error message included in the exception.
     */
    private void enforceModifyPhoneState(String message) {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.MODIFY_PHONE_STATE, message);
    }

    /**
     * Enforce {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} permission
     *
     * @param message Error message included in the exception.
     */
    private void enforceReadPrivilegedPhoneState(String message) {
        mContext.enforceCallingOrSelfPermission(
                Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
    }

    /**
     * Enforce {@link android.Manifest.permission#MANAGE_SUBSCRIPTION_USER_ASSOCIATION} permission
     *
     * @param message Error message included in the exception.
     */
    private void enforceManageSubscriptionUserAssociation(String message) {
        mContext.enforceCallingOrSelfPermission(
                Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION, message);
    }

    /**
     * Get the subscription info by subscription id.
     *
     * @param subId The subscription id.
     *
     * @return The subscription info. {@code null} if not found.
     */
    @Nullable
    public SubscriptionInfoInternal getSubscriptionInfoInternal(int subId) {
        return mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subId);
    }

    /**
     * Log debug messages.
     *
Loading