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

Commit abcc76c2 authored by Jack Yu's avatar Jack Yu Committed by Automerger Merge Worker
Browse files

Added addSubInfo support am: 5aed8aec am: 97d54377

parents 3c62ecff 97d54377
Loading
Loading
Loading
Loading
+7 −1
Original line number Original line Diff line number Diff line
@@ -43,6 +43,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.metrics.CarrierIdMatchStats;
import com.android.internal.telephony.metrics.CarrierIdMatchStats;
import com.android.internal.telephony.metrics.TelephonyMetrics;
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.IccRecords;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.util.TelephonyUtils;
import com.android.internal.telephony.util.TelephonyUtils;
@@ -547,9 +548,14 @@ public class CarrierResolver extends Handler {
        // subscriptioninfo db to make sure we have correct carrier id set.
        // subscriptioninfo db to make sure we have correct carrier id set.
        if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId()) && !isSimOverride) {
        if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId()) && !isSimOverride) {
            // only persist carrier id to simInfo db when subId is valid.
            // 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());
                SubscriptionController.getInstance().setCarrierId(mCarrierId, mPhone.getSubId());
            }
            }
        }
        }
    }


    private static CarrierMatchingRule makeCarrierMatchingRule(Cursor cursor) {
    private static CarrierMatchingRule makeCarrierMatchingRule(Cursor cursor) {
        String certs = cursor.getString(
        String certs = cursor.getString(
+13 −2
Original line number Original line Diff line number Diff line
@@ -100,6 +100,7 @@ import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
import com.android.internal.telephony.imsphone.ImsPhoneMmiCode;
import com.android.internal.telephony.imsphone.ImsPhoneMmiCode;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.metrics.VoiceCallSessionStats;
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.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
import com.android.internal.telephony.uicc.IccCardStatus;
import com.android.internal.telephony.uicc.IccCardStatus;
@@ -340,8 +341,18 @@ public class GsmCdmaPhone extends Phone {
        mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
        mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
        mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, 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,
            SubscriptionController.getInstance().registerForUiccAppsEnabled(this,
                    EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false);
                    EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false);
        }


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


    protected SubscriptionManagerService mSubscriptionManagerService;

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


        mIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean(
        mIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_using_subscription_manager_service);
                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.
        // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
        mTelephonyComponentFactory = telephonyComponentFactory;
        mTelephonyComponentFactory = telephonyComponentFactory;
+217 −153
Original line number Original line Diff line number Diff line
@@ -49,7 +49,9 @@ import com.android.telephony.Rlog;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.AbstractMap;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Objects;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executor;
@@ -77,45 +79,6 @@ public class SubscriptionDatabaseManager extends Handler {
    /** Invalid database row index. */
    /** Invalid database row index. */
    private static final int INVALID_ROW_INDEX = -1;
    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. */
    /** The mapping from {@link SimInfo} table to {@link SubscriptionInfoInternal} get methods. */
    private static final Map<String, Function<SubscriptionInfoInternal, ?>>
    private static final Map<String, Function<SubscriptionInfoInternal, ?>>
            SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries(
            SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries(
@@ -265,6 +228,45 @@ public class SubscriptionDatabaseManager extends Handler {
                    SubscriptionInfoInternal::getUserId)
                    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}.
     * This is the callback used for listening events from {@link SubscriptionDatabaseManager}.
     */
     */
@@ -298,12 +300,25 @@ public class SubscriptionDatabaseManager extends Handler {
            mExecutor.execute(runnable);
            mExecutor.execute(runnable);
        }
        }


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

        /**
        /**
         * Called when subscription changed.
         * Called when subscription changed.
         *
         *
         * @param subId The subscription id.
         * @param subId The subscription id.
         */
         */
        public abstract void onSubscriptionChanged(int subId);
        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);
        super(looper);
        mContext = context;
        mContext = context;
        mCallback = callback;
        mCallback = callback;
        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
        mUiccController = UiccController.getInstance();
        mUiccController = UiccController.getInstance();
        loadFromDatabase();
        loadFromDatabase();
    }
    }
@@ -414,6 +428,11 @@ public class SubscriptionDatabaseManager extends Handler {
                    + "insert. subInfo=" + subInfo);
                    + "insert. subInfo=" + subInfo);
        }
        }


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

        int subId;
        int subId;
        // Grab the write lock so no other threads can read or write the cache.
        // Grab the write lock so no other threads can read or write the cache.
        mReadWriteLock.writeLock().lock();
        mReadWriteLock.writeLock().lock();
