@SuppressAutoDoc
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getSimSerialNumber() {
return getSimSerialNumber(getSubId());
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@UnsupportedAppUsage
public 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) {
return 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> T callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(int subId,
String callingPackage, @Nullable String callingFeatureId, String message,
CallPhoneMethodHelper<T> callMethodHelper) {
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 (checkCarrierPrivilegeForSubId(context, subId)) return true;
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);
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 (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 (checkCarrierPrivilegeForSubId(context, subId)) return true;
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;
if (callingPackage != null && callingPackage.equals("com.xxx.xxx")) {
Log.d(LOG_TAG, "com.xxx.xxx skip permission check of "+message);
return true;
return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
message);
android 11 发布了
android 11 以前使用的MAC的设备唯一码的方式被废弃了,因为11不让用了,然后就去官方上找推荐了;
之前的获取MAC的地址,有兴趣的可以点进去看看
官方推荐使用UUID ;这个好像目前几个大厂的APP都在使用的方法
具体的就直接上代码吧;
下面的代码直接获取UUID
public static String getUUID() {
return UUID.randomUUID().toString().replaceAll("-", "");
//获取IMEI码
TelephonyManager telephonyManager = (TelephonyManager) this
.getSystemService(Context.TELEPHONY_SERVICE);
String IMEI = t...
按照正常的获取在Android 8.0 之前都是可以拿到我们的Imei码的,就是广为流传的那些形式,我就意义赘述了,到了Android 9.0 之后就出现了部分手机厂商的机型获取不到我们的IMEI码,例如 '‘一加’'等厂商,而且其他厂商的在获取的时候也需要获取我们的
READ_PHONE_STATE权限
不过也能在大部分的手机上通用;也不算太大的缺点,但是到了我们的Android 10 开始,...