系统源码分析-android_id 生成

本文深入探讨了Android设备上Android ID的生成与保存过程,详细分析了从Android 8.0之前的系统级生成到8.0后应用级生成的变化,包括随机生成、保存位置及生成规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码的查看推荐在AndroidXRef进行查看。

1.一般我们获取android_id是通过以下的方式进行获取

Settings.System.getString(context.contentResolver, Settings.System.ANDROID_ID)

跟踪android.provider.Settings中的getString方法

private static final HashSet<String> MOVED_TO_SECURE;
        static {
            MOVED_TO_SECURE = new HashSet<>(30);
			//(1)这里设置了android_id的常量
            MOVED_TO_SECURE.add(Secure.ANDROID_ID);
            MOVED_TO_SECURE.add(Secure.HTTP_PROXY);
           ....

            // At one time in System, then Global, but now back in Secure
            MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS);
        }


public static String getString(ContentResolver resolver, String name) {
            return getStringForUser(resolver, name, resolver.getUserId());
        }

        /** @hide */
        @UnsupportedAppUsage
        public static String getStringForUser(ContentResolver resolver, String name,
                int userHandle) {
			//(2)通过判断name进行调用不同的对象的方法 ,从(1)中可以看到是MOVED_TO_SECURE包含了android_id
            if (MOVED_TO_SECURE.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Secure, returning read-only value.");
                return Secure.getStringForUser(resolver, name, userHandle);
            }
            if (MOVED_TO_GLOBAL.contains(name) || MOVED_TO_SECURE_THEN_GLOBAL.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Global, returning read-only value.");
                return Global.getStringForUser(resolver, name, userHandle);
            }
            return sNameValueCache.getStringForUser(resolver, name, userHandle);
        }

接着跟踪Secure.getStringForUser(resolver, name, userHandle)方法。这是Settings一个内部类

android.provider.Settings.Secure

public static final class Secure extends NameValueTable {
        // NOTE: If you add new settings here, be sure to add them to
        // com.android.providers.settings.SettingsProtoDumpUtil#dumpProtoSecureSettingsLocked.

       .....

        /**
         * Look up a name in the database.
         * @param resolver to access the database with
         * @param name to look up in the table
         * @return the corresponding value, or null if not present
         */
        public static String getString(ContentResolver resolver, String name) {
            return getStringForUser(resolver, name, resolver.getUserId());
        }

        /** @hide */
        @UnsupportedAppUsage
        public static String getStringForUser(ContentResolver resolver, String name,
                int userHandle) {
            if (MOVED_TO_GLOBAL.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
                        + " to android.provider.Settings.Global.");
                return Global.getStringForUser(resolver, name, userHandle);
            }

            if (MOVED_TO_LOCK_SETTINGS.contains(name)) {
                .......
            }
			//由于MOVED_TO_GLOBAL和MOVED_TO_LOCK_SETTINGS都没有包含android_id,所以调用了下面的这个方法
            return sNameValueCache.getStringForUser(resolver, name, userHandle);
        }
		}

跟踪 android.provider.Settings.NameValueCache  中的getStringForUser方法

@UnsupportedAppUsage
        public String getStringForUser(ContentResolver cr, String name, final int userHandle) {
            .....

			//(1)通过mProviderHolder获取provide对象
            IContentProvider cp = mProviderHolder.getProvider(cr);

            // Try the fast path first, not using query().  If this
            // fails (alternate Settings provider that doesn't support
            // this interface?) then we fall back to the query/table
            // interface.
            if (mCallGetCommand != null) {
                try {
                    ....
                    Bundle b;
                    // If we're in system server and in a binder transaction we need to clear the
                    // calling uid. This works around code in system server that did not call
                    // clearCallingIdentity, previously this wasn't needed because reading settings
                    // did not do permission checking but thats no longer the case.
                    // Long term this should be removed and callers should properly call
                    // clearCallingIdentity or use a ContentResolver from the caller as needed.
                    if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
                        final long token = Binder.clearCallingIdentity();
                        try {
						    //(2) 通过(1)中获取的provide在这里获取android_id的值
                            b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
                                    mCallGetCommand, name, args);
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    } else {
                        b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
                                mCallGetCommand, name, args);
                    }
                    if (b != null) {
                        ......
                    }
                    // If the response Bundle is null, we fall through
                    // to the query interface below.
                } catch (RemoteException e) {
                    // Not supported by the remote side?  Fall through
                    // to query().
                }
            }

            ...
        }

