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

Commit 74eaf2cc authored by Jack Yu's avatar Jack Yu
Browse files

Notify subscription info changed

Notify clients when subscription info changes.

Bug: 239607619
Test: Manual
Change-Id: I7c3e133cb0b00a0118583ca67e5b54239f28ea7d
parent 959c1281
Loading
Loading
Loading
Loading
+6 −8
Original line number Diff line number Diff line
@@ -439,14 +439,12 @@ public class MultiSimSettingController extends Handler {
        // being specified in it. So here we do additional check to make sur we don't miss the
        // subId.
        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
            int[] subIds = mSubController.getSubIds(phoneId);
            if (!ArrayUtils.isEmpty(subIds)) {
                CarrierConfigManager cm = (CarrierConfigManager) mContext.getSystemService(
                        mContext.CARRIER_CONFIG_SERVICE);
                if (cm != null && cm.getConfigForSubId(subIds[0]) != null) {
                    loge("onCarrierConfigChanged with invalid subId while subd "
                            + subIds[0] + " is active and its config is loaded");
                    subId = subIds[0];
            subId = mSubController.getSubId(phoneId);
            if (SubscriptionManager.isValidSubscriptionId(subId)) {
                CarrierConfigManager cm = mContext.getSystemService(CarrierConfigManager.class);
                if (cm != null && cm.getConfigForSubId(subId) != null) {
                    loge("onCarrierConfigChanged with invalid subId while subId "
                            + subId + " is active and its config is loaded");
                }
            }
        }
+2 −1
Original line number Diff line number Diff line
@@ -201,7 +201,8 @@ public class PhoneFactory {
                if (sContext.getResources().getBoolean(
                        com.android.internal.R.bool.config_using_subscription_manager_service)) {
                    Rlog.i(LOG_TAG, "Creating SubscriptionManagerService");
                    sSubscriptionManagerService = new SubscriptionManagerService(context);
                    sSubscriptionManagerService = new SubscriptionManagerService(context,
                            Looper.myLooper());
                } else {
                    Rlog.i(LOG_TAG, "Creating SubscriptionController");
                    TelephonyComponentFactory.getInstance().inject(SubscriptionController.class
+72 −16
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.internal.telephony.subscription;

import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentValues;
@@ -41,6 +42,7 @@ import android.util.IndentingPrintWriter;
import android.util.LocalLog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.uicc.UiccController;
import com.android.telephony.Rlog;

@@ -50,6 +52,7 @@ import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.BiFunction;
@@ -78,6 +81,10 @@ public class SubscriptionDatabaseManager extends Handler {
    @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;

@@ -258,15 +265,59 @@ public class SubscriptionDatabaseManager extends Handler {
                            SubscriptionInfoInternal::getUserId)
                    );

    /**
     * This is the callback used for listening events from {@link SubscriptionDatabaseManager}.
     */
    public abstract static class SubscriptionDatabaseManagerCallback {
        /** The executor of the callback. */
        private final @NonNull Executor mExecutor;

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

        /**
         * @return The executor of the callback.
         */
        @VisibleForTesting
        public @NonNull 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 abstract void onSubscriptionChanged(int subId);
    }

    /**
     * The constructor.
     *
     * @param context The context.
     * @param looper Looper for the handler.
     * @param callback Subscription database callback.
     */
    public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper) {
    public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper,
            @NonNull SubscriptionDatabaseManagerCallback callback) {
        super(looper);
        mContext = context;
        mCallback = callback;
        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
        mUiccController = UiccController.getInstance();
        loadFromDatabase();
@@ -382,6 +433,8 @@ public class SubscriptionDatabaseManager extends Handler {
        } finally {
            mReadWriteLock.writeLock().unlock();
        }

        mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
        return subId;
    }

@@ -425,20 +478,20 @@ public class SubscriptionDatabaseManager extends Handler {
            BiFunction<SubscriptionInfoInternal.Builder, T, SubscriptionInfoInternal.Builder>
                    builderSetMethod) {
        ContentValues contentValues = new ContentValues();
        SubscriptionInfoInternal subInfoCache;
        SubscriptionInfoInternal oldSubInfo;

        // Grab the write lock so no other threads can read or write the cache.
        mReadWriteLock.writeLock().lock();
        try {
            subInfoCache = mAllSubscriptionInfoInternalCache.get(subId);
            if (subInfoCache != null) {
            oldSubInfo = mAllSubscriptionInfoInternalCache.get(subId);
            if (oldSubInfo != null) {
                // Check if the new value is different from the old value in the cache.
                if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfoCache, columnName),
                if (!Objects.equals(getSubscriptionInfoFieldByColumnName(oldSubInfo, columnName),
                        newValue)) {
                    // If the value is different, then we need to update the cache. Since all fields
                    // in SubscriptionInfo is final, so we need to create a new SubscriptionInfo.
                    SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal
                            .Builder(subInfoCache);
                            .Builder(oldSubInfo);

                    // Apply the new value to the builder. This line is equivalent to
                    // builder.setXxxxxx(newValue);
@@ -446,6 +499,7 @@ public class SubscriptionDatabaseManager extends Handler {

                    // Update the subscription database cache.
                    mAllSubscriptionInfoInternalCache.put(subId, builder.build());
                    mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));

                    // Prepare the content value for update.
                    contentValues.putObject(columnName, newValue);
@@ -461,26 +515,28 @@ public class SubscriptionDatabaseManager extends Handler {
    }

    /**
     * Update the database with the {@link SubscriptionInfo}, and also update the cache.
     * Update the database with the {@link SubscriptionInfoInternal}, and also update the cache.
     *
     * @param subInfo The new {@link SubscriptionInfo}.
     * @param newSubInfo The new {@link SubscriptionInfoInternal}.
     */
    public void updateSubscription(@NonNull SubscriptionInfoInternal subInfo) {
        Objects.requireNonNull(subInfo);
    public void updateSubscription(@NonNull SubscriptionInfoInternal newSubInfo) {
        Objects.requireNonNull(newSubInfo);

        // Grab the write lock so no other threads can read or write the cache.
        mReadWriteLock.writeLock().lock();
        try {
            int subId = subInfo.getSubscriptionId();
            SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(
                    subInfo.getSubscriptionId());
            if (subInfoCache == null) {
            int subId = newSubInfo.getSubscriptionId();
            SubscriptionInfoInternal oldSubInfo = mAllSubscriptionInfoInternalCache.get(
                    newSubInfo.getSubscriptionId());
            if (oldSubInfo == null) {
                throw new RuntimeException("updateSubscription: subscription does not exist. subId="
                        + subId);
            }
            mAllSubscriptionInfoInternalCache.put(subId, subInfo);
            if (oldSubInfo.equals(newSubInfo)) return;
            mAllSubscriptionInfoInternalCache.put(subId, newSubInfo);
            mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
            // Writing into the database is slow. So do this asynchronously.
            updateDatabaseAsync(subId, createDeltaContentValues(subInfoCache, subInfo));
            updateDatabaseAsync(subId, createDeltaContentValues(oldSubInfo, newSubInfo));
        } finally {
            mReadWriteLock.writeLock().unlock();
        }
+38 −2
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@ package com.android.internal.telephony.subscription;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.TelephonyServiceManager;
import android.os.UserHandle;
@@ -28,11 +30,14 @@ import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.SubscriptionManager.SubscriptionType;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyRegistryManager;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;

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.telephony.Rlog;

import java.io.FileDescriptor;
@@ -56,6 +61,9 @@ public class SubscriptionManagerService extends ISub.Stub {
    /** The context */
    private final Context mContext;

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

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

@@ -140,9 +148,11 @@ public class SubscriptionManagerService extends ISub.Stub {
     * The constructor
     *
     * @param context The context
     * @param looper The looper for the handler.
     */
    public SubscriptionManagerService(@NonNull Context context) {
    public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) {
        mContext = context;
        mHandler = new Handler(looper);
        TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer =
                TelephonyFrameworkInitializer
                        .getTelephonyServiceManager()
@@ -154,7 +164,33 @@ public class SubscriptionManagerService extends ISub.Stub {
        HandlerThread handlerThread = new HandlerThread(LOG_TAG);
        handlerThread.start();
        mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(context,
                handlerThread.getLooper());
                handlerThread.getLooper(), new SubscriptionDatabaseManagerCallback(mHandler::post) {
                    /**
                     * Called when subscription changed.
                     *
                     * @param subId The subscription id.
                     */
                    @Override
                    public void onSubscriptionChanged(int subId) {
                        MultiSimSettingController.getInstance().notifySubscriptionInfoChanged();

                        TelephonyRegistryManager telephonyRegistryManager =
                                mContext.getSystemService(TelephonyRegistryManager.class);
                        if (telephonyRegistryManager != null) {
                            telephonyRegistryManager.notifySubscriptionInfoChanged();
                        }

                        SubscriptionInfoInternal subInfo =
                                mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subId);
                        if (subInfo != null && subInfo.isOpportunistic()
                                && telephonyRegistryManager != null) {
                            telephonyRegistryManager.notifyOpportunisticSubscriptionInfoChanged();
                        }

                        // TODO: Call TelephonyMetrics.updateActiveSubscriptionInfoList when active
                        //  subscription changes.
                    }
                });
    }

    /**
+1 −1
Original line number Diff line number Diff line
@@ -848,7 +848,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest {

        // Still notify carrier config without specifying subId2, but this time subController
        // and CarrierConfigManager have subId 2 active and ready.
        doReturn(new int[] {2}).when(mSubControllerMock).getSubIds(1);
        doReturn(2).when(mSubControllerMock).getSubId(1);
        CarrierConfigManager cm = (CarrierConfigManager) mContext.getSystemService(
                mContext.CARRIER_CONFIG_SERVICE);
        doReturn(new PersistableBundle()).when(cm).getConfigForSubId(2);
Loading