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

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

根據(jù)接口定義 load 方法會根據(jù)指定的 serviceType 創(chuàng)建新的 ServiceLoader 對象返回,ServiceLoader 內(nèi)部根據(jù)當前線程對應的 ContextClassLoader 對象去加載配置,所以到這里可以分析到 load 方法的加載結果會受 ContextClassLoader 的影響,進一步推理可能收到插件化、熱修復等框架影響,確認后并沒有使插件化、熱修復等框架。
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());");
}
...
}
在應用創(chuàng)建時會調用 ActivityThread 類中的 attach 方法中,attach 方法進而調用 LoadedApk 類中的 makeApplicationInner() 用于創(chuàng)建對應的 Application 對象。在 makeApplicationInner() 方法的內(nèi)部調用 initializeJavaContextClassLoader 方法創(chuàng)建對應的 ContentClassLoader 對象,在 initializeJavaContextClassLoader 方法的內(nèi)部可以看到,如果當前 App 在 manifest 中設置 sharedUserId 屬性,則當前應用使用的是 WarningContextClassLoader。下面我們就是查看 App 中的配置。

最終驗證了我們的猜想,使用 demo 設置 sharedUserId 屬性問題可正常復現(xiàn)。
2.3 sharedUserId 屬性
查看官方文檔該屬性配置 API 級別 29 中已棄用此常量。共享用戶 ID 會在軟件包管理器中導致具有不確定性的行為。因此,強烈建議您不要使用它,并且我們在未來的 Android 版本中會將其移除。

2.總結
排查問題還是比較費神,在沒有明顯錯誤的時候,只能針對每個可疑的信息去分析,期望發(fā)現(xiàn)蛛絲馬跡。
以上就是android sharedUserId 使用知識盲點解析的詳細內(nèi)容,更多關于android sharedUserId 知識盲點的資料請關注腳本之家其它相關文章!
相關文章
android開發(fā)教程之使用listview顯示qq聯(lián)系人列表
這篇文章主要介紹了android使用listview顯示qq聯(lián)系人列表的示例,需要的朋友可以參考下2014-02-02
Android編程實現(xiàn)基于局域網(wǎng)udp廣播自動建立socket連接的方法
這篇文章主要介紹了Android編程實現(xiàn)基于局域網(wǎng)udp廣播自動建立socket連接的方法,涉及Android使用udp廣播實現(xiàn)socket通訊的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11
Android利用ViewPager實現(xiàn)帶小圓球的圖片滑動
這篇文章主要為大家詳細介紹了Android利用ViewPager實現(xiàn)帶小圓球的圖片滑動,并且只有第一次安裝app時才出現(xiàn)歡迎界面具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-11-11
Android編程實現(xiàn)ListView滾動提示等待框功能示例
這篇文章主要介紹了Android編程實現(xiàn)ListView滾動提示等待框功能,結合實例形式分析了Android ListView滾動事件相關實現(xiàn)技巧,需要的朋友可以參考下2017-02-02

