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);

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