Android app targetSdk从28升级到33问题汇总

一.TelephonyManager#listen(PhoneStateListener listener, int events)

问题说明:targetsdkversion升级到12或者以上,设备运行系统至少12的话,如果不动态申请READ PHONE STATE权限则报错SecurityException

错误日志

java.lang.SecurityException: listen
   at android.os.Parcel.createExceptionOrNull(Parcel.java:2442)
   at android.os.Parcel.createException(Parcel.java:2426)
   at android.os.Parcel.readException(Parcel.java:2409)
   at android.os.Parcel.readException(Parcel.java:2351)
   at com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy.listenWithEventList(ITelephonyRegistry.java:1036)
   at android.telephony.TelephonyRegistryManager.listenFromListener(TelephonyRegistryManager.java:250)
   at android.telephony.TelephonyManager.listen(TelephonyManager.java:6064)

android12
过程概述:

1.调用入口

5956      /**
5957       * Registers a listener object to receive notification of changes
5958       * in specified telephony states.
5959       * <p>
5960       * To register a listener, pass a {
    
    @link PhoneStateListener} and specify at least one telephony
5961       * state of interest in the events argument.
5962       *
5963       * At registration, and when a specified telephony state changes, the telephony manager invokes
5964       * the appropriate callback method on the listener object and passes the current (updated)
5965       * values.
5966       * <p>
5967       * To un-register a listener, pass the listener object and set the events argument to
5968       * {
    
    @link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
5969       *
5970       * If this TelephonyManager object has been created with {
    
    @link #createForSubscriptionId},
5971       * applies to the given subId. Otherwise, applies to
5972       * {
    
    @link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
5973       * pass a separate listener object to each TelephonyManager object created with
5974       * {
    
    @link #createForSubscriptionId}.
5975       *
5976       * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
5977       * call {
    
    @link android.os.Binder#clearCallingIdentity()} before calling this method. A
5978       * {
    
    @link SecurityException} will be thrown otherwise.
5979       *
5980       * This API should be used sparingly -- large numbers of listeners will cause system
5981       * instability. If a process has registered too many listeners without unregistering them, it
5982       * may encounter an {
    
    @link IllegalStateException} when trying to register more listeners.
5983       *
5984       * @param listener The {
    
    @link PhoneStateListener} object to register
5985       *                 (or unregister)
5986       * @param events The telephony state(s) of interest to the listener,
5987       *               as a bitwise-OR combination of {
    
    @link PhoneStateListener}
5988       *               LISTEN_ flags.
5989       * @deprecated Use {
    
    @link #registerTelephonyCallback(Executor, TelephonyCallback)}.
5990       */
5991      @Deprecated
5992      public void listen(PhoneStateListener listener, int events) {
    
    
5993          if (mContext == null) return;
5994          boolean notifyNow = (getITelephony() != null);
5995          TelephonyRegistryManager telephonyRegistry =
5996                  (TelephonyRegistryManager)
5997                          mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
5998          if (telephonyRegistry != null) {
    
    
5999              telephonyRegistry.listenFromListener(mSubId, getOpPackageName(),
6000                      getAttributionTag(), listener, events, notifyNow);
6001          } else {
    
    
6002              Rlog.w(TAG, "telephony registry not ready.");
6003          }
6004      }

走到TelephonyRegistryManager#listenFromListener(int subId, @NonNull String pkg, @NonNull String featureId,@NonNull PhoneStateListener listener, @NonNull int events, boolean notifyNow)

2.binder service之TelephonyRegistryManager TelephonyRegistryManager(不是binder服务端!!!)

注册

源码位置/frameworks/base/core/java/android/app/SystemServiceRegistry.java

678          registerService(Context.TELEPHONY_REGISTRY_SERVICE, TelephonyRegistryManager.class,
679              new CachedServiceFetcher<TelephonyRegistryManager>() {
    
    
680                  @Override
681                  public TelephonyRegistryManager createService(ContextImpl ctx) {
    
    
682                      return new TelephonyRegistryManager(ctx);
683                  }});

