android?sharedUserId?使用知識(shí)盲點(diǎn)解析
1. 背景
由于在工程中使用了 SPI 機(jī)制,通過 ServiceLoader 的配合來完成模塊間的通信。但是突然收到線上客戶反饋使用了 SDK 后無法進(jìn)行模塊加載,導(dǎo)致部分功能異常。
2. 分析排查
借助客戶提供的測(cè)試包進(jìn)行 debug 調(diào)試,發(fā)現(xiàn)在調(diào)試到 ServiceLoader.load() 方法時(shí)確實(shí)無法加載到對(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)后并沒有使插件化、熱修復(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 屬性問題可正常復(fù)現(xiàn)。
2.3 sharedUserId 屬性
查看官方文檔該屬性配置 API 級(jí)別 29 中已棄用此常量。共享用戶 ID 會(huì)在軟件包管理器中導(dǎo)致具有不確定性的行為。因此,強(qiáng)烈建議您不要使用它,并且我們?cè)谖磥淼?Android 版本中會(huì)將其移除。

2.總結(jié)
排查問題還是比較費(fè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開發(fā)教程之使用listview顯示qq聯(lián)系人列表
這篇文章主要介紹了android使用listview顯示qq聯(lián)系人列表的示例,需要的朋友可以參考下2014-02-02
Android編程實(shí)現(xiàn)基于局域網(wǎng)udp廣播自動(dòng)建立socket連接的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)基于局域網(wǎng)udp廣播自動(dòng)建立socket連接的方法,涉及Android使用udp廣播實(shí)現(xiàn)socket通訊的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
Android未讀消息拖動(dòng)氣泡示例代碼詳解(附源碼)
這篇文章主要介紹了Android未讀消息拖動(dòng)氣泡示例代碼詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
Android 二維碼 生成和識(shí)別二維碼 附源碼下載
這篇文章主要介紹了Android 生成和識(shí)別二維碼的方法,提供源碼下載,需要的朋友可以參考下。2016-06-06
Android利用ViewPager實(shí)現(xiàn)帶小圓球的圖片滑動(dòng)
這篇文章主要為大家詳細(xì)介紹了Android利用ViewPager實(shí)現(xiàn)帶小圓球的圖片滑動(dòng),并且只有第一次安裝app時(shí)才出現(xiàn)歡迎界面具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
Android編程實(shí)現(xiàn)ListView滾動(dòng)提示等待框功能示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)ListView滾動(dòng)提示等待框功能,結(jié)合實(shí)例形式分析了Android ListView滾動(dòng)事件相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-02-02

