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 c5e36e1c1f)
This commit is contained in:
@@ -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.";
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.telephony;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -53,6 +54,7 @@ import com.android.telephony.Rlog;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -9715,4 +9717,85 @@ public class CarrierConfigManager {
|
||||
configs.putPersistableBundle(key, (PersistableBundle) value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener interface to get a notification when the carrier configurations have changed.
|
||||
*
|
||||
* Use this listener to receive timely updates when the carrier configuration changes. System
|
||||
* components should prefer this listener over {@link #ACTION_CARRIER_CONFIG_CHANGED}
|
||||
* whenever possible.
|
||||
*
|
||||
* To register the listener, call
|
||||
* {@link #registerCarrierConfigChangeListener(Executor, CarrierConfigChangeListener)}.
|
||||
* To unregister, call
|
||||
* {@link #unregisterCarrierConfigChangeListener(CarrierConfigChangeListener)}.
|
||||
*
|
||||
* Note that on registration, registrants will NOT receive a notification on last carrier config
|
||||
* change. Only carrier configs change AFTER the registration will be sent to registrants. And
|
||||
* unlike {@link #ACTION_CARRIER_CONFIG_CHANGED}, notification wouldn't send when the device is
|
||||
* unlocked. Registrants only receive the notification when there has been real carrier config
|
||||
* changes.
|
||||
*
|
||||
* @see #registerCarrierConfigChangeListener(Executor, CarrierConfigChangeListener)
|
||||
* @see #unregisterCarrierConfigChangeListener(CarrierConfigChangeListener)
|
||||
* @see #ACTION_CARRIER_CONFIG_CHANGED
|
||||
* @see #getConfig(String...)
|
||||
* @see #getConfigForSubId(int, String...)
|
||||
*/
|
||||
public interface CarrierConfigChangeListener {
|
||||
/**
|
||||
* Called when carrier configurations have changed.
|
||||
*
|
||||
* @param logicalSlotIndex The logical SIM slot index on which to monitor and get
|
||||
* notification. It is guaranteed to be valid.
|
||||
* @param subscriptionId 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}.
|
||||
* See {@link TelephonyManager#getSimCarrierId()}.
|
||||
* @param specificCarrierId The optional fine-grained carrierId, may be {@link
|
||||
* TelephonyManager#UNKNOWN_CARRIER_ID}. A specific carrierId may
|
||||
* be different from the carrierId above in a MVNO scenario. See
|
||||
* detail in {@link TelephonyManager#getSimSpecificCarrierId()}.
|
||||
*/
|
||||
void onCarrierConfigChanged(int logicalSlotIndex, int subscriptionId, int carrierId,
|
||||
int specificCarrierId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link CarrierConfigChangeListener} to get a notification when carrier
|
||||
* configurations have changed.
|
||||
*
|
||||
* @param executor The executor on which the listener will be called.
|
||||
* @param listener The CarrierConfigChangeListener called when carrier configs has changed.
|
||||
*/
|
||||
public void registerCarrierConfigChangeListener(@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull CarrierConfigChangeListener listener) {
|
||||
Objects.requireNonNull(executor, "Executor should be non-null.");
|
||||
Objects.requireNonNull(listener, "Listener should be non-null.");
|
||||
|
||||
TelephonyRegistryManager trm = mContext.getSystemService(TelephonyRegistryManager.class);
|
||||
if (trm == null) {
|
||||
throw new IllegalStateException("Telephony registry service is null");
|
||||
}
|
||||
trm.addCarrierConfigChangedListener(executor, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister the {@link CarrierConfigChangeListener} to stop notification on carrier
|
||||
* configurations change.
|
||||
*
|
||||
* @param listener The CarrierConfigChangeListener which was registered with method
|
||||
* {@link #registerCarrierConfigChangeListener(Executor, CarrierConfigChangeListener)}.
|
||||
*/
|
||||
public void unregisterCarrierConfigChangeListener(
|
||||
@NonNull CarrierConfigChangeListener listener) {
|
||||
Objects.requireNonNull(listener, "Listener should be non-null.");
|
||||
|
||||
TelephonyRegistryManager trm = mContext.getSystemService(TelephonyRegistryManager.class);
|
||||
if (trm == null) {
|
||||
throw new IllegalStateException("Telephony registry service is null");
|
||||
}
|
||||
trm.removeCarrierConfigChangedListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user