使用

源码位置 /frameworks/base/core/java/android/telephony/TelephonyRegistryManager.java

216      /**
217       * To check the SDK version for {
    
    @link #listenFromListener}.
218       */
219      @ChangeId
220      @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
221      private static final long LISTEN_CODE_CHANGE = 147600208L;
222  
223      /**
224       * Listen for incoming subscriptions
225       * @param subId Subscription ID
226       * @param pkg Package name
227       * @param featureId Feature ID
228       * @param listener Listener providing callback
229       * @param events Events
230       * @param notifyNow Whether to notify instantly
231       */
232      public void listenFromListener(int subId, @NonNull String pkg, @NonNull String featureId,
233              @NonNull PhoneStateListener listener, @NonNull int events, boolean notifyNow) {
    
    
234          if (listener == null) {
    
    
235              throw new IllegalStateException("telephony service is null.");
236          }
237  
238          try {
    
    
239              int[] eventsList = getEventsFromBitmask(events).stream().mapToInt(i -> i).toArray();
240              // subId from PhoneStateListener is deprecated Q on forward, use the subId from
241              // TelephonyManager instance. Keep using subId from PhoneStateListener for pre-Q.
242              if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) {
    
    
243                  // Since mSubId in PhoneStateListener is deprecated from Q on forward, this is
244                  // the only place to set mSubId and its for "informational" only.
245                  listener.mSubId = (eventsList.length == 0)
246                          ? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subId;
247              } else if (listener.mSubId != null) {
    
    
248                  subId = listener.mSubId;
249              }
250              sRegistry.listenWithEventList(
251                      subId, pkg, featureId, listener.callback, eventsList, notifyNow);
252          } catch (RemoteException e) {
    
    
253              throw e.rethrowFromSystemServer();
254          }
255      }
private @NonNull Set<Integer> getEventsFromBitmask(int eventMask) {
    
    
1003  
1004          Set<Integer> eventList = new ArraySet<>();
。。。
1026          // Note: Legacy call state listeners can get the phone number which is not provided in the
1027          // new version in TelephonyCallback.
1028          if ((eventMask & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
    
    
1029              eventList.add(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED);
1030          }
1031  

最后转换成EVENT_LEGACY_CALL_STATE_CHANGED

至此走到ITelephonyRegistry#listenWithEventList(int subId, String callingPackage, String callingFeatureId,IPhoneStateListener callback, int[] events, boolean notifyNow)

3.binder service之TelephonyRegistry

注册

源码位置 /frameworks/base/services/java/com/android/server/SystemServer.java

1410              t.traceBegin("StartTelephonyRegistry");
1411              telephonyRegistry = new TelephonyRegistry(
1412                      context, new TelephonyRegistry.ConfigurationProvider());
1413              ServiceManager.addService("telephony.registry", telephonyRegistry);
1414              t.traceEnd();
注意:可以看到两个binder service注册位置不一样 经确认,前者运行在调用进程(同一个jvm),后者运行在binder服务端进程,这里是system server进程,通过ServiceManager注册

使用

源码位置:frameworks/base/services/core/java/com/android/server/TelephonyRegistry.java

992      @Override
993      public void listenWithEventList(int subId, String callingPackage, String callingFeatureId,
994              IPhoneStateListener callback, int[] events, boolean notifyNow) {
    
    
995          Set<Integer> eventList = Arrays.stream(events).boxed().collect(Collectors.toSet());
996          listen(callingPackage, callingFeatureId, callback, eventList, notifyNow, subId);
997      }



private void listen(String callingPackage, @Nullable String callingFeatureId,
1000              IPhoneStateListener callback, Set<Integer> events, boolean notifyNow, int subId) {
    
    
1001          int callerUserId = UserHandle.getCallingUserId();
1002          mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
1003          String str = "listen: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
1004                  + " events=" + events + " notifyNow=" + notifyNow
1005                  + " subId=" + subId + " myUserId=" + UserHandle.myUserId()
1006                  + " callerUserId=" + callerUserId;
1007          mListenLog.log(str);
1008          if (VDBG) {
    
    
1009              log(str);
1010          }
1011  
1012          if (events.isEmpty()) {
    
    
1013              if (DBG) {
    
    
1014                  log("listen: Unregister");
1015              }
1016              events.clear();
1017              remove(callback.asBinder());
1018              return;
1019          }
1020  
1021          // Checks permission and throws SecurityException for disallowed operations. For pre-M
1022          // apps whose runtime permission has been revoked, we return immediately to skip sending
1023          // events to the app without crashing it.
1024          if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId, "listen")) {
    
    
1025              return;
1026          }//关键权限校验代码
1027  

。。。
}