由以上的代码可以看到是通过provide进行获取android_id的值,接下来我们跟踪这个provide是哪里提供的

android.provider.Settings.java

private final ContentProviderHolder mProviderHolder;

        // The method we'll call (or null, to not use) on the provider
        // for the fast path of retrieving settings.
        private final String mCallGetCommand;
        private final String mCallSetCommand;

        @GuardedBy("this")
        private GenerationTracker mGenerationTracker;

        public NameValueCache(Uri uri, String getCommand, String setCommand,
                ContentProviderHolder providerHolder) {
            mUri = uri;
            mCallGetCommand = getCommand;
            mCallSetCommand = setCommand;
			//(1)NameValueCache对象初始化的时候会初始化providerHolder对象
            mProviderHolder = providerHolder;
        }
		
		
		//(3)初始化sProviderHolder 对象
		private static final ContentProviderHolder sProviderHolder =
                new ContentProviderHolder(DeviceConfig.CONTENT_URI);

        // Populated lazily, guarded by class object:
        private static final NameValueCache sNameValueCache = new NameValueCache(
                DeviceConfig.CONTENT_URI,
                CALL_METHOD_GET_CONFIG,
                CALL_METHOD_PUT_CONFIG,
				//(2)在这里进行NameValueCache对象初始化
                sProviderHolder);
				
				
				
	//(4) android.provider.DeviceConfig.java 中的常量	
	public static final Uri CONTENT_URI = Uri.parse("content://" + Settings.AUTHORITY + "/config");
	
	//(5) android.provider.Settings.java 中的常量
	public static final String AUTHORITY = "settings";

以上的代码除了(4)以外都是在Settings.java中,最后我们得到“content://settings/config”

通过上面的查询可以发现,是frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java这个类提供了接口。

frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java

跟踪SettingsProvide.java 中的onCreate的方法

@Override
302    public boolean onCreate() {
303        Settings.setInSystemServer();
304
305        // fail to boot if there're any backed up settings that don't have a non-null validator
306        ensureAllBackedUpSystemSettingsHaveValidators();
307        ensureAllBackedUpGlobalSettingsHaveValidators();
308        ensureAllBackedUpSecureSettingsHaveValidators();
309
310        synchronized (mLock) {
311            mUserManager = UserManager.get(getContext());
312            mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
313            mPackageManager = AppGlobals.getPackageManager();
314            mHandlerThread = new HandlerThread(LOG_TAG,
315                    Process.THREAD_PRIORITY_BACKGROUND);
316            mHandlerThread.start();
317            mHandler = new Handler(mHandlerThread.getLooper());
				//对Setting内容进行初始化
318            mSettingsRegistry = new SettingsRegistry();
319        }
320        mHandler.post(() -> {
321            registerBroadcastReceivers();
322            startWatchingUserRestrictionChanges();
323        });
324        ServiceManager.addService("settings", new SettingsService(this));
325        return true;
326    }

frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java  -》SettingsRegistry

public SettingsRegistry() {
2133            mHandler = new MyHandler(getContext().getMainLooper());
2134            mGenerationRegistry = new GenerationRegistry(mLock);
2135            mBackupManager = new BackupManager(getContext());
				//(1)初始化所有常量
2136            migrateAllLegacySettingsIfNeeded();
2137            syncSsaidTableOnStart();
2138        }

private void migrateAllLegacySettingsIfNeeded() {
2585            synchronized (mLock) {
2586                final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
2587                File globalFile = getSettingsFile(key);
2588                if (SettingsState.stateFileExists(globalFile)) {
2589                    return;
2590                }
2591
2592                mSettingsCreationBuildId = Build.ID;
2593
2594                final long identity = Binder.clearCallingIdentity();
2595                try {
2596                    List<UserInfo> users = mUserManager.getUsers(true);
2597
2598                    final int userCount = users.size();
2599                    for (int i = 0; i < userCount; i++) {
2600                        final int userId = users.get(i).id;
2601
2602                        DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
2603                        SQLiteDatabase database = dbHelper.getWritableDatabase();
							//(2)通过获取本地文件进行初始化操作
2604                        migrateLegacySettingsForUserLocked(dbHelper, database, userId);
2605
2606                        // Upgrade to the latest version.
2607                        UpgradeController upgrader = new UpgradeController(userId);
2608                        upgrader.upgradeIfNeededLocked();
2609
2610                        // Drop from memory if not a running user.
2611                        if (!mUserManager.isUserRunning(new UserHandle(userId))) {
2612                            removeUserStateLocked(userId, false);
2613                        }
2614                    }
2615                } finally {
2616                    Binder.restoreCallingIdentity(identity);
2617                }
2618            }
2619        }


