diff options
| -rw-r--r-- | core/api/system-current.txt | 15 | ||||
| -rw-r--r-- | core/java/android/telephony/TelephonyRegistryManager.java | 203 | ||||
| -rw-r--r-- | core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl (renamed from core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl) | 3 | ||||
| -rw-r--r-- | core/java/com/android/internal/telephony/ITelephonyRegistry.aidl | 10 | ||||
| -rw-r--r-- | services/core/java/com/android/server/TelephonyRegistry.java | 85 | ||||
| -rw-r--r-- | telephony/java/android/telephony/TelephonyManager.java | 106 |
6 files changed, 359 insertions, 63 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 8040a67c5e0e..0b5e7279f38c 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -13340,7 +13340,7 @@ package android.telephony { } public class TelephonyManager { - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addCarrierPrivilegesListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addCarrierPrivilegesListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) @WorkerThread public void bootstrapAuthenticationRequest(int, @NonNull android.net.Uri, @NonNull android.telephony.gba.UaSecurityProtocolIdentifier, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.BootstrapAuthenticationCallback); method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String); @@ -13440,7 +13440,8 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled(); method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot(); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerCarrierPrivilegesCallback(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback); + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>); @@ -13490,6 +13491,7 @@ package android.telephony { method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterCarrierPrivilegesCallback(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback); method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor); method public void updateServiceLocation(); field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED"; @@ -13595,8 +13597,13 @@ package android.telephony { field public static final int RESULT_SUCCESS = 0; // 0x0 } - public static interface TelephonyManager.CarrierPrivilegesListener { - method public void onCarrierPrivilegesChanged(@NonNull java.util.List<java.lang.String>, @NonNull int[]); + public static interface TelephonyManager.CarrierPrivilegesCallback { + method public void onCarrierPrivilegesChanged(@NonNull java.util.Set<java.lang.String>, @NonNull java.util.Set<java.lang.Integer>); + method public default void onCarrierServiceChanged(@Nullable String, int); + } + + @Deprecated public static interface TelephonyManager.CarrierPrivilegesListener { + method @Deprecated public void onCarrierPrivilegesChanged(@NonNull java.util.List<java.lang.String>, @NonNull int[]); } public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception { diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index c1fcd664f6fa..f8445921d3b0 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -27,6 +27,7 @@ import android.os.Binder; import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; +import android.service.carrier.CarrierService; import android.telephony.Annotation.CallState; import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.DisconnectCauses; @@ -36,6 +37,7 @@ import android.telephony.Annotation.PreciseDisconnectCauses; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; +import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.telephony.TelephonyManager.CarrierPrivilegesListener; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; @@ -44,17 +46,19 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.listeners.ListenerExecutor; -import com.android.internal.telephony.ICarrierPrivilegesListener; +import com.android.internal.telephony.ICarrierPrivilegesCallback; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.ITelephonyRegistry; import java.lang.ref.WeakReference; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.Executor; +import java.util.stream.Collectors; /** * A centralized place to notify telephony related status changes, e.g, {@link ServiceState} update @@ -1260,34 +1264,78 @@ public class TelephonyRegistryManager { pkgName, attributionTag, callback, new int[0], notifyNow); } - private static class CarrierPrivilegesListenerWrapper extends ICarrierPrivilegesListener.Stub + // TODO(b/216549778): Remove listener logic once all clients switch to CarrierPrivilegesCallback + private static class CarrierPrivilegesCallbackWrapper extends ICarrierPrivilegesCallback.Stub implements ListenerExecutor { - private final WeakReference<CarrierPrivilegesListener> mListener; - private final Executor mExecutor; + // Either mListener or mCallback may be null, never both + @Nullable private final WeakReference<CarrierPrivilegesListener> mListener; + @Nullable private final WeakReference<CarrierPrivilegesCallback> mCallback; + @NonNull private final Executor mExecutor; + + CarrierPrivilegesCallbackWrapper( + @NonNull CarrierPrivilegesCallback callback, @NonNull Executor executor) { + mListener = null; + mCallback = new WeakReference<>(callback); + mExecutor = executor; + } - CarrierPrivilegesListenerWrapper(CarrierPrivilegesListener listener, Executor executor) { + CarrierPrivilegesCallbackWrapper( + @NonNull CarrierPrivilegesListener listener, @NonNull Executor executor) { mListener = new WeakReference<>(listener); + mCallback = null; mExecutor = executor; } @Override public void onCarrierPrivilegesChanged( - List<String> privilegedPackageNames, int[] privilegedUids) { - Binder.withCleanCallingIdentity( - () -> - executeSafely( - mExecutor, - mListener::get, - cpl -> - cpl.onCarrierPrivilegesChanged( - privilegedPackageNames, privilegedUids))); + @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids) { + if (mListener != null) { + Binder.withCleanCallingIdentity( + () -> + executeSafely( + mExecutor, + mListener::get, + cpl -> + cpl.onCarrierPrivilegesChanged( + privilegedPackageNames, privilegedUids))); + } + + if (mCallback != null) { + // AIDL interface does not support Set, keep the List/Array and translate them here + Set<String> privilegedPkgNamesSet = Set.copyOf(privilegedPackageNames); + Set<Integer> privilegedUidsSet = Arrays.stream(privilegedUids).boxed().collect( + Collectors.toSet()); + Binder.withCleanCallingIdentity( + () -> + executeSafely( + mExecutor, + mCallback::get, + cpc -> + cpc.onCarrierPrivilegesChanged( + privilegedPkgNamesSet, privilegedUidsSet))); + } + } + + @Override + public void onCarrierServiceChanged(@Nullable String packageName, int uid) { + if (mCallback != null) { + Binder.withCleanCallingIdentity( + () -> + executeSafely( + mExecutor, + mCallback::get, + cpc -> cpc.onCarrierServiceChanged(packageName, uid))); + } } } - @GuardedBy("sCarrierPrivilegeListeners") - private static final WeakHashMap< - CarrierPrivilegesListener, WeakReference<CarrierPrivilegesListenerWrapper>> - sCarrierPrivilegeListeners = new WeakHashMap<>(); + // TODO(b/216549778): Change the map key to CarrierPrivilegesCallback once all clients switch to + // CarrierPrivilegesCallback. Before that, the key is either CarrierPrivilegesCallback or + // CarrierPrivilegesListener, no logic actually depends on the type. + @NonNull + @GuardedBy("sCarrierPrivilegeCallbacks") + private static final WeakHashMap<Object, WeakReference<CarrierPrivilegesCallbackWrapper>> + sCarrierPrivilegeCallbacks = new WeakHashMap<>(); /** * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to @@ -1297,7 +1345,11 @@ public class TelephonyRegistryManager { * @param logicalSlotIndex The SIM slot to listen on * @param executor The executor where {@code listener} will be invoked * @param listener The callback to register + * + * @deprecated Use {@link #addCarrierPrivilegesCallback} instead. This API will be removed + * prior to API finalization. */ + @Deprecated public void addCarrierPrivilegesListener( int logicalSlotIndex, @NonNull @CallbackExecutor Executor executor, @@ -1305,18 +1357,18 @@ public class TelephonyRegistryManager { if (listener == null || executor == null) { throw new IllegalArgumentException("listener and executor must be non-null"); } - synchronized (sCarrierPrivilegeListeners) { - WeakReference<CarrierPrivilegesListenerWrapper> existing = - sCarrierPrivilegeListeners.get(listener); + synchronized (sCarrierPrivilegeCallbacks) { + WeakReference<CarrierPrivilegesCallbackWrapper> existing = + sCarrierPrivilegeCallbacks.get(listener); if (existing != null && existing.get() != null) { Log.d(TAG, "addCarrierPrivilegesListener: listener already registered"); return; } - CarrierPrivilegesListenerWrapper wrapper = - new CarrierPrivilegesListenerWrapper(listener, executor); - sCarrierPrivilegeListeners.put(listener, new WeakReference<>(wrapper)); + CarrierPrivilegesCallbackWrapper wrapper = + new CarrierPrivilegesCallbackWrapper(listener, executor); + sCarrierPrivilegeCallbacks.put(listener, new WeakReference<>(wrapper)); try { - sRegistry.addCarrierPrivilegesListener( + sRegistry.addCarrierPrivilegesCallback( logicalSlotIndex, wrapper, mContext.getOpPackageName(), @@ -1331,19 +1383,84 @@ public class TelephonyRegistryManager { * Unregisters a {@link CarrierPrivilegesListener}. * * @param listener The callback to unregister + * + * @deprecated Use {@link #removeCarrierPrivilegesCallback} instead. The callback will prior + * to API finalization. */ + @Deprecated public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must be non-null"); } - synchronized (sCarrierPrivilegeListeners) { - WeakReference<CarrierPrivilegesListenerWrapper> ref = - sCarrierPrivilegeListeners.remove(listener); + synchronized (sCarrierPrivilegeCallbacks) { + WeakReference<CarrierPrivilegesCallbackWrapper> ref = + sCarrierPrivilegeCallbacks.remove(listener); if (ref == null) return; - CarrierPrivilegesListenerWrapper wrapper = ref.get(); + CarrierPrivilegesCallbackWrapper wrapper = ref.get(); if (wrapper == null) return; try { - sRegistry.removeCarrierPrivilegesListener(wrapper, mContext.getOpPackageName()); + sRegistry.removeCarrierPrivilegesCallback(wrapper, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to + * receive callbacks when the set of packages with carrier privileges changes. The callback will + * immediately be called with the latest state. + * + * @param logicalSlotIndex The SIM slot to listen on + * @param executor The executor where {@code listener} will be invoked + * @param callback The callback to register + */ + public void addCarrierPrivilegesCallback( + int logicalSlotIndex, + @NonNull @CallbackExecutor Executor executor, + @NonNull CarrierPrivilegesCallback callback) { + if (callback == null || executor == null) { + throw new IllegalArgumentException("callback and executor must be non-null"); + } + synchronized (sCarrierPrivilegeCallbacks) { + WeakReference<CarrierPrivilegesCallbackWrapper> existing = + sCarrierPrivilegeCallbacks.get(callback); + if (existing != null && existing.get() != null) { + Log.d(TAG, "addCarrierPrivilegesCallback: callback already registered"); + return; + } + CarrierPrivilegesCallbackWrapper wrapper = + new CarrierPrivilegesCallbackWrapper(callback, executor); + sCarrierPrivilegeCallbacks.put(callback, new WeakReference<>(wrapper)); + try { + sRegistry.addCarrierPrivilegesCallback( + logicalSlotIndex, + wrapper, + mContext.getOpPackageName(), + mContext.getAttributionTag()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Unregisters a {@link CarrierPrivilegesCallback}. + * + * @param callback The callback to unregister + */ + public void removeCarrierPrivilegesCallback(@NonNull CarrierPrivilegesCallback callback) { + if (callback == null) { + throw new IllegalArgumentException("listener must be non-null"); + } + synchronized (sCarrierPrivilegeCallbacks) { + WeakReference<CarrierPrivilegesCallbackWrapper> ref = + sCarrierPrivilegeCallbacks.remove(callback); + if (ref == null) return; + CarrierPrivilegesCallbackWrapper wrapper = ref.get(); + if (wrapper == null) return; + try { + sRegistry.removeCarrierPrivilegesCallback(wrapper, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1359,15 +1476,33 @@ public class TelephonyRegistryManager { */ public void notifyCarrierPrivilegesChanged( int logicalSlotIndex, - @NonNull List<String> privilegedPackageNames, - @NonNull int[] privilegedUids) { + @NonNull Set<String> privilegedPackageNames, + @NonNull Set<Integer> privilegedUids) { if (privilegedPackageNames == null || privilegedUids == null) { throw new IllegalArgumentException( "privilegedPackageNames and privilegedUids must be non-null"); } try { - sRegistry.notifyCarrierPrivilegesChanged( - logicalSlotIndex, privilegedPackageNames, privilegedUids); + // AIDL doesn't support Set yet. Convert Set to List/Array + List<String> pkgList = List.copyOf(privilegedPackageNames); + int[] uids = privilegedUids.stream().mapToInt(Number::intValue).toArray(); + sRegistry.notifyCarrierPrivilegesChanged(logicalSlotIndex, pkgList, uids); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Notify listeners that the {@link CarrierService} for current user has changed. + * + * @param logicalSlotIndex the SIM slot the change occurred on + * @param packageName the package name of the changed {@link CarrierService} + * @param uid the UID of the changed {@link CarrierService} + */ + public void notifyCarrierServiceChanged(int logicalSlotIndex, @Nullable String packageName, + int uid) { + try { + sRegistry.notifyCarrierServiceChanged(logicalSlotIndex, packageName, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl b/core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl index 6ca8cecba3c8..0c8e73fb2b67 100644 --- a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl +++ b/core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl @@ -16,7 +16,8 @@ package com.android.internal.telephony; -oneway interface ICarrierPrivilegesListener { +oneway interface ICarrierPrivilegesCallback { void onCarrierPrivilegesChanged( in List<String> privilegedPackageNames, in int[] privilegedUids); + void onCarrierServiceChanged(in String carrierServicePackageName, in int carrierServiceUid); } diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 9712d7e38a4b..c7fa757ac0b7 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -32,7 +32,7 @@ import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.emergency.EmergencyNumber; -import com.android.internal.telephony.ICarrierPrivilegesListener; +import com.android.internal.telephony.ICarrierPrivilegesCallback; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; @@ -102,9 +102,11 @@ interface ITelephonyRegistry { void notifyLinkCapacityEstimateChanged(in int phoneId, in int subId, in List<LinkCapacityEstimate> linkCapacityEstimateList); - void addCarrierPrivilegesListener( - int phoneId, ICarrierPrivilegesListener callback, String pkg, String featureId); - void removeCarrierPrivilegesListener(ICarrierPrivilegesListener callback, String pkg); + void addCarrierPrivilegesCallback( + int phoneId, ICarrierPrivilegesCallback callback, String pkg, String featureId); + void removeCarrierPrivilegesCallback(ICarrierPrivilegesCallback callback, String pkg); void notifyCarrierPrivilegesChanged( int phoneId, in List<String> privilegedPackageNames, in int[] privilegedUids); + void notifyCarrierServiceChanged(int phoneId, in String packageName, int uid); + } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 58fa9fb28a78..839cdc6eaca3 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -91,7 +91,7 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; -import com.android.internal.telephony.ICarrierPrivilegesListener; +import com.android.internal.telephony.ICarrierPrivilegesCallback; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.ITelephonyRegistry; @@ -153,7 +153,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { IPhoneStateListener callback; IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback; IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback; - ICarrierPrivilegesListener carrierPrivilegesListener; + ICarrierPrivilegesCallback carrierPrivilegesCallback; int callerUid; int callerPid; @@ -178,8 +178,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return (onOpportunisticSubscriptionsChangedListenerCallback != null); } - boolean matchCarrierPrivilegesListener() { - return carrierPrivilegesListener != null; + boolean matchCarrierPrivilegesCallback() { + return carrierPrivilegesCallback != null; } boolean canReadCallLog() { @@ -199,7 +199,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { + onSubscriptionsChangedListenerCallback + " onOpportunisticSubscriptionsChangedListenererCallback=" + onOpportunisticSubscriptionsChangedListenerCallback - + " carrierPrivilegesListener=" + carrierPrivilegesListener + + " carrierPrivilegesCallback=" + carrierPrivilegesCallback + " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}"; } } @@ -414,7 +414,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPreciseDataConnectionStates; /** Per-phoneId snapshot of privileged packages (names + UIDs). */ - private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates; + @NonNull private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates; + /** Per-phoneId of CarrierService (PackageName, UID) pair. */ + @NonNull private List<Pair<String, Integer>> mCarrierServiceStates; /** * Support backward compatibility for {@link android.telephony.TelephonyDisplayInfo}. @@ -705,6 +707,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { cutListToSize(mPhysicalChannelConfigs, mNumPhones); cutListToSize(mLinkCapacityEstimateLists, mNumPhones); cutListToSize(mCarrierPrivilegeStates, mNumPhones); + cutListToSize(mCarrierServiceStates, mNumPhones); return; } @@ -746,6 +749,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); + mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID)); } } } @@ -813,6 +817,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataEnabledReason = new int[numPhones]; mLinkCapacityEstimateLists = new ArrayList<>(); mCarrierPrivilegeStates = new ArrayList<>(); + mCarrierServiceStates = new ArrayList<>(); for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; @@ -851,6 +856,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); + mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID)); } mAppOps = mContext.getSystemService(AppOpsManager.class); @@ -2784,16 +2790,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override - public void addCarrierPrivilegesListener( + public void addCarrierPrivilegesCallback( int phoneId, - ICarrierPrivilegesListener callback, - String callingPackage, - String callingFeatureId) { + @NonNull ICarrierPrivilegesCallback callback, + @NonNull String callingPackage, + @NonNull String callingFeatureId) { int callerUserId = UserHandle.getCallingUserId(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, - "addCarrierPrivilegesListener"); + "addCarrierPrivilegesCallback"); if (VDBG) { log( "listen carrier privs: E pkg=" + pii(callingPackage) + " phoneId=" + phoneId @@ -2813,7 +2819,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (r == null) return; r.context = mContext; - r.carrierPrivilegesListener = callback; + r.carrierPrivilegesCallback = callback; r.callingPackage = callingPackage; r.callingFeatureId = callingFeatureId; r.callerUid = Binder.getCallingUid(); @@ -2825,10 +2831,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } Pair<List<String>, int[]> state = mCarrierPrivilegeStates.get(phoneId); + Pair<String, Integer> carrierServiceState = mCarrierServiceStates.get(phoneId); try { - r.carrierPrivilegesListener.onCarrierPrivilegesChanged( - Collections.unmodifiableList(state.first), - Arrays.copyOf(state.second, state.second.length)); + if (r.matchCarrierPrivilegesCallback()) { + // Here, two callbacks are triggered in quick succession on the same binder. + // In typical case, we expect the callers to care about only one or the other. + r.carrierPrivilegesCallback.onCarrierPrivilegesChanged( + Collections.unmodifiableList(state.first), + Arrays.copyOf(state.second, state.second.length)); + + r.carrierPrivilegesCallback.onCarrierServiceChanged(carrierServiceState.first, + carrierServiceState.second); + } } catch (RemoteException ex) { remove(r.binder); } @@ -2836,12 +2850,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override - public void removeCarrierPrivilegesListener( - ICarrierPrivilegesListener callback, String callingPackage) { + public void removeCarrierPrivilegesCallback( + @NonNull ICarrierPrivilegesCallback callback, @NonNull String callingPackage) { mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, - "removeCarrierPrivilegesListener"); + "removeCarrierPrivilegesCallback"); remove(callback.asBinder()); } @@ -2866,13 +2880,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { // Listeners are per-slot, not per-subscription. This is to provide a stable // view across SIM profile switches. - if (!r.matchCarrierPrivilegesListener() + if (!r.matchCarrierPrivilegesCallback() || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) { continue; } try { // Make sure even in-process listeners can't modify the values. - r.carrierPrivilegesListener.onCarrierPrivilegesChanged( + r.carrierPrivilegesCallback.onCarrierPrivilegesChanged( Collections.unmodifiableList(privilegedPackageNames), Arrays.copyOf(privilegedUids, privilegedUids.length)); } catch (RemoteException ex) { @@ -2883,6 +2897,34 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + @Override + public void notifyCarrierServiceChanged(int phoneId, @Nullable String packageName, int uid) { + if (!checkNotifyPermission("notifyCarrierServiceChanged")) return; + if (!validatePhoneId(phoneId)) return; + if (VDBG) { + log("notifyCarrierServiceChanged: phoneId=" + phoneId + + ", package=" + pii(packageName) + ", uid=" + uid); + } + + synchronized (mRecords) { + mCarrierServiceStates.set( + phoneId, new Pair<>(packageName, uid)); + for (Record r : mRecords) { + // Listeners are per-slot, not per-subscription. + if (!r.matchCarrierPrivilegesCallback() + || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) { + continue; + } + try { + r.carrierPrivilegesCallback.onCarrierServiceChanged(packageName, uid); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + handleRemoveListLocked(); + } + } + @NeverCompile // Avoid size overhead of debugging code. @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { @@ -2938,6 +2980,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println( "mCarrierPrivilegeState=<packages=" + pii(carrierPrivilegeState.first) + ", uids=" + Arrays.toString(carrierPrivilegeState.second) + ">"); + Pair<String, Integer> carrierServiceState = mCarrierServiceStates.get(i); + pw.println("mCarrierServiceState=<package=" + pii(carrierServiceState.first) + + ", uid=" + carrierServiceState.second + ">"); pw.decreaseIndent(); } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 1eb391d60e4d..5ef22de1dab3 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -16790,7 +16790,10 @@ public class TelephonyManager { * Callback to listen for when the set of packages with carrier privileges for a SIM changes. * * @hide + * @deprecated Use {@link CarrierPrivilegesCallback} instead. This API will be removed soon + * prior to API finalization. */ + @Deprecated @SystemApi public interface CarrierPrivilegesListener { /** @@ -16810,6 +16813,54 @@ public class TelephonyManager { } /** + * Callbacks to listen for when the set of packages with carrier privileges for a SIM changes. + * + * <p>Of note, when multiple callbacks are registered, they may be triggered one after another. + * The ordering of them is not guaranteed and thus should not be depend on. + * + * @hide + */ + @SystemApi + public interface CarrierPrivilegesCallback { + /** + * Called when the set of packages with carrier privileges has changed. + * + * <p>Of note, this callback will <b>not</b> be fired if a carrier triggers a SIM profile + * switch and the same set of packages remains privileged after the switch. + * + * <p>At registration, the callback will receive the current set of privileged packages. + * + * @param privilegedPackageNames The updated set of package names that have carrier + * privileges + * @param privilegedUids The updated set of UIDs that have carrier privileges + */ + void onCarrierPrivilegesChanged( + @NonNull Set<String> privilegedPackageNames, @NonNull Set<Integer> privilegedUids); + + /** + * Called when the {@link CarrierService} for the current user profile has changed. + * + * <p>This method does nothing by default. Clients that are interested in the carrier + * service change should override this method to get package name and UID info. + * + * <p>At registration, the callback will receive the current carrier service info. + * + * <p>Of note, this callback will <b>not</b> be fired if a carrier triggers a SIM profile + * switch and the same carrier service remains after switch. + * + * @param carrierServicePackageName package name of the {@link CarrierService}. May be + * {@code null} when no carrier service is detected. + * @param carrierServiceUid UID of the {@link CarrierService}. May be + * {@link android.os.Process#INVALID_UID} if no carrier + * service is detected. + */ + default void onCarrierServiceChanged( + @Nullable String carrierServicePackageName, int carrierServiceUid) { + // do nothing by default + } + } + + /** * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to * receive callbacks when the set of packages with carrier privileges changes. The callback will * immediately be called with the latest state. @@ -16818,7 +16869,10 @@ public class TelephonyManager { * @param executor The executor where {@code listener} will be invoked * @param listener The callback to register * @hide + * @deprecated Use {@link #unregisterCarrierPrivilegesCallback} instead. This API will be + * removed prior to API finalization. */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addCarrierPrivilegesListener( @@ -16842,7 +16896,10 @@ public class TelephonyManager { * Unregisters an existing {@link CarrierPrivilegesListener}. * * @hide + * @deprecated Use {@link #unregisterCarrierPrivilegesCallback} instead. This API will be + * removed prior to API finalization. */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) { @@ -16890,4 +16947,53 @@ public class TelephonyManager { ex.rethrowAsRuntimeException(); } } + + /** + * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to + * receive callbacks when the set of packages with carrier privileges changes. The callback will + * immediately be called with the latest state. + * + * @param logicalSlotIndex The SIM slot to listen on + * @param executor The executor where {@code callback} will be invoked + * @param callback The callback to register + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void registerCarrierPrivilegesCallback( + int logicalSlotIndex, + @NonNull @CallbackExecutor Executor executor, + @NonNull CarrierPrivilegesCallback callback) { + if (mContext == null) { + throw new IllegalStateException("Telephony service is null"); + } else if (executor == null || callback == null) { + throw new IllegalArgumentException( + "CarrierPrivilegesCallback and executor must be non-null"); + } + mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); + if (mTelephonyRegistryMgr == null) { + throw new IllegalStateException("Telephony registry service is null"); + } + mTelephonyRegistryMgr.addCarrierPrivilegesCallback(logicalSlotIndex, executor, callback); + } + + /** + * Unregisters an existing {@link CarrierPrivilegesCallback}. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void unregisterCarrierPrivilegesCallback(@NonNull CarrierPrivilegesCallback callback) { + if (mContext == null) { + throw new IllegalStateException("Telephony service is null"); + } else if (callback == null) { + throw new IllegalArgumentException("CarrierPrivilegesCallback must be non-null"); + } + mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); + if (mTelephonyRegistryMgr == null) { + throw new IllegalStateException("Telephony registry service is null"); + } + mTelephonyRegistryMgr.removeCarrierPrivilegesCallback(callback); + } } |