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

Commit bc4480ea authored by rambowang's avatar rambowang Committed by Rambo Wang
Browse files

Introduce CarrierConfigChangeListener API to monitor CC change

The new interface is used for system components and 3rd party apps
to monitor carrier config changes, replacing the current carrier config
change broadcast receivers which has known performance issue.

Bug: 244087782
Test: atest CarrierConfigManagerTest

Merged-In: I782e3aa2312886279cc7f449fa3a8238b4115407
Change-Id: I782e3aa2312886279cc7f449fa3a8238b4115407
(cherry picked from commit c5e36e1c)
parent 5b326816
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -41276,6 +41276,8 @@ package android.telephony {
    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, "carrier privileges"}) public android.os.PersistableBundle getConfigForSubId(int, @NonNull java.lang.String...);
    method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyConfigChangedForSubId(int);
    method public void registerCarrierConfigChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.CarrierConfigManager.CarrierConfigChangeListener);
    method public void unregisterCarrierConfigChangeListener(@NonNull android.telephony.CarrierConfigManager.CarrierConfigChangeListener);
    field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
    field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1
    field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2
@@ -41590,6 +41592,10 @@ package android.telephony {
    field public static final String KEY_PREFIX = "bsf.";
  }
  public static interface CarrierConfigManager.CarrierConfigChangeListener {
    method public void onCarrierConfigChanged(int, int, int, int);
  }
  public static final class CarrierConfigManager.Gps {
    field public static final String KEY_PERSIST_LPP_MODE_BOOL = "gps.persist_lpp_mode_bool";
    field public static final String KEY_PREFIX = "gps.";
+101 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.util.Log;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.listeners.ListenerExecutor;
import com.android.internal.telephony.ICarrierConfigChangeListener;
import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.ITelephonyRegistry;
@@ -54,8 +55,10 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

@@ -89,6 +92,14 @@ public class TelephonyRegistryManager {
            IOnSubscriptionsChangedListener> mOpportunisticSubscriptionChangedListenerMap
            = new HashMap<>();

    /**
     * A mapping between {@link CarrierConfigManager.CarrierConfigChangeListener} and its callback
     * ICarrierConfigChangeListener.
     */
    private final ConcurrentHashMap<CarrierConfigManager.CarrierConfigChangeListener,
                ICarrierConfigChangeListener>
            mCarrierConfigChangeListenerMap = new ConcurrentHashMap<>();


    /** @hide **/
    public TelephonyRegistryManager(@NonNull Context context) {
@@ -1409,4 +1420,94 @@ public class TelephonyRegistryManager {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Register a {@link android.telephony.CarrierConfigManager.CarrierConfigChangeListener} to get
     * notification when carrier configurations have changed.
     *
     * @param executor The executor on which the callback will be executed.
     * @param listener The CarrierConfigChangeListener to be registered with.
     */
    public void addCarrierConfigChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull CarrierConfigManager.CarrierConfigChangeListener listener) {
        Objects.requireNonNull(executor, "Executor should be non-null.");
        Objects.requireNonNull(listener, "Listener should be non-null.");
        if (mCarrierConfigChangeListenerMap.get(listener) != null) {
            Log.e(TAG, "registerCarrierConfigChangeListener: listener already present");
            return;
        }

        ICarrierConfigChangeListener callback = new ICarrierConfigChangeListener.Stub() {
            @Override
            public void onCarrierConfigChanged(int slotIndex, int subId, int carrierId,
                    int specificCarrierId) {
                Log.d(TAG, "onCarrierConfigChanged call in ICarrierConfigChangeListener callback");
                final long identify = Binder.clearCallingIdentity();
                try {
                    executor.execute(() -> listener.onCarrierConfigChanged(slotIndex, subId,
                            carrierId, specificCarrierId));
                } finally {
                    Binder.restoreCallingIdentity(identify);
                }
            }
        };

        try {
            sRegistry.addCarrierConfigChangeListener(callback,
                    mContext.getOpPackageName(), mContext.getAttributionTag());
            mCarrierConfigChangeListenerMap.put(listener, callback);
        } catch (RemoteException re) {
            // system server crashes
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Unregister to stop the notification when carrier configurations changed.
     *
     * @param listener The CarrierConfigChangeListener to be unregistered with.
     */
    public void removeCarrierConfigChangedListener(
            @NonNull CarrierConfigManager.CarrierConfigChangeListener listener) {
        Objects.requireNonNull(listener, "Listener should be non-null.");
        if (mCarrierConfigChangeListenerMap.get(listener) == null) {
            Log.e(TAG, "removeCarrierConfigChangedListener: listener was not present");
            return;
        }

        try {
            sRegistry.removeCarrierConfigChangeListener(
                    mCarrierConfigChangeListenerMap.get(listener), mContext.getOpPackageName());
            mCarrierConfigChangeListenerMap.remove(listener);
        } catch (RemoteException re) {
            // System sever crashes
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Notify the registrants the carrier configurations have changed.
     *
     * @param slotIndex         The SIM slot index on which to monitor and get notification.
     * @param subId             The subscription on the SIM slot. May be
     *                          {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
     * @param carrierId         The optional carrier Id, may be
     *                          {@link TelephonyManager#UNKNOWN_CARRIER_ID}.
     * @param specificCarrierId The optional specific carrier Id, may be {@link
     *                          TelephonyManager#UNKNOWN_CARRIER_ID}.
     */
    public void notifyCarrierConfigChanged(int slotIndex, int subId, int carrierId,
            int specificCarrierId) {
        // Only validate slotIndex, all others are optional and allowed to be invalid
        if (!SubscriptionManager.isValidPhoneId(slotIndex)) {
            Log.e(TAG, "notifyCarrierConfigChanged, ignored: invalid slotIndex " + slotIndex);
            return;
        }
        try {
            sRegistry.notifyCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }
}
+21 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony;

oneway interface ICarrierConfigChangeListener {
    void onCarrierConfigChanged(int slotIndex, int subId, int carrierId, int specificCarrierId);
}
 No newline at end of file
+5 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.telephony.PreciseDataConnectionState;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.emergency.EmergencyNumber;
import com.android.internal.telephony.ICarrierConfigChangeListener;
import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -109,4 +110,8 @@ interface ITelephonyRegistry {
            int phoneId, in List<String> privilegedPackageNames, in int[] privilegedUids);
    void notifyCarrierServiceChanged(int phoneId, in String packageName, int uid);

    void addCarrierConfigChangeListener(ICarrierConfigChangeListener listener,
            String pkg, String featureId);
    void removeCarrierConfigChangeListener(ICarrierConfigChangeListener listener, String pkg);
    void notifyCarrierConfigChanged(int phoneId, int subId, int carrierId, int specificCarrierId);
}
+83 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ import android.util.Pair;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.ICarrierConfigChangeListener;
import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.IPhoneStateListener;
@@ -154,6 +155,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
        IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
        IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback;
        ICarrierPrivilegesCallback carrierPrivilegesCallback;
        ICarrierConfigChangeListener carrierConfigChangeListener;

        int callerUid;
        int callerPid;
@@ -182,6 +184,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
            return carrierPrivilegesCallback != null;
        }

        boolean matchCarrierConfigChangeListener() {
            return carrierConfigChangeListener != null;
        }

        boolean canReadCallLog() {
            try {
                return TelephonyPermissions.checkReadCallLog(
@@ -200,6 +206,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
                    + " onOpportunisticSubscriptionsChangedListenererCallback="
                    + onOpportunisticSubscriptionsChangedListenerCallback
                    + " carrierPrivilegesCallback=" + carrierPrivilegesCallback
                    + " carrierConfigChangeListener=" + carrierConfigChangeListener
                    + " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}";
        }
    }
@@ -2956,6 +2963,82 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
        }
    }

    @Override
    public void addCarrierConfigChangeListener(ICarrierConfigChangeListener listener,
            String pkg, String featureId) {
        final int callerUserId = UserHandle.getCallingUserId();
        mAppOps.checkPackage(Binder.getCallingUid(), pkg);
        if (VDBG) {
            log("addCarrierConfigChangeListener pkg=" + pii(pkg) + " uid=" + Binder.getCallingUid()
                    + " myUserId=" + UserHandle.myUserId() + " callerUerId" + callerUserId
                    + " listener=" + listener + " listener.asBinder=" + listener.asBinder());
        }

        synchronized (mRecords) {
            IBinder b = listener.asBinder();
            boolean doesLimitApply = doesLimitApplyForListeners(Binder.getCallingUid(),
                    Process.myUid());
            Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply);

            if (r == null) {
                loge("Can not create Record instance!");
                return;
            }

            r.context = mContext;
            r.carrierConfigChangeListener = listener;
            r.callingPackage = pkg;
            r.callingFeatureId = featureId;
            r.callerUid = Binder.getCallingUid();
            r.callerPid = Binder.getCallingPid();
            r.eventList = new ArraySet<>();
            if (DBG) {
                log("addCarrierConfigChangeListener:  Register r=" + r);
            }
        }
    }

    @Override
    public void removeCarrierConfigChangeListener(ICarrierConfigChangeListener listener,
            String pkg) {
        if (DBG) log("removeCarrierConfigChangeListener listener=" + listener + ", pkg=" + pkg);
        mAppOps.checkPackage(Binder.getCallingUid(), pkg);
        remove(listener.asBinder());
    }

    @Override
    public void notifyCarrierConfigChanged(int phoneId, int subId, int carrierId,
            int specificCarrierId) {
        if (!validatePhoneId(phoneId)) {
            throw new IllegalArgumentException("Invalid phoneId: " + phoneId);
        }
        if (!checkNotifyPermission("notifyCarrierConfigChanged")) {
            loge("Caller has no notify permission!");
            return;
        }
        if (VDBG) {
            log("notifyCarrierConfigChanged: phoneId=" + phoneId + ", subId=" + subId
                    + ", carrierId=" + carrierId + ", specificCarrierId=" + specificCarrierId);
        }

        synchronized (mRecords) {
            mRemoveList.clear();
            for (Record r : mRecords) {
                // Listeners are "global", neither per-slot nor per-sub, so no idMatch check here
                if (!r.matchCarrierConfigChangeListener()) {
                    continue;
                }
                try {
                    r.carrierConfigChangeListener.onCarrierConfigChanged(phoneId, subId, carrierId,
                            specificCarrierId);
                } catch (RemoteException re) {
                    mRemoveList.add(r.binder);
                }
            }
            handleRemoveListLocked();
        }
    }

    @NeverCompile // Avoid size overhead of debugging code.
    @Override
    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Loading