android?sharedUserId?使用知識(shí)盲點(diǎn)解析
1. 背景
由于在工程中使用了 SPI 機(jī)制,通過(guò) ServiceLoader 的配合來(lái)完成模塊間的通信。但是突然收到線上客戶反饋使用了 SDK 后無(wú)法進(jìn)行模塊加載,導(dǎo)致部分功能異常。
2. 分析排查
借助客戶提供的測(cè)試包進(jìn)行 debug 調(diào)試,發(fā)現(xiàn)在調(diào)試到 ServiceLoader.load() 方法時(shí)確實(shí)無(wú)法加載到對(duì)應(yīng)的模塊配置。查看 ServiceLoader 的狀態(tài)信息如下:

其中的 loader 是 LoadApk$WarningContextClassLoader 對(duì)象,而正常情況下是 DexPathClassLoader。
2.1 查看 ServiceLoader.loader 定義
ServiceLoader API 文檔:developer.android.com/reference/j…

根據(jù)接口定義 load 方法會(huì)根據(jù)指定的 serviceType 創(chuàng)建新的 ServiceLoader 對(duì)象返回,ServiceLoader 內(nèi)部根據(jù)當(dāng)前線程對(duì)應(yīng)的 ContextClassLoader 對(duì)象去加載配置,所以到這里可以分析到 load 方法的加載結(jié)果會(huì)受 ContextClassLoader 的影響,進(jìn)一步推理可能收到插件化、熱修復(fù)等框架影響,確認(rèn)后并沒(méi)有使插件化、熱修復(fù)等框架。
2.2 WarningContextClassLoader 為何物?
查找 Android famework 源碼,找到 WarningContextClassLoader 是定義在 LoaderApk 文件中的內(nèi)部類(部分版本是 ActivityThread 類中的內(nèi)部類)。
private void initializeJavaContextClassLoader() {
IPackageManager pm = ActivityThread.getPackageManager();
android.content.pm.PackageInfo pi =
PackageManager.getPackageInfoAsUserCached(
mPackageName,
PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.myUserId());
if (pi == null) {
throw new IllegalStateException("Unable to get package info for "
+ mPackageName + "; is package not installed?");
}
/*
* Two possible indications that this package could be
* sharing its virtual machine with other packages:
*
* 1.) the sharedUserId attribute is set in the manifest,
* indicating a request to share a VM with other
* packages with the same sharedUserId.
*
* 2.) the application element of the manifest has an
* attribute specifying a non-default process name,
* indicating the desire to run in another packages VM.
*/
boolean sharedUserIdSet = (pi.sharedUserId != null);
boolean processNameNotDefault =
(pi.applicationInfo != null &&
!mPackageName.equals(pi.applicationInfo.processName));
boolean sharable = (sharedUserIdSet || processNameNotDefault);
ClassLoader contextClassLoader =
(sharable)
? new WarningContextClassLoader()
: mClassLoader;
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
private static class WarningContextClassLoader extends ClassLoader {
private static boolean warned = false;
private void warn(String methodName) {
if (warned) {
return;
}
warned = true;
Thread.currentThread().setContextClassLoader(getParent());
Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " +
"The class loader returned by " +
"Thread.getContextClassLoader() may fail for processes " +
"that host multiple applications. You should explicitly " +
"specify a context class loader. For example: " +
"Thread.setContextClassLoader(getClass().getClassLoader());");
}
...
}
在應(yīng)用創(chuàng)建時(shí)會(huì)調(diào)用 ActivityThread 類中的 attach 方法中,attach 方法進(jìn)而調(diào)用 LoadedApk 類中的 makeApplicationInner() 用于創(chuàng)建對(duì)應(yīng)的 Application 對(duì)象。在 makeApplicationInner() 方法的內(nèi)部調(diào)用 initializeJavaContextClassLoader 方法創(chuàng)建對(duì)應(yīng)的 ContentClassLoader 對(duì)象,在 initializeJavaContextClassLoader 方法的內(nèi)部可以看到,如果當(dāng)前 App 在 manifest 中設(shè)置 sharedUserId 屬性,則當(dāng)前應(yīng)用使用的是 WarningContextClassLoader。下面我們就是查看 App 中的配置。

