Loading core/api/system-current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -12001,6 +12001,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 @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); Loading Loading @@ -12095,6 +12096,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled(); method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot(); method @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.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>); Loading Loading @@ -12270,6 +12272,10 @@ 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 class TelephonyManager.ModemActivityInfoException extends java.lang.Exception { method public int getErrorCode(); field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2 core/java/android/telephony/TelephonyRegistryManager.java +119 −0 Original line number Diff line number Diff line Loading @@ -36,18 +36,24 @@ import android.telephony.Annotation.PreciseDisconnectCauses; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; import android.telephony.TelephonyManager.CarrierPrivilegesListener; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.util.ArraySet; 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.IOnSubscriptionsChangedListener; import com.android.internal.telephony.ITelephonyRegistry; import java.lang.ref.WeakReference; 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; /** Loading Loading @@ -1214,4 +1220,117 @@ public class TelephonyRegistryManager { listenFromCallback(false, false, subId, pkgName, attributionTag, callback, new int[0], notifyNow); } private static class CarrierPrivilegesListenerWrapper extends ICarrierPrivilegesListener.Stub implements ListenerExecutor { private final WeakReference<CarrierPrivilegesListener> mListener; private final Executor mExecutor; CarrierPrivilegesListenerWrapper(CarrierPrivilegesListener listener, Executor executor) { mListener = new WeakReference<>(listener); mExecutor = executor; } @Override public void onCarrierPrivilegesChanged( List<String> privilegedPackageNames, int[] privilegedUids) { Binder.withCleanCallingIdentity( () -> executeSafely( mExecutor, mListener::get, cpl -> cpl.onCarrierPrivilegesChanged( privilegedPackageNames, privilegedUids))); } } @GuardedBy("sCarrierPrivilegeListeners") private static final WeakHashMap< CarrierPrivilegesListener, WeakReference<CarrierPrivilegesListenerWrapper>> sCarrierPrivilegeListeners = new WeakHashMap<>(); /** * 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. * * @param logicalSlotIndex The SIM slot to listen on * @param executor The executor where {@code listener} will be invoked * @param listener The callback to register */ public void addCarrierPrivilegesListener( int logicalSlotIndex, @NonNull @CallbackExecutor Executor executor, @NonNull CarrierPrivilegesListener listener) { if (listener == null || executor == null) { throw new IllegalArgumentException("listener and executor must be non-null"); } synchronized (sCarrierPrivilegeListeners) { WeakReference<CarrierPrivilegesListenerWrapper> existing = sCarrierPrivilegeListeners.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)); try { sRegistry.addCarrierPrivilegesListener( logicalSlotIndex, wrapper, mContext.getOpPackageName(), mContext.getAttributionTag()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Unregisters a {@link CarrierPrivilegesListener}. * * @param listener The callback to unregister */ 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); if (ref == null) return; CarrierPrivilegesListenerWrapper wrapper = ref.get(); if (wrapper == null) return; try { sRegistry.removeCarrierPrivilegesListener(wrapper, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Notify listeners that the set of packages with carrier privileges has changed. * * @param logicalSlotIndex The SIM slot the change occurred on * @param privilegedPackageNames The updated set of packages names with carrier privileges * @param privilegedUids The updated set of UIDs with carrier privileges */ public void notifyCarrierPrivilegesChanged( int logicalSlotIndex, @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids) { if (privilegedPackageNames == null || privilegedUids == null) { throw new IllegalArgumentException( "privilegedPackageNames and privilegedUids must be non-null"); } try { sRegistry.notifyCarrierPrivilegesChanged( logicalSlotIndex, privilegedPackageNames, privilegedUids); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 ICarrierPrivilegesListener { void onCarrierPrivilegesChanged( in List<String> privilegedPackageNames, in int[] privilegedUids); } core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -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.ICarrierPrivilegesListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; Loading Loading @@ -100,4 +101,10 @@ interface ITelephonyRegistry { void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in int reason, in long allowedNetworkType); 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 notifyCarrierPrivilegesChanged( int phoneId, in List<String> privilegedPackageNames, in int[] privilegedUids); } services/core/java/com/android/server/TelephonyRegistry.java +127 −2 Original line number Diff line number Diff line Loading @@ -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.ICarrierPrivilegesListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.ITelephonyRegistry; Loading @@ -106,6 +107,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; Loading Loading @@ -149,6 +151,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { IPhoneStateListener callback; IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback; IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback; ICarrierPrivilegesListener carrierPrivilegesListener; int callerUid; int callerPid; Loading @@ -173,6 +176,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return (onOpportunisticSubscriptionsChangedListenerCallback != null); } boolean matchCarrierPrivilegesListener() { return carrierPrivilegesListener != null; } boolean canReadCallLog() { try { return TelephonyPermissions.checkReadCallLog( Loading @@ -189,8 +196,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { + " onSubscriptionsChangedListenererCallback=" + onSubscriptionsChangedListenerCallback + " onOpportunisticSubscriptionsChangedListenererCallback=" + onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}"; + onOpportunisticSubscriptionsChangedListenerCallback + " carrierPrivilegesListener=" + carrierPrivilegesListener + " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}"; } } Loading Loading @@ -402,6 +410,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { */ private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>> mPreciseDataConnectionStates; /** Per-phoneId snapshot of privileged packages (names + UIDs). */ private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates; /** * Support backward compatibility for {@link android.telephony.TelephonyDisplayInfo}. */ Loading Loading @@ -689,6 +701,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { cutListToSize(mBarringInfo, mNumPhones); cutListToSize(mPhysicalChannelConfigs, mNumPhones); cutListToSize(mLinkCapacityEstimateLists, mNumPhones); cutListToSize(mCarrierPrivilegeStates, mNumPhones); return; } Loading Loading @@ -729,6 +742,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeReason[i] = -1; mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); } } Loading Loading @@ -794,6 +808,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mIsDataEnabled = new boolean[numPhones]; mDataEnabledReason = new int[numPhones]; mLinkCapacityEstimateLists = new ArrayList<>(); mCarrierPrivilegeStates = new ArrayList<>(); for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; Loading Loading @@ -831,6 +846,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeReason[i] = -1; mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); } mAppOps = mContext.getSystemService(AppOpsManager.class); Loading Loading @@ -2765,6 +2781,104 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } @Override public void addCarrierPrivilegesListener( int phoneId, ICarrierPrivilegesListener callback, String callingPackage, String callingFeatureId) { int callerUserId = UserHandle.getCallingUserId(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, "addCarrierPrivilegesListener"); if (VDBG) { log( "listen carrier privs: E pkg=" + pii(callingPackage) + " phoneId=" + phoneId + " uid=" + Binder.getCallingUid() + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId + " callback=" + callback + " callback.asBinder=" + callback.asBinder()); } if (!validatePhoneId(phoneId)) { throw new IllegalArgumentException("Invalid slot index: " + phoneId); } synchronized (mRecords) { Record r = add( callback.asBinder(), Binder.getCallingUid(), Binder.getCallingPid(), false); if (r == null) return; r.context = mContext; r.carrierPrivilegesListener = callback; r.callingPackage = callingPackage; r.callingFeatureId = callingFeatureId; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); r.phoneId = phoneId; r.eventList = new ArraySet<>(); if (DBG) { log("listen carrier privs: Register r=" + r); } Pair<List<String>, int[]> state = mCarrierPrivilegeStates.get(phoneId); try { r.carrierPrivilegesListener.onCarrierPrivilegesChanged( Collections.unmodifiableList(state.first), Arrays.copyOf(state.second, state.second.length)); } catch (RemoteException ex) { remove(r.binder); } } } @Override public void removeCarrierPrivilegesListener( ICarrierPrivilegesListener callback, String callingPackage) { mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, "removeCarrierPrivilegesListener"); remove(callback.asBinder()); } @Override public void notifyCarrierPrivilegesChanged( int phoneId, List<String> privilegedPackageNames, int[] privilegedUids) { if (!checkNotifyPermission("notifyCarrierPrivilegesChanged")) { return; } if (!validatePhoneId(phoneId)) return; if (VDBG) { log( "notifyCarrierPrivilegesChanged: phoneId=" + phoneId + ", <packages=" + pii(privilegedPackageNames) + ", uids=" + Arrays.toString(privilegedUids) + ">"); } synchronized (mRecords) { mCarrierPrivilegeStates.set( phoneId, new Pair<>(privilegedPackageNames, privilegedUids)); 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() || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) { continue; } try { // Make sure even in-process listeners can't modify the values. r.carrierPrivilegesListener.onCarrierPrivilegesChanged( Collections.unmodifiableList(privilegedPackageNames), Arrays.copyOf(privilegedUids, privilegedUids.length)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } } handleRemoveListLocked(); } } @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); Loading Loading @@ -2814,6 +2928,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]); pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs.get(i)); pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i)); // We need to obfuscate package names, and primitive arrays' native toString is ugly Pair<List<String>, int[]> carrierPrivilegeState = mCarrierPrivilegeStates.get(i); pw.println( "mCarrierPrivilegeState=<packages=" + pii(carrierPrivilegeState.first) + ", uids=" + Arrays.toString(carrierPrivilegeState.second) + ">"); pw.decreaseIndent(); } Loading Loading @@ -3540,4 +3659,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private static String pii(String packageName) { return Build.IS_DEBUGGABLE ? packageName : "***"; } /** Redacts an entire list of package names if necessary. */ private static String pii(List<String> packageNames) { if (packageNames.isEmpty() || Build.IS_DEBUGGABLE) return packageNames.toString(); return "[***, size=" + packageNames.size() + "]"; } } Loading
core/api/system-current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -12001,6 +12001,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 @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); Loading Loading @@ -12095,6 +12096,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled(); method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot(); method @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.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>); Loading Loading @@ -12270,6 +12272,10 @@ 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 class TelephonyManager.ModemActivityInfoException extends java.lang.Exception { method public int getErrorCode(); field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2
core/java/android/telephony/TelephonyRegistryManager.java +119 −0 Original line number Diff line number Diff line Loading @@ -36,18 +36,24 @@ import android.telephony.Annotation.PreciseDisconnectCauses; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; import android.telephony.TelephonyManager.CarrierPrivilegesListener; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.util.ArraySet; 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.IOnSubscriptionsChangedListener; import com.android.internal.telephony.ITelephonyRegistry; import java.lang.ref.WeakReference; 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; /** Loading Loading @@ -1214,4 +1220,117 @@ public class TelephonyRegistryManager { listenFromCallback(false, false, subId, pkgName, attributionTag, callback, new int[0], notifyNow); } private static class CarrierPrivilegesListenerWrapper extends ICarrierPrivilegesListener.Stub implements ListenerExecutor { private final WeakReference<CarrierPrivilegesListener> mListener; private final Executor mExecutor; CarrierPrivilegesListenerWrapper(CarrierPrivilegesListener listener, Executor executor) { mListener = new WeakReference<>(listener); mExecutor = executor; } @Override public void onCarrierPrivilegesChanged( List<String> privilegedPackageNames, int[] privilegedUids) { Binder.withCleanCallingIdentity( () -> executeSafely( mExecutor, mListener::get, cpl -> cpl.onCarrierPrivilegesChanged( privilegedPackageNames, privilegedUids))); } } @GuardedBy("sCarrierPrivilegeListeners") private static final WeakHashMap< CarrierPrivilegesListener, WeakReference<CarrierPrivilegesListenerWrapper>> sCarrierPrivilegeListeners = new WeakHashMap<>(); /** * 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. * * @param logicalSlotIndex The SIM slot to listen on * @param executor The executor where {@code listener} will be invoked * @param listener The callback to register */ public void addCarrierPrivilegesListener( int logicalSlotIndex, @NonNull @CallbackExecutor Executor executor, @NonNull CarrierPrivilegesListener listener) { if (listener == null || executor == null) { throw new IllegalArgumentException("listener and executor must be non-null"); } synchronized (sCarrierPrivilegeListeners) { WeakReference<CarrierPrivilegesListenerWrapper> existing = sCarrierPrivilegeListeners.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)); try { sRegistry.addCarrierPrivilegesListener( logicalSlotIndex, wrapper, mContext.getOpPackageName(), mContext.getAttributionTag()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Unregisters a {@link CarrierPrivilegesListener}. * * @param listener The callback to unregister */ 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); if (ref == null) return; CarrierPrivilegesListenerWrapper wrapper = ref.get(); if (wrapper == null) return; try { sRegistry.removeCarrierPrivilegesListener(wrapper, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Notify listeners that the set of packages with carrier privileges has changed. * * @param logicalSlotIndex The SIM slot the change occurred on * @param privilegedPackageNames The updated set of packages names with carrier privileges * @param privilegedUids The updated set of UIDs with carrier privileges */ public void notifyCarrierPrivilegesChanged( int logicalSlotIndex, @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids) { if (privilegedPackageNames == null || privilegedUids == null) { throw new IllegalArgumentException( "privilegedPackageNames and privilegedUids must be non-null"); } try { sRegistry.notifyCarrierPrivilegesChanged( logicalSlotIndex, privilegedPackageNames, privilegedUids); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }
core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 ICarrierPrivilegesListener { void onCarrierPrivilegesChanged( in List<String> privilegedPackageNames, in int[] privilegedUids); }
core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -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.ICarrierPrivilegesListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; Loading Loading @@ -100,4 +101,10 @@ interface ITelephonyRegistry { void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in int reason, in long allowedNetworkType); 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 notifyCarrierPrivilegesChanged( int phoneId, in List<String> privilegedPackageNames, in int[] privilegedUids); }
services/core/java/com/android/server/TelephonyRegistry.java +127 −2 Original line number Diff line number Diff line Loading @@ -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.ICarrierPrivilegesListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.ITelephonyRegistry; Loading @@ -106,6 +107,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; Loading Loading @@ -149,6 +151,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { IPhoneStateListener callback; IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback; IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback; ICarrierPrivilegesListener carrierPrivilegesListener; int callerUid; int callerPid; Loading @@ -173,6 +176,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return (onOpportunisticSubscriptionsChangedListenerCallback != null); } boolean matchCarrierPrivilegesListener() { return carrierPrivilegesListener != null; } boolean canReadCallLog() { try { return TelephonyPermissions.checkReadCallLog( Loading @@ -189,8 +196,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { + " onSubscriptionsChangedListenererCallback=" + onSubscriptionsChangedListenerCallback + " onOpportunisticSubscriptionsChangedListenererCallback=" + onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}"; + onOpportunisticSubscriptionsChangedListenerCallback + " carrierPrivilegesListener=" + carrierPrivilegesListener + " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}"; } } Loading Loading @@ -402,6 +410,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { */ private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>> mPreciseDataConnectionStates; /** Per-phoneId snapshot of privileged packages (names + UIDs). */ private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates; /** * Support backward compatibility for {@link android.telephony.TelephonyDisplayInfo}. */ Loading Loading @@ -689,6 +701,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { cutListToSize(mBarringInfo, mNumPhones); cutListToSize(mPhysicalChannelConfigs, mNumPhones); cutListToSize(mLinkCapacityEstimateLists, mNumPhones); cutListToSize(mCarrierPrivilegeStates, mNumPhones); return; } Loading Loading @@ -729,6 +742,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeReason[i] = -1; mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); } } Loading Loading @@ -794,6 +808,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mIsDataEnabled = new boolean[numPhones]; mDataEnabledReason = new int[numPhones]; mLinkCapacityEstimateLists = new ArrayList<>(); mCarrierPrivilegeStates = new ArrayList<>(); for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; Loading Loading @@ -831,6 +846,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeReason[i] = -1; mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); } mAppOps = mContext.getSystemService(AppOpsManager.class); Loading Loading @@ -2765,6 +2781,104 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } @Override public void addCarrierPrivilegesListener( int phoneId, ICarrierPrivilegesListener callback, String callingPackage, String callingFeatureId) { int callerUserId = UserHandle.getCallingUserId(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, "addCarrierPrivilegesListener"); if (VDBG) { log( "listen carrier privs: E pkg=" + pii(callingPackage) + " phoneId=" + phoneId + " uid=" + Binder.getCallingUid() + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId + " callback=" + callback + " callback.asBinder=" + callback.asBinder()); } if (!validatePhoneId(phoneId)) { throw new IllegalArgumentException("Invalid slot index: " + phoneId); } synchronized (mRecords) { Record r = add( callback.asBinder(), Binder.getCallingUid(), Binder.getCallingPid(), false); if (r == null) return; r.context = mContext; r.carrierPrivilegesListener = callback; r.callingPackage = callingPackage; r.callingFeatureId = callingFeatureId; r.callerUid = Binder.getCallingUid(); r.callerPid = Binder.getCallingPid(); r.phoneId = phoneId; r.eventList = new ArraySet<>(); if (DBG) { log("listen carrier privs: Register r=" + r); } Pair<List<String>, int[]> state = mCarrierPrivilegeStates.get(phoneId); try { r.carrierPrivilegesListener.onCarrierPrivilegesChanged( Collections.unmodifiableList(state.first), Arrays.copyOf(state.second, state.second.length)); } catch (RemoteException ex) { remove(r.binder); } } } @Override public void removeCarrierPrivilegesListener( ICarrierPrivilegesListener callback, String callingPackage) { mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, "removeCarrierPrivilegesListener"); remove(callback.asBinder()); } @Override public void notifyCarrierPrivilegesChanged( int phoneId, List<String> privilegedPackageNames, int[] privilegedUids) { if (!checkNotifyPermission("notifyCarrierPrivilegesChanged")) { return; } if (!validatePhoneId(phoneId)) return; if (VDBG) { log( "notifyCarrierPrivilegesChanged: phoneId=" + phoneId + ", <packages=" + pii(privilegedPackageNames) + ", uids=" + Arrays.toString(privilegedUids) + ">"); } synchronized (mRecords) { mCarrierPrivilegeStates.set( phoneId, new Pair<>(privilegedPackageNames, privilegedUids)); 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() || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) { continue; } try { // Make sure even in-process listeners can't modify the values. r.carrierPrivilegesListener.onCarrierPrivilegesChanged( Collections.unmodifiableList(privilegedPackageNames), Arrays.copyOf(privilegedUids, privilegedUids.length)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } } handleRemoveListLocked(); } } @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); Loading Loading @@ -2814,6 +2928,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]); pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs.get(i)); pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i)); // We need to obfuscate package names, and primitive arrays' native toString is ugly Pair<List<String>, int[]> carrierPrivilegeState = mCarrierPrivilegeStates.get(i); pw.println( "mCarrierPrivilegeState=<packages=" + pii(carrierPrivilegeState.first) + ", uids=" + Arrays.toString(carrierPrivilegeState.second) + ">"); pw.decreaseIndent(); } Loading Loading @@ -3540,4 +3659,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private static String pii(String packageName) { return Build.IS_DEBUGGABLE ? packageName : "***"; } /** Redacts an entire list of package names if necessary. */ private static String pii(List<String> packageNames) { if (packageNames.isEmpty() || Build.IS_DEBUGGABLE) return packageNames.toString(); return "[***, size=" + packageNames.size() + "]"; } }