@@ -447,6 +466,12 @@ public class SubscriptionDatabaseManager extends Handler {
    private void updateDatabaseAsync(int subId, @NonNull ContentValues contentValues) {
    private void updateDatabaseAsync(int subId, @NonNull ContentValues contentValues) {
        logv("updateDatabaseAsync: prepare to update sub " + subId);
        logv("updateDatabaseAsync: prepare to update sub " + subId);
        // Perform the update in the handler thread asynchronously.
        // 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(() -> {
        post(() -> {
            int rowsUpdated = mContext.getContentResolver().update(Uri.withAppendedPath(
            int rowsUpdated = mContext.getContentResolver().update(Uri.withAppendedPath(
                    SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null);
                    SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null);
@@ -535,6 +560,10 @@ public class SubscriptionDatabaseManager extends Handler {
            if (oldSubInfo.equals(newSubInfo)) return;
            if (oldSubInfo.equals(newSubInfo)) return;
            mAllSubscriptionInfoInternalCache.put(subId, newSubInfo);
            mAllSubscriptionInfoInternalCache.put(subId, newSubInfo);
            mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
            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.
            // Writing into the database is slow. So do this asynchronously.
            updateDatabaseAsync(subId, createDeltaContentValues(oldSubInfo, newSubInfo));
            updateDatabaseAsync(subId, createDeltaContentValues(oldSubInfo, newSubInfo));
        } finally {
        } finally {
@@ -1176,6 +1205,8 @@ public class SubscriptionDatabaseManager extends Handler {
                                    .put(subInfo.getSubscriptionId(), subInfo);
                                    .put(subInfo.getSubscriptionId(), subInfo);
                        }
                        }
                    }
                    }
                    mDatabaseLoaded = true;
                    mCallback.invokeFromExecutor(mCallback::onDatabaseLoaded);
                    log("Loaded " + mAllSubscriptionInfoInternalCache.size()
                    log("Loaded " + mAllSubscriptionInfoInternalCache.size()
                            + " records from the subscription database.");
                            + " records from the subscription database.");
                } finally {
                } finally {
@@ -1311,7 +1342,7 @@ public class SubscriptionDatabaseManager extends Handler {
    /**
    /**
     * Get the subscription info by subscription id.
     * 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.
     * @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.
     * Log debug messages.
     *
     *
+241 −8
Original line number Original line Diff line number Diff line
@@ -16,9 +16,13 @@


package com.android.internal.telephony.subscription;
package com.android.internal.telephony.subscription;


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


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


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


/**
/**
 * The subscription manager service is the backend service of {@link SubscriptionManager}.
 * 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. */
    /** Whether enabling verbose debugging message or not. */
    private static final boolean VDBG = false;
    private static final boolean VDBG = false;


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

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


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


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


    /** The subscription database manager. */
    /** The subscription database manager. */
    @NonNull
    private final SubscriptionDatabaseManager mSubscriptionDatabaseManager;
    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.
     * 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
     * The constructor
@@ -151,13 +225,16 @@ public class SubscriptionManagerService extends ISub.Stub {
     * @param looper The looper for the handler.
     * @param looper The looper for the handler.
     */
     */
    public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) {
    public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) {
        sInstance = this;
        mContext = context;
        mContext = context;
        mHandler = new Handler(looper);
        mHandler = new Handler(looper);
        TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer =
        TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer =
                TelephonyFrameworkInitializer
                TelephonyFrameworkInitializer
                        .getTelephonyServiceManager()
                        .getTelephonyServiceManager()
                        .getSubscriptionServiceRegisterer();
                        .getSubscriptionServiceRegisterer();
        if (subscriptionServiceRegisterer.get() == null) {
            subscriptionServiceRegisterer.register(this);
            subscriptionServiceRegisterer.register(this);
        }


        // Create a separate thread for subscription database manager. The database will be updated
        // Create a separate thread for subscription database manager. The database will be updated
        // from a different thread.
        // from a different thread.
@@ -165,6 +242,14 @@ public class SubscriptionManagerService extends ISub.Stub {
        handlerThread.start();
        handlerThread.start();
        mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(context,
        mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(context,
                handlerThread.getLooper(), new SubscriptionDatabaseManagerCallback(mHandler::post) {
                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.
                     * Called when subscription changed.
                     *
                     *
@@ -172,6 +257,10 @@ public class SubscriptionManagerService extends ISub.Stub {
                     */
                     */
                    @Override
                    @Override
                    public void onSubscriptionChanged(int subId) {
                    public void onSubscriptionChanged(int subId) {
                        mSubscriptionManagerServiceCallbacks.forEach(
                                callback -> callback.invokeFromExecutor(
                                        () -> callback.onSubscriptionChanged(subId)));

                        MultiSimSettingController.getInstance().notifySubscriptionInfoChanged();
                        MultiSimSettingController.getInstance().notifySubscriptionInfoChanged();


                        TelephonyRegistryManager telephonyRegistryManager =
                        TelephonyRegistryManager telephonyRegistryManager =
@@ -190,9 +279,43 @@ public class SubscriptionManagerService extends ISub.Stub {
                        // TODO: Call TelephonyMetrics.updateActiveSubscriptionInfoList when active
                        // TODO: Call TelephonyMetrics.updateActiveSubscriptionInfoList when active
                        //  subscription changes.
                        //  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 callingPackage The package making the call.
     * @param callingFeatureId The feature in the package
     * @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
     * @param iccId ICCID of the SIM card.
     * subscription type
     * @param displayName human-readable name of the device the subscription corresponds to.
     * @param displayName human-readable name of the device the subscription corresponds to
     * @param slotIndex the logical SIM slot index assigned to this device.
     * @param slotIndex the slot assigned to this device
     * @param subscriptionType the type of subscription to be added
     * @param subscriptionType the type of subscription to be added
     *
     *
     * @return 0 if success, < 0 on error
     * @return 0 if success, < 0 on error
     */
     */
    @Override
    @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) {
            @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;
        return 0;

    }
    }


    /**
    /**
@@ -700,6 +873,66 @@ public class SubscriptionManagerService extends ISub.Stub {
        return null;
        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.
     * Log debug messages.
     *
     *
Loading