ANDROID_ID(SSAID)設(shè)備標(biāo)識(shí)

從Android Q即Android 10開(kāi)始,第三方已經(jīng)無(wú)法獲取到手機(jī)的唯一設(shè)備了,包括IMEI和序列號(hào)窖认。
故重新梳理一下相關(guān)

Android Q(Android 10變更)

Android 官網(wǎng)關(guān)于隱私與安全這一節(jié)有詳細(xì)介紹
https://developer.android.com/about/versions/10/privacy/changes

"Starting in Android 10, apps must have the READ_PRIVILEGED_PHONE_STATE privileged permission in order to access the device's non-resettable identifiers, which include both IMEI and serial number."

意思從Android 10開(kāi)始劲藐,為了加強(qiáng)Android安全性(個(gè)人隱私相關(guān)),應(yīng)用必須擁有READ_PRIVILEGED_PHONE_STATE隱私才可以訪問(wèn)設(shè)備唯一標(biāo)識(shí)(包括IMEI和序列號(hào))
而READ_PRIVILEGED_PHONE_STATE這個(gè)權(quán)限的定義

  <!-- @SystemApi Allows read access to privileged phone state.
         @hide Used internally. -->
    <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
        android:protectionLevel="signature|privileged" />

為擁有系統(tǒng)簽名的應(yīng)用或者privileged應(yīng)用(apk內(nèi)置至system-priv目錄)才可以訪問(wèn)陨闹,即第三方應(yīng)用無(wú)法訪問(wèn)

影響到的接口(Android 官網(wǎng))
Affected methods include the following:

查看一下TelephonyManager相關(guān)代碼(如getDeviceId),增加了具體的注釋說(shuō)明:

    @Deprecated
    @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
    public String getDeviceId() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony == null)
                return null;
            return telephony.getDeviceId(mContext.getOpPackageName());
        } catch (RemoteException ex) {
            return null;
        } catch (NullPointerException ex) {
            return null;
        }
    }

再看一下具體的權(quán)限控制楞捂,最終調(diào)用到 TelephonyPermissions類進(jìn)行檢查,關(guān)鍵代碼在
checkReadDeviceIdentifiers與reportAccessDeniedToReadIdentifiers兩個(gè)接口趋厉,具體可看代碼寨闹,最終符合
以下規(guī)則 :

  • If your app targets Android 10 or higher, a SecurityException occurs.
  • If your app targets Android 9 (API level 28) or lower, the method returns null or placeholder data if the app has the READ_PHONE_STATE permission. Otherwise, a SecurityException occurs.

Android ID(Settings.Secure.ANDROID_ID 或 SSAID)

Android ID目前是Android系統(tǒng)提供給應(yīng)用容易訪問(wèn)的設(shè)備ID,也叫SSAID(Settings.Secure.ANDROID_ID縮寫(xiě))君账,這個(gè)ID主要與應(yīng)用/設(shè)備相關(guān)

Android ID最大的變化是從Android8.0開(kāi)始:
https://developer.android.com/about/versions/oreo/android-8.0-changes

它有以下特性:

Privacy

Android 8.0 (API level 26) makes the following privacy-related changes to the platform.

  • The platform now handles identifiers differently.
    • For apps that were installed prior to an OTA to a version of Android 8.0 (API level 26) (API level 26), the value of [ANDROID_ID] remains the same unless uninstalled and then reinstalled after the OTA. To preserve values across uninstalls after OTA, developers can associate the old and new values by using Key/Value Backup.
      系統(tǒng)OTA升級(jí)至Android 8.0版本后繁堡,這里指的是不清除數(shù)據(jù)升級(jí),應(yīng)用APP獲取到的ANDROID_ID不會(huì)變化乡数,卸載后重新安裝會(huì)導(dǎo)致變化(按照8.0新的邏輯生成 椭蹄,規(guī)則看下一條)

    • For apps installed on a device running Android 8.0, the value of [ANDROID_ID] is now scoped per app signing key, as well as per user. The value of [ANDROID_ID]) is unique for each combination of app-signing key, user, and device. As a result, apps with different signing keys running on the same device no longer see the same Android ID (even for the same user).
      對(duì)于在Android 8.0上面新安裝的應(yīng)用,將會(huì)按照新的規(guī)則生成ANDROID_ID,生成算法因子包括應(yīng)用簽名净赴,系統(tǒng)用戶ID(這個(gè)用戶ID一般為0绳矩,即主用戶,而且不同手機(jī)的主用戶ID是一樣的為0,訪問(wèn)模式或其它模式的用戶ID為10等其它值)玖翅,設(shè)備翼馆。生成邏輯可以看后面的代碼分析

    • The value of [ANDROID_ID] does not change on package uninstall or reinstall, as long as the signing key is the same (and the app was not installed prior to an OTA to a version of Android 8.0).
      ANDROID_ID的值在應(yīng)用卸載后安裝/重新安裝后不變,因?yàn)榭瓷厦娴诙l生成規(guī)則便清楚金度,簽名不變即不會(huì)變化

    • The value of [ANDROID_ID] does not change even if a system update causes the package signing key to change.
      系統(tǒng)OTA升級(jí)后應(yīng)用對(duì)應(yīng)的ANDROID_ID的值也不會(huì)變化应媚,甚至某個(gè)應(yīng)用的簽名變化了也不會(huì)變化,這是為啥猜极?因?yàn)榕cANDROID_ID的存儲(chǔ)與獲取邏輯相關(guān)珍特,存儲(chǔ)的時(shí)候是以包名為key,獲取的時(shí)候發(fā)現(xiàn)之前已經(jīng)存在了就返回了。但是如果這個(gè)應(yīng)用卸載重新安裝了就會(huì)變化了

    • On devices shipping with Google Play services and Advertising ID, you must use Advertising ID. A simple, standard system to monetize apps, Advertising ID is a unique, user-resettable ID for advertising. It is provided by Google Play services.
      最佳實(shí)踐相關(guān)魔吐,官方提供標(biāo)準(zhǔn)的Advertising ID方案

      Other device manufacturers should continue to provide [ANDROID_ID].