最終驗(yàn)證了我們的猜想,使用 demo 設(shè)置 sharedUserId 屬性問(wèn)題可正常復(fù)現(xiàn)。
2.3 sharedUserId 屬性
查看官方文檔該屬性配置 API 級(jí)別 29 中已棄用此常量。共享用戶 ID 會(huì)在軟件包管理器中導(dǎo)致具有不確定性的行為。因此,強(qiáng)烈建議您不要使用它,并且我們?cè)谖磥?lái)的 Android 版本中會(huì)將其移除。

2.總結(jié)
排查問(wèn)題還是比較費(fèi)神,在沒(méi)有明顯錯(cuò)誤的時(shí)候,只能針對(duì)每個(gè)可疑的信息去分析,期望發(fā)現(xiàn)蛛絲馬跡。
以上就是android sharedUserId 使用知識(shí)盲點(diǎn)解析的詳細(xì)內(nèi)容,更多關(guān)于android sharedUserId 知識(shí)盲點(diǎn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android互聯(lián)網(wǎng)訪問(wèn)圖片并在客戶端顯示的方法
這篇文章主要介紹了Android互聯(lián)網(wǎng)訪問(wèn)圖片并在客戶端顯示的方法,結(jié)合實(shí)例分析了Android處理圖片的技巧,并附帶了Android的URL封裝類,網(wǎng)絡(luò)連接封裝類與輸出流封裝類,需要的朋友可以參考下2015-12-12
Android動(dòng)態(tài)修改ToolBar的Menu菜單示例
本篇文章主要介紹了Android動(dòng)態(tài)修改ToolBar的Menu菜單示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
Android仿網(wǎng)易客戶端頂部導(dǎo)航欄效果
這篇文章主要為大家詳細(xì)介紹了Android仿網(wǎng)易客戶端頂部導(dǎo)航欄效果,幫助大家制作網(wǎng)易客戶端導(dǎo)航欄特效,感興趣的小伙伴們可以參考一下2016-06-06
Android實(shí)現(xiàn)絢麗的自定義進(jìn)度條
進(jìn)度條是在Android項(xiàng)目中很常用的組件之一,本文將為大家詳細(xì)地介紹一下自定義進(jìn)度條的實(shí)現(xiàn)過(guò)程。感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-01-01
Android實(shí)現(xiàn)仿微軟系統(tǒng)加載動(dòng)畫效果
這篇文章主要介紹了Android實(shí)現(xiàn)仿微軟系統(tǒng)加載動(dòng)畫效果的方法,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-04-04
Android遠(yuǎn)程服務(wù)編寫和調(diào)用教程
這篇文章主要介紹了Android遠(yuǎn)程服務(wù)編寫和調(diào)用教程,本文教大家如何編寫或者調(diào)用Android的遠(yuǎn)程服務(wù),感興趣的小伙伴們可以參考一下2016-02-02
Intent傳遞對(duì)象之Serializable和Parcelable的區(qū)別
Intent在不同的組件中傳遞對(duì)象數(shù)據(jù)的應(yīng)用非常普遍,大家都知道在intent傳遞對(duì)象的方法有兩種:1、實(shí)現(xiàn)Serializable接口、2、實(shí)現(xiàn)Parcelable接口,接下來(lái)通過(guò)本文給大家介紹Intent傳遞對(duì)象之Serializable和Parcelable的區(qū)別,感興趣的朋友一起學(xué)習(xí)吧2016-01-01
Eclipse新建Android項(xiàng)目報(bào)錯(cuò)解決方案詳細(xì)匯總
這篇文章主要介紹了Eclipse新建Android項(xiàng)目報(bào)錯(cuò)解決方案詳細(xì)匯總,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08

