赞
踩
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获取 value
- String 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' data
- if (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 id
- mValues.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 id
- Slog.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 对应的 setting
- final Setting ssaid = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId,
- name);
- //获取 setting对应的SettingsState
- final SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked(
- SETTINGS_TYPE_SSAID, owningUserId);
- //如果 app 对应的setting 不存在,就重新生成 走到这里生成userkey
- if (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 userkey
- Slog.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 id
- final 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);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。