android_id 的生成原理是由系统生成的随机数,并与应用 app 签名,经过 HmacSHA256 算法生成的;
从 android 8 以后开始就是随机的了,每个应用获取到的简要步骤;
获取的方式如下所示:

androidId = android.provider.Settings.Secure.getString(context.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
 public String getStringForUser(ContentResolver cr, String name, final int userHandle) {final boolean isSelf = (userHandle == UserHandle.myUserId());if (isSelf) {synchronized (NameValueCache.this) {if (mGenerationTracker != null) {if (mGenerationTracker.isGenerationChanged()) {if (true) {Log.i(TAG, "Generation changed for type:"+ mUri.getPath() + " in package:"+ cr.getPackageName() +" and user:" + userHandle);}mValues.clear();} else if (mValues.containsKey(name)) {//如果APP已经安装第二次读取位置Log.v(TAG, "getStringForUser clear name= " + name  + " key: " + mValues.get(name));mValues.remove(name);// return mValues.get(name);}}}final long token = Binder.clearCallingIdentity();try {Log.w(TAG, "call here ------" );b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);} finally {Binder.restoreCallingIdentity(token);}} else {b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);}if (b != null) {//这里 call getSecureSetting获取 valueString value = b.getString(Settings.NameValueTable.VALUE);Log.w(TAG, "NameValueCache b.getString(Settings " + value + " isSelf " + isSelf + " needsGenerationTracker " + needsGenerationTracker);Log.w(TAG, "NameValueCache value " + value);// Don't update our cache for reads of other users' dataif (isSelf) {synchronized (NameValueCache.this) {if (needsGenerationTracker) {MemoryIntArray array = b.getParcelable(CALL_METHOD_TRACK_GENERATION_KEY);final int index = b.getInt(CALL_METHOD_GENERATION_INDEX_KEY, -1);if (array != null && index >= 0) {final int generation = b.getInt(CALL_METHOD_GENERATION_KEY, 0);if (true) {Log.i(TAG, "Received generation tracker for type:"+ mUri.getPath() + " in package:"+ cr.getPackageName() + " and user:"+ userHandle + " with index:" + index);}if (mGenerationTracker != null) {mGenerationTracker.destroy();}mGenerationTracker = new GenerationTracker(array, index,generation, () -> {synchronized (NameValueCache.this) {Log.e(TAG, "Error accessing generation"+ " tracker - removing");if (mGenerationTracker != null) {GenerationTracker generationTracker =mGenerationTracker;mGenerationTracker = null;generationTracker.destroy();mValues.clear();}}});}}//第一次APP安装执行到这里,保存生成的Android idmValues.put(name, value);}

首先从缓存mValues变量中去找,如果没有查询到,就调用SettingsProvider的call()接口,如果call()接口也没有查询到,再调用query()接口。这里用的是call()接口,下文就以call()接口往下分析。cp.call()会调用到SettingsProvider的call()方法
APP安装后第一次尝试读取Android id ,mValues 一定为NULL,所有就会调用SettingsProvider 相关接口读取Android id。读取成功会保存到mValues缓存中。
frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
接着会调用到SettingsProvider.java内部函数getSecureSetting

private Setting getSecureSetting(String name, int requestingUserId) {执行到这里说明此App在缓存中不存在。在这里获取 if (isNewSsaidSetting(name)) {PackageInfo callingPkg = getCallingPackageInfo(owningUserId);synchronized (mLock) {//getStringForUser -> getSecureSetting ,进入下一步生成android idSlog.e(LOG_TAG, "getSecureSetting to getSsaidSettingLocked " +  callingPkg.packageName + " owningUserId " +   owningUserId);return getSsaidSettingLocked(callingPkg, owningUserId);}}
}
 private Setting getSsaidSettingLocked(PackageInfo callingPkg, int owningUserId) {//首先获取APP的 userid,因为Android id 是根据 key = userid 保存在文件和settings中String name = Integer.toString(UserHandle.getUid(owningUserId, UserHandle.getAppId(Binder.getCallingUid())));//获取msettings 保存的 app 的 android id 对应的 settingfinal Setting ssaid = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId,name);//获取 setting对应的SettingsStatefinal SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked(SETTINGS_TYPE_SSAID, owningUserId);//如果 app 对应的setting 不存在,就重新生成 走到这里生成userkeyif (ssaid == null || ssaid.isNull() || ssaid.getValue() == null) {Slog.e(LOG_TAG, "ssaid is null . go generate====");Setting setting = mSettingsRegistry.generateSsaidLocked(callingPkg, owningUserId);return mascaradeSsaidSetting(ssaidSettings, setting);}return mascaradeSsaidSetting(ssaidSettings, ssaid);}

上段代码主要是获取相关的app 对应的setting ,获取不到就重新生成一个。
下面就进入到真正生成Android id的相关逻辑流程

        public Setting generateSsaidLocked(PackageInfo callingPkg, int userId) {// Read the user's key from the ssaid table.//这里获取生成Android id所用的系统随机数Setting userKeySetting = getSettingLocked(SETTINGS_TYPE_SSAID, userId, SSAID_USER_KEY);if (userKeySetting == null || userKeySetting.isNull()|| userKeySetting.getValue() == null) {// Lazy initialize and store the user key.//如果默认的系统key不存在,这里生成默认Android userkeySlog.e(LOG_TAG, "generateSsaidLocked -------");generateUserKeyLocked(userId);userKeySetting = getSettingLocked(SETTINGS_TYPE_SSAID, userId, SSAID_USER_KEY);if (userKeySetting == null || userKeySetting.isNull()|| userKeySetting.getValue() == null) {throw new IllegalStateException("User key not accessible");}}final String userKey = userKeySetting.getValue();// Convert the user's key back to a byte array.final byte[] keyBytes = ByteStringUtils.fromHexToByteArray(userKey);// Validate that the key is of expected length.// Keys are currently 32 bytes, but were once 16 bytes during Android O development.if (keyBytes == null || (keyBytes.length != 16 && keyBytes.length != 32)) {throw new IllegalStateException("User key invalid");}//下面就是对APP做相关的算法生成Android idfinal Mac m;try {m = Mac.getInstance("HmacSHA256");m.init(new SecretKeySpec(keyBytes, m.getAlgorithm()));} catch (NoSuchAlgorithmException e) {throw new IllegalStateException("HmacSHA256 is not available", e);} catch (InvalidKeyException e) {throw new IllegalStateException("Key is corrupted", e);}Slog.e(LOG_TAG, "generateSsaidLocked -------Mac " +  m);// Mac each of the developer signatures.for (int i = 0; i < callingPkg.signatures.length; i++) {byte[] sig = callingPkg.signatures[i].toByteArray();m.update(getLengthPrefix(sig), 0, 4);m.update(sig);}// Convert result to a string for storage in settings table. Only want first 64 bits.final String ssaid = ByteStringUtils.toHexString(m.doFinal()).substring(0, 16).toLowerCase(Locale.US);// Save the ssaid in the ssaid table.final String uid = Integer.toString(callingPkg.applicationInfo.uid);生成新的Android id 插入到msetting表中和写入到ssid.xml中final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);final boolean success = ssaidSettings.insertSettingLocked(uid, ssaid, null, true,callingPkg.packageName);if (!success) {throw new IllegalStateException("Ssaid settings not accessible");}return getSettingLocked(SETTINGS_TYPE_SSAID, userId, uid);}

Android生成 userkey 所用的生成随机数的代码如下所示。

 final byte[] keyBytes1 = new byte[32];final SecureRandom rand1 = new SecureRandom();rand1.nextBytes(keyBytes1);final String userKey = ByteStringUtils.toHexString(keyBytes1);

安卓获取APP对应的Android id的原理分析相关推荐

  1. 您的应用审核未通过,在用户同意隐私政策前,您的应用获取了用户的ANDROID ID

    您的应用审核未通过.在用户同意隐私政策前,您的应用获取了用户的ANDROID ID,不符合华为应用市场审核标准.修改建议:请在用户同意隐私政策后,再申请获取用户个人信息及权限.请参考<审核指南& ...

  2. 在用户同意隐私政策前,您的应用获取了用户的ANDROID ID,不符合华为应用市场审核标准。

    环境 Android Studio Bumblebee, Mac mini 2014 问题描述 在发布应用到华为应用市场时,提示"在用户同意隐私政策前,您的应用获取了用户的ANDROID I ...

  3. 可能是最详细的Android图片压缩原理分析(二)—— 鲁班压缩算法解析

    本篇文章已授权微信公众号guolin_blog(郭霖)独家发布 稀土掘金链接 前言 通过上一篇,我们了解了一些关于图片压缩的基础知识,这篇文章我们主要讲解一下鲁班压缩的算法逻辑,很多博客都是从Gith ...

  4. 可能是最详细的Android图片压缩原理分析(一)—— Android图片压缩必备基础知识

    本篇文章已授权微信公众号guolin_blog(郭霖)独家发布 稀土掘金链接 前言: 最近在研究图片压缩原理,看了大量资料,从上层尺寸压缩.质量压缩原理到下层的哈夫曼压缩,走成华大道,然后去二仙桥,全 ...

  5. 支付宝app支付java后台流程、原理分析(含nei wang chuan tou)

    java版支付宝app支付流程及原理分析 本实例是基于springmvc框架编写      一.流程步骤          1.执行流程            当手机端app(就是你公司开发的app) ...

  6. Camera2 APP Flash 打闪流程及原理分析

    Camera Flash打闪流程梳理 Flash打闪的条件有两个一个是AE_Mode 一个是Flash Mode两个参数决定Flash打闪的过程. Flash mode有四个状态 AUTO OFF O ...

  7. android获取app用户数据,Android 原生app获取用户授权访问Autodesk云应用数据

    oAuth机制对于网站间的授权管理是很容易实现的,设置好app回调端口,当数据服务提供方拿到其用户授权,则返回授权码发送到回调端口.上一篇文章介绍了如何授权Forge app访问Autodesk 云应 ...

  8. android获取app内存信息,Android 获取内存信息(RAM,ROM)

    一.RAM,ROM简单介绍 RAM为运行内存,比如,360手机助手的悬浮窗,经常提示的运行内存超过80%之类的,指的都是运行内存.一般大小为几个G. ROM为存储数据的内存,比如,爱奇艺APP在视频页 ...

  9. android 怎么获取app 字体颜色,Android APP使用自定义字体实现方法

    android系统内置字体 android 系统本身内置了一些字体,可以在程序中使用,并且支持在xml配置textView的时候进行修改字体的样式.支持字段为android:textStyle ,an ...

最新文章

  1. Linux命令基础--uname
  2. windows 服务开发教程
  3. Python - 移除List中重复项的五种常用方法
  4. bzoj1564: [NOI2009]二叉查找树
  5. 前端学习(511):两列布局的第一种方式
  6. String s1==s2面试题
  7. UIAlertView, UIAlertViewController
  8. eclipse没有Web分支Dynamic Web Project
  9. explain是mysql的关键字吗_Mysql Explain 关键字
  10. shiro—登录拦截
  11. stata中安装meta分析模块
  12. Python打造qq音乐歌曲下载器
  13. python当前时间获取_python 当前时间获取方法
  14. 淘宝母婴商品分析-Python
  15. 黎曼猜想--论文笔记《On the Number of Primes Less Than a Given Magnitude》
  16. Dagger2利器系列二:懒/重加载+Component 的组织关系
  17. 推荐一款跨平台视频播放器:ZY-Player
  18. 同步器Synchronizer
  19. r2_score与accuracy_score的区别
  20. Linux---wifi驱动移植及调试(SSV6x5x)

热门文章

  1. Excel如何根据单元格内容插入同名称图片到批注
  2. 从数学角度讲解DH密钥交换算法、非对称加密、数字签名
  3. Git- 连接远程仓库
  4. 谭宁计算机组装与维护,(毕业学术论文设计)-家庭电脑组装方案的设计与分析.doc...
  5. 2021年安全员-C证(陕西省)及安全员-C证(陕西省)证考试
  6. 最便宜android手机型号,价格低但性价比非常高,这三款机型你可吗?
  7. 计算机配置分析,笔记本电脑配置全解析,看完让你轻松选择笔记本
  8. 路漫漫其修远兮,必先苦其心志,劳其筋骨,饿其体肤
  9. CV | Emotionally Enhanced Talking Face Generation论文详解及代码实现
  10. CRM项目,找工作怎么介绍?