Android11 授权应用获取IMEI号和ICCID
创始人
2025-05-29 05:54:59
0

在Android11上获取IMEI号等设备信息需要android.permission.READ_PRIVILEGED_PHONE_STATE权限,而这个权限又只授予系统级应用。项目中如果targetSdkVersion值小于29获取到的是null,大于28报SecurityException错误。

1.获取ICCID
 public String getICCID(Context context) {TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);String simSerialNumber = telephonyManager.getSimSerialNumber();return simSerialNumber;}或者public static String getICCID(Context context) {String iccid;TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);iccid = tm.getSimSerialNumber();if (iccid == null || iccid.length() < 20) {SubscriptionManager sm = SubscriptionManager.from(context);List sis = sm.getActiveSubscriptionInfoList();if (sis.size() >= 1) {SubscriptionInfo si1 = sis.get(0); // 卡一iccid = si1.getIccId();}}return iccid;}
2.系统对应用的权限检查
  • 源码路径:frameworks/base/telephony/java/android/telephony/TelephonyManager.java
 @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)public String getSimSerialNumber() {return getSimSerialNumber(getSubId());}@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)@UnsupportedAppUsagepublic String getSimSerialNumber(int subId) {try {IPhoneSubInfo info = getSubscriberInfoService();if (info == null)return null;return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName(),mContext.getAttributionTag());} catch (RemoteException ex) {return null;} catch (NullPointerException ex) {// This could happen before phone restarts due to crashingreturn null;}}

可以看到getSimSerialNumber()方法要求声明android.permission.READ_PRIVILEGED_PHONE_STATE权限
然后调用IPhoneSubInfo的getIccSerialNumberForSubscriber()方法

  • 源码路径:frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneSubInfoController.java
 public class PhoneSubInfoController extends IPhoneSubInfo.Stub {省略部分代码。。。public String getIccSerialNumberForSubscriber(int subId, String callingPackage,String callingFeatureId) {return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,callingFeatureId, "getIccSerialNumber", (phone) -> phone.getIccSerialNumber());}省略部分代码。。。private  T callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(int subId,String callingPackage, @Nullable String callingFeatureId, String message,CallPhoneMethodHelper callMethodHelper) {// 调用Phone的相关方法,进行权限检查return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,message, callMethodHelper,(aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)->TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage));}}

在TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers方法中判断是否有权限获取ICCID

  • 源码路径:frameworks/base/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
 public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,String callingPackage, @Nullable String callingFeatureId, String message) {return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(context, subId, callingPackage, callingFeatureId, message, false);}private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission(Context context, int subId, String callingPackage, @Nullable String callingFeatureId,String message, boolean allowCarrierPrivilegeOnAnySub) {int uid = Binder.getCallingUid();int pid = Binder.getCallingPid();// 调用包是否具有运营商特权// If the calling package has carrier privileges for specified sub, then allow access.if (checkCarrierPrivilegeForSubId(context, subId)) return true;// If the calling package has carrier privileges for any subscription// and allowCarrierPrivilegeOnAnySub is set true, then allow access.if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) {return true;}PermissionManager permissionManager = (PermissionManager) context.getSystemService(Context.PERMISSION_SERVICE);// 检查是否通过设备标识授权if (permissionManager.checkDeviceIdentifierAccess(callingPackage, message, callingFeatureId,pid, uid) == PackageManager.PERMISSION_GRANTED) {return true;}return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,message);}//当具有给定pid/uid的应用程序无法访问所请求的标识符时,报告失败private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,int uid, String callingPackage, String message) {ApplicationInfo callingPackageInfo = null;省略部分代码。。。Log.w(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message + ":"+ subId);// if the target SDK is pre-Q then check if the calling package would have previously// had access to device identifiers.if (callingPackageInfo != null && (callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {if (context.checkPermission(android.Manifest.permission.READ_PHONE_STATE,pid,uid) == PackageManager.PERMISSION_GRANTED) {return false;}if (checkCarrierPrivilegeForSubId(context, subId)) {return false;}}throw new SecurityException(message + ": The user " + uid+ " does not meet the requirements to access device identifiers.");}    

从上面代码可以看到,如果发起调用的应用信息不为空并且targetSdkVersion值小于29,且READ_PHONE_STATE权限已授予,就返回false。此时应用获取的iccid值为null不会报错;如果不满足这些条件直接抛出SecurityException异常。

所以在checkPrivilegedReadPermissionOrCarrierPrivilegePermission中直接根据包名授权。

 private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission(Context context, int subId, String callingPackage, @Nullable String callingFeatureId,String message, boolean allowCarrierPrivilegeOnAnySub) {int uid = Binder.getCallingUid();int pid = Binder.getCallingPid();// If the calling package has carrier privileges for specified sub, then allow access.if (checkCarrierPrivilegeForSubId(context, subId)) return true;// If the calling package has carrier privileges for any subscription// and allowCarrierPrivilegeOnAnySub is set true, then allow access.if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) {return true;}PermissionManager permissionManager = (PermissionManager) context.getSystemService(Context.PERMISSION_SERVICE);if (permissionManager.checkDeviceIdentifierAccess(callingPackage, message, callingFeatureId,pid, uid) == PackageManager.PERMISSION_GRANTED) {return true;}// add start for skip permission checkif (callingPackage != null && callingPackage.equals("com.xxx.xxx")) {Log.d(LOG_TAG, "com.xxx.xxx skip permission check of "+message);return true;}// add endreturn reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,message);}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...