private boolean checkListenerPermission(Set<Integer> events, int subId, String callingPackage,
3055              @Nullable String callingFeatureId, String message) {
    
    
。。。
3090  
3091          if (isPhoneStatePermissionRequired(events, callingPackage, Binder.getCallingUserHandle())) {
    
    
3092              if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
3093                      mContext, subId, callingPackage, callingFeatureId, message)) {
    
    
3094                  isPermissionCheckSuccessful = false;
3095              }
3096          }

1.先看权限检查TelephonyPermissions.checkCallingOrSelfReadPhoneState( mContext, subId, callingPackage, callingFeatureId, message)

可以看到先校验READ_PRIVILEGED_PHONE_STATE,如果没有该权限,则校验READ_PHONE_STATE,如果都没有,则抛出异常SecurityException

91      public static boolean checkCallingOrSelfReadPhoneState(
92              Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
93              String message) {
    
    
94          return checkReadPhoneState(context, subId, Binder.getCallingPid(), Binder.getCallingUid(),
95                  callingPackage, callingFeatureId, message);
96      }
。。。

132      public static boolean checkReadPhoneState(
133              Context context, int subId, int pid, int uid, String callingPackage,
134              @Nullable  String callingFeatureId, String message) {
    
    
135          try {
    
    
136              context.enforcePermission(
137                      android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
138  
139              // SKIP checking for run-time permission since caller has PRIVILEGED permission
140              return true;
141          } catch (SecurityException privilegedPhoneStateException) {
    
    
142              try {
    
    
143                  context.enforcePermission(
144                          android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
145              } catch (SecurityException phoneStateException) {
    
    
146                  // If we don't have the runtime permission, but do have carrier privileges, that
147                  // suffices for reading phone state.
148                  if (SubscriptionManager.isValidSubscriptionId(subId)) {
149                      enforceCarrierPrivilege(context, subId, uid, message);
150                      return true;
151                  }
152                  throw phoneStateException;
153              }
154          }
155  
156          // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
157          // revoked.
158          AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
159          return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage,
160                  callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
161      }
2.再看什么情况下需要权限

isPhoneStatePermissionRequired(events, callingPackage, Binder.getCallingUserHandle())

 private boolean isPhoneStatePermissionRequired(Set<Integer> events, String callingPackage,
465              UserHandle userHandle) {
    
    
。。。
471  
472          // Only check READ_PHONE_STATE for CALL_STATE_CHANGED for Android 12 or above.
473          if ((events.contains(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED)
474                  || events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED))
475                  && mConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(
476                          callingPackage, userHandle)) {
    
    
477              return true;
478          }
。。。
504      }

因为events中包含TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED

194      /**
195       * Wrapper class to facilitate testing -- encapsulates bits of configuration that are
196       * normally fetched from static methods with many dependencies.
197       */
198      public static class ConfigurationProvider {
    
    
...
225           */
226          public boolean isCallStateReadPhoneStateEnforcedInPlatformCompat(String packageName,
227                  UserHandle userHandle) {
    
    
228              return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled(
229                      TelecomManager.ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION, packageName,
230                      userHandle));
231          }

源码位置:frameworks/base/telecomm/java/android/telecom/TelecomManager.java

1010      /**
1011       * Enable READ_PHONE_STATE protection on APIs querying and notifying call state, such as
1012       * {
    
    @code TelecomManager#getCallState}, {@link TelephonyManager#getCallStateForSubscription()},
1013       * and {
    
    @link android.telephony.TelephonyCallback.CallStateListener}.
1014       * @hide
1015       */
1016      @ChangeId
1017      @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
1018      // this magic number is a bug ID
1019      public static final long ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION = 157233955L;

到了这里,就可以确定targetsdk版本从android 12开始并且运行系统版本不低于12则这个权限READ PHONE STATE必须动态申请,否则binder通信会报错SecurityException

注意:注解@EnabledSince 要和注解@ChangeId搭配使用

源码位置 /tools/platform-compat/java/android/compat/annotation/EnabledSince.java

25  /**
26   * Used to indicate that a compatibility {
    
    @link ChangeId change} is enabled only for apps with a
27   * {
    
    @code targetSdkVersion} <em>greater or equal to</em> the given value.
28   *
29   * <p>This annotation should only be applied to change ID constants that are also annotated with
30   * {
    
    @link ChangeId}. In any other context, this annotation will have no effect.
31   *
32   * @hide
33   */
34  @Retention(SOURCE)
35  @Target({
    
    FIELD})
36  public @interface EnabledSince {
    
    
37      /**
38       * @return Theminimum  {
    
    @code targetSdkVersion} for which this change is enabled. Apps with
39       *     a {
    
    @code targetSdkVersion} greater or equal to this value will get the change.
40       */
41      int targetSdkVersion();
42  }
43  

为什么同时要求运行系统不低于12

答:低于12的系统版本中没有这些逻辑要求,可以对照12以下系统源码

二.TelephonyManager#getCallState()

问题说明:targetsdkversion升级到12或者以上,设备运行系统至少12的话,如果不动态申请READ PHONE STATE权限则报错SecurityException

跟上一个问题类似

错误日志

java.lang.SecurityException: getCallState: Neither user 10495 nor current process has android.permission.READ_PHONE_STATE.
                                                                                                    	at android.os.Parcel.createExceptionOrNull(Parcel.java:2442)
                                                                                                    	at android.os.Parcel.createException(Parcel.java:2426)
                                                                                                    	at android.os.Parcel.readException(Parcel.java:2409)
                                                                                                    	at android.os.Parcel.readException(Parcel.java:2351)
                                                                                                    	at com.android.internal.telecom.ITelecomService$Stub$Proxy.getCallStateUsingPackage(ITelecomService.java:2700)
                                                                                                    	at android.telecom.TelecomManager.getCallState(TelecomManager.java:1825)

这里我们可以看到是android.os.Parcel.readException抛出的,因为涉及到binder跨进程通信,属于binder服务端权限校验异常,会发送异常数据到binder客户端,所以binder客户端才会通过Parcel读取到exception

还是跟android12源码
过程概述:

1.调用入口

光看这段代码是看不出有任何权限要求的

5680      /**
5681       * Returns the state of all calls on the device.
5682       * <p>
5683       * This method considers not only calls in the Telephony stack, but also calls via other
5684       * {
    
    @link android.telecom.ConnectionService} implementations.
5685       * <p>
5686       * Note: The call state returned via this method may differ from what is reported by
5687       * {
    
    @link PhoneStateListener#onCallStateChanged(int, String)}, as that callback only considers
5688       * Telephony (mobile) calls.
5689       * <p>
5690       * Requires Permission:
5691       * {
    
    @link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} for applications
5692       * targeting API level 31+.
5693       *
5694       * @return the current call state.
5695       * @deprecated Use {
    
    @link #getCallStateForSubscription} to retrieve the call state for a
5696       * specific telephony subscription (which allows carrier privileged apps),
5697       * {
    
    @link TelephonyCallback.CallStateListener} for real-time call state updates, or
5698       * {
    
    @link TelecomManager#isInCall()}, which supplies an aggregate "in call" state for the entire
5699       * device.
5700       */
5701      @RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
5702      @Deprecated
5703      public @CallState int getCallState() {
    
    
5704          if (mContext != null) {
    
    
5705              TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
5706              if (telecomManager != null) {
    
    
5707                  return telecomManager.getCallState();
5708              }
5709          }
5710          return CALL_STATE_IDLE;
5711      }

2.TelecomManager

注册

源码位置/frameworks/base/core/java/android/app/SystemServiceRegistry.java

685          registerService(Context.TELECOM_SERVICE, TelecomManager.class,
686                  new CachedServiceFetcher<TelecomManager>() {
    
    
687              @Override
688              public TelecomManager createService(ContextImpl ctx) {
    
    
689                  return new TelecomManager(ctx.getOuterContext());
690              }});

注意:这里注册逻辑是在同一个进程注册的,没有binder跨进程

源码位置: /frameworks/base/core/java/android/app/ContextImpl.java

2048      public Object getSystemService(String name) {
    
    
2049          if (vmIncorrectContextUseEnabled()) {
    
    
2050              // Check incorrect Context usage.
2051              if (WINDOW_SERVICE.equals(name) && !isUiContext()) {
    
    
2052                  final String errorMessage = "Tried to access visual service "
2053                          + SystemServiceRegistry.getSystemServiceClassName(name)
2054                          + " from a non-visual Context:" + getOuterContext();
2055                  final String message = "WindowManager should be accessed from Activity or other "
2056                          + "visual Context. Use an Activity or a Context created with "
2057                          + "Context#createWindowContext(int, Bundle), which are adjusted to "
2058                          + "the configuration and visual bounds of an area on screen.";
2059                  final Exception exception = new IllegalAccessException(errorMessage);
2060                  StrictMode.onIncorrectContextUsed(message, exception);
2061                  Log.e(TAG, errorMessage + " " + message, exception);
2062              }
2063          }
2064          return SystemServiceRegistry.getSystemService(this, name);
2065      }

使用

源码位置: /frameworks/base/telecomm/java/android/telecom/TelecomManager.java

1781      /**
1782       * Returns one of the following constants that represents the current state of Telecom:
1783       *
1784       * {
    
    @link TelephonyManager#CALL_STATE_RINGING}
1785       * {
    
    @link TelephonyManager#CALL_STATE_OFFHOOK}
1786       * {
    
    @link TelephonyManager#CALL_STATE_IDLE}
1787       *
1788       * Takes into consideration both managed and self-managed calls.
1789       * <p>
1790       * Requires Permission:
1791       * {
    
    @link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} for applications
1792       * targeting API level 31+.
1793       *
1794       * @hide
1795       */
1796      @RequiresPermission(anyOf = {
    
    READ_PRIVILEGED_PHONE_STATE,
1797              android.Manifest.permission.READ_PHONE_STATE}, conditional = true)
1798      @SystemApi
1799      public @CallState int getCallState() {
    
    
1800          ITelecomService service = getTelecomService();
1801          if (service != null) {
    
    
1802              try {
    
    
1803                  return service.getCallStateUsingPackage(mContext.getPackageName(),
1804                          mContext.getAttributionTag());
1805              } catch (RemoteException e) {
    
    
1806                  Log.d(TAG, "RemoteException calling getCallState().", e);
1807              }
1808          }
1809          return TelephonyManager.CALL_STATE_IDLE;
1810      }
1811  

这里只是看到

@RequiresPermission(anyOf = {
    
    READ_PRIVILEGED_PHONE_STATE,android.Manifest.permission.READ_PHONE_STATE}, conditional = true)

但是其实并没有对targetsdk有要求,也不是硬性要求必须有READ_PHONE_STATE权限,没有则不能运行

这里继续看getTelecomService(),这时候才是真正有binder通信

2572      private ITelecomService getTelecomService() {
    
    
2573          if (mTelecomServiceOverride != null) {
    
    
2574              return mTelecomServiceOverride;
2575          }
2576          if (sTelecomService == null) {
    
    
2577              ITelecomService temp = ITelecomService.Stub.asInterface(
2578                      ServiceManager.getService(Context.TELECOM_SERVICE));
2579              synchronized (CACHE_LOCK) {
    
    
2580                  if (sTelecomService == null && temp != null) {
    
    
2581                      try {
    
    
2582                          sTelecomService = temp;
2583                          sTelecomService.asBinder().linkToDeath(SERVICE_DEATH, 0);
2584                      } catch (Exception e) {
    
    
2585                          sTelecomService = null;
2586                      }
2587                  }
2588              }
2589          }
2590          return sTelecomService;
2591      }

3.binder service之ITelecomService

注册

这里注册逻辑比较深!!!

源码位置: /frameworks/base/telecomm/java/android/telecom/TelecomManager.java

144      private void connectToTelecom() {
    
    
145          synchronized (mLock) {
    
    
146              if (mServiceConnection != null) {
    
    
147                  // TODO: Is unbinding worth doing or wait for system to rebind?
148                  mContext.unbindService(mServiceConnection);
149                  mServiceConnection = null;
150              }
151  
152              TelecomServiceConnection serviceConnection = new TelecomServiceConnection();
153              Intent intent = new Intent(SERVICE_ACTION);
154              intent.setComponent(SERVICE_COMPONENT);
155              int flags = Context.BIND_IMPORTANT | Context.BIND_FOREGROUND_SERVICE
156                      | Context.BIND_AUTO_CREATE;
157  
158              // Bind to Telecom and register the service
159              if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.SYSTEM)) {
    
    
160                  mServiceConnection = serviceConnection;
161              }
162          }
163      }