private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
2636                SQLiteDatabase database, int userId) {
2637            // Move over the system settings.
2638            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
2639            ensureSettingsStateLocked(systemKey);
2640            SettingsState systemSettings = mSettingsStates.get(systemKey);
2641            migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
2642            systemSettings.persistSyncLocked();
2643
2644            // Move over the secure settings.
2645            // Do this after System settings, since this is the first thing we check when deciding
2646            // to skip over migration from db to xml for a secondary user.
2647            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
2648            ensureSettingsStateLocked(secureKey);
2649            SettingsState secureSettings = mSettingsStates.get(secureKey);
2650            migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);
				//(3)判断android_id进行初始化
2651            ensureSecureSettingAndroidIdSetLocked(secureSettings);
2652            secureSettings.persistSyncLocked();
2653
				.......
2677        }


private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
2714            Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
2715
2716            if (!value.isNull()) {
2717                return;
2718            }
2719
2720            final int userId = getUserIdFromKey(secureSettings.mKey);
2721
2722            final UserInfo user;
2723            final long identity = Binder.clearCallingIdentity();
2724            try {
2725                user = mUserManager.getUserInfo(userId);
2726            } finally {
2727                Binder.restoreCallingIdentity(identity);
2728            }
2729            if (user == null) {
2730                // Can happen due to races when deleting users - treat as benign.
2731                return;
2732            }
2733			//(4)这里进行了随机生成android_id并保存到本地文件中
2734            String androidId = Long.toHexString(new SecureRandom().nextLong());
2735            secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
2736                    null, true, SettingsState.SYSTEM_PACKAGE_NAME);
2737
2738            Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
2739                    + "] for user " + userId);
2740
2741            // Write a drop box entry if it's a restricted profile
2742            if (user.isRestricted()) {
2743                DropBoxManager dbm = (DropBoxManager) getContext().getSystemService(
2744                        Context.DROPBOX_SERVICE);
2745                if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
2746                    dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
2747                            + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n");
2748                }
2749            }
2750        }

在上面的流程中,通过获取本地的文件,进行对系统的一些基本的信息进行初始化,并保存到不同的文件中

android_id保存的文件路径: /data/system/users/0/settings_secure.xml

以上获取随机的android_id,并保存到本地文件之后。

我们通过provider就是通过这里的call方法去读取settings_secure.xml中的android_id的值

--------------------------------------------------android8.0后的android_id生成---------------------------------

由于在android8.0之后,应用的android_id 生成规则发生改变,不再和系统的android_id值一致,每个应用都在安装的时候拥有了自己的独特的android_id的值,并且有固定的生成规则

8.0后的android_id的生成规则也是在 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java中的generateSsaidLocked方法中

public Setting generateSsaidLocked(PackageInfo callingPkg, int userId) {
            // Read the user's key from the ssaid table.
            //(1)获取系统的userkey值的setting对象
            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.
                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");
                }
            }
            //(2)获取userkey的值,值的位置在/data/system/users/0/settings_ssaid.xml中的userkey的值
            final String userKey = userKeySetting.getValue();
            if (userKey == null || userKey.length() % 2 != 0) {
                throw new IllegalStateException("User key invalid");
            }

            // Convert the user's key back to a byte array.
            final byte[] keyBytes = HexEncoding.decode(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.length != 16 && keyBytes.length != 32) {
                throw new IllegalStateException("User key invalid");
            }

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

            // Mac each of the developer signatures.
            //(3)获取应用相关的签名信息
            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.
            //(4) 通过以上获取的签名,userkey等信息生成独特的android_id
            final String ssaid = HexEncoding.encodeToString(m.doFinal(), false /* upperCase */)
                    .substring(0, 16);

            // Save the ssaid in the ssaid table.
            final String uid = Integer.toString(callingPkg.applicationInfo.uid);
            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);
        }

从以上的代码中可以看到主要的生成规则和影响由于主要的用户组都是0,其中影响android_id 的就是/data/system/users/0/settings_ssaid.xml中的userkey值(这个值只会在系统第一次启动时随机,并且之后不会改变),和应用本身的签名,生成新的android_id之后,会保存在/data/system/users/0/settings_ssaid.xml中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值