Merge "Introduce CarrierConfigChangeListener API to monitor CC change"

This commit is contained in:
Rambo Wang 2023-03-09 00:49:59 +00:00 committed by Gerrit Code Review
commit e302b2a385
6 changed files with 299 additions and 0 deletions

View File

@ -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.";

View File

@ -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();
}
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 + "}";
}
}
@ -2955,6 +2962,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) {

View File

@ -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;
/**
@ -9726,4 +9728,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);
}
}