抽丝剥茧,真正的binder服务端是在

源码位置: /packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java

944          /**
945           * @see TelecomManager#getCallState()
946           */
947          @Override
948          public int getCallStateUsingPackage(String callingPackage, String callingFeatureId) {
    
    
949              try {
    
    
950                  Log.startSession("TSI.getCallStateUsingPackage");
951                  if (CompatChanges.isChangeEnabled(
952                          TelecomManager.ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION, callingPackage,
953                          Binder.getCallingUserHandle())) {
    
    
954                      // Bypass canReadPhoneState check if this is being called from SHELL UID
955                      if (Binder.getCallingUid() != Process.SHELL_UID && !canReadPhoneState(
956                              callingPackage, callingFeatureId, "getCallState")) {
    
    
957                          throw new SecurityException("getCallState API requires READ_PHONE_STATE"
958                                  + " for API version 31+");
959                      }
960                  }
961                  synchronized (mLock) {
    
    
962                      return mCallsManager.getCallState();
963                  }
964              } finally {
    
    
965                  Log.endSession();
966              }
967          }

使用

继续看到
源码位置: /packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java

getCallStateUsingPackage这个方法,关键校验逻辑

CompatChanges.isChangeEnabled(
952                          TelecomManager.ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION, callingPackage,
953                          Binder.getCallingUserHandle())

源码位置:frameworks/base/telecomm/java/android/telecom/TelecomManager.java

1010      /**
1011       * Enable READ_PHONE_STATE protection on APIs querying and notifying call state, such as
1012       * {
    
    @code TelecomManager#getCallState}, {@link TelephonyManager#getCallStateForSubscription()},
1013       * and {
    
    @link android.telephony.TelephonyCallback.CallStateListener}.
1014       * @hide
1015       */
1016      @ChangeId
1017      @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
1018      // this magic number is a bug ID
1019      public static final long ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION = 157233955L;

又回到注解EnabledSince

跟TelephonyManager#listen(PhoneStateListener listener, int events)
殊途同归

猜你喜欢

转载自blog.csdn.net/weixin_41548050/article/details/133038263