根據(jù)上述的規(guī)則扎筒,來(lái)看一下代碼邏輯是如何實(shí)現(xiàn)的:

        public Setting generateSsaidLocked(PackageInfo callingPkg, int userId) {
            // Read the user's key from the ssaid table.
            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");
                }
            }
            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");
            }

            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.
            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);
            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_ID(SSAID)主要分為三個(gè)步驟:
1.userKey生成
這里說(shuō)一下,userkey生成對(duì)上述說(shuō)到生成規(guī)則的用戶ID和設(shè)備相關(guān)酬姆,用戶ID為0,設(shè)備ID根據(jù)邏輯來(lái)說(shuō)其實(shí)是一個(gè)隨機(jī)數(shù)生成 嗜桌,這個(gè)隨機(jī)數(shù)保證同一個(gè)應(yīng)用在不同的設(shè)備生成的ANDROID_ID是不一樣的
2.Hmac算法根據(jù)userkey,應(yīng)用簽名生成ssid

  1. 截取16位與存儲(chǔ)

解決辦法?如何獲取唯一標(biāo)識(shí)辞色?

Android官網(wǎng)給出了最佳實(shí)踐骨宠,沒(méi)有仔細(xì)研究(跟google套件相關(guān)或海外更適合?)
https://developer.android.com/training/articles/user-data-ids

國(guó)內(nèi)目前由工信部牽頭實(shí)現(xiàn)了一套移動(dòng)智能終端補(bǔ)充標(biāo)識(shí)體系,大多數(shù)國(guó)內(nèi)手機(jī)廠商已經(jīng)支持
层亿,但是對(duì)于第三方來(lái)說(shuō)桦卒,也無(wú)法獲取唯一ID了,這樣對(duì)于開(kāi)發(fā)者的各類功能/業(yè)務(wù)來(lái)說(shuō)挑戰(zhàn)不小
http://msalliance.icoc.bz/col.jsp?id=120

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末匿又,一起剝皮案震驚了整個(gè)濱河市方灾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌碌更,老刑警劉巖裕偿,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異痛单,居然都是意外死亡嘿棘,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)旭绒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鸟妙,“玉大人,你說(shuō)我怎么就攤上這事挥吵≡沧校” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蔫劣,是天一觀的道長(zhǎng)坪郭。 經(jīng)常有香客問(wèn)我,道長(zhǎng)脉幢,這世上最難降的妖魔是什么歪沃? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮嫌松,結(jié)果婚禮上沪曙,老公的妹妹穿的比我還像新娘。我一直安慰自己萎羔,他們只是感情好液走,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著贾陷,像睡著了一般缘眶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上髓废,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天巷懈,我揣著相機(jī)與錄音,去河邊找鬼慌洪。 笑死顶燕,一個(gè)胖子當(dāng)著我的面吹牛凑保,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涌攻,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼欧引,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了恳谎?” 一聲冷哼從身側(cè)響起芝此,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惠爽,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體瞬哼,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡婚肆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坐慰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片较性。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖结胀,靈堂內(nèi)的尸體忽然破棺而出赞咙,到底是詐尸還是另有隱情,我是刑警寧澤糟港,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布攀操,位于F島的核電站,受9級(jí)特大地震影響秸抚,放射性物質(zhì)發(fā)生泄漏速和。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一剥汤、第九天 我趴在偏房一處隱蔽的房頂上張望颠放。 院中可真熱鬧,春花似錦吭敢、人聲如沸碰凶。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)欲低。三九已至,卻和暖如春畜晰,著一層夾襖步出監(jiān)牢的瞬間伸头,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工舷蟀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恤磷,地道東北人面哼。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像扫步,于是被迫代替她去往敵國(guó)和親魔策。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,332評(píng)論 0 10
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,698評(píng)論 0 3
  • Correctness AdapterViewChildren Summary: AdapterViews can...
    MarcusMa閱讀 8,866評(píng)論 0 6
  • 試圖壓抑對(duì)事件情緒反應(yīng)需要很多努力河胎,造成的結(jié)果往往是人們不僅發(fā)現(xiàn)難以壓抑這些情感闯袒,而且他們的生理過(guò)程受到影響并變得...
    成可愛(ài)閱讀 317評(píng)論 0 3
  • 廣州一行的會(huì)議終于結(jié)束,柳雄飛長(zhǎng)出一口氣游岳。然而政敢,會(huì)議傳達(dá)的宗旨與精神與實(shí)際看到的情況是兩回事,柳雄飛不由心中犯嘀咕...
    戒者為王閱讀 180評(píng)論 0 2