Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android PackageManager Service詳解(5.1源碼)(四)

Android PackageManager Service詳解(5.1源碼)(四)

編輯:關於Android編程

2.4 APP執行代碼

APP運行時可執行的代碼,主要有三部分:

1) 虛擬機初始化時加載的系統jar包,主要包含framework.jar和libcore.jar,分別對應android framework代碼和jdk代碼

2) APP自身程序代碼,也就是打包入APK的dex文件

3) APP程序運行需要額外加載的library,對應manifest裡配置的uses-library字段

 

前兩個沒啥好講的,重點講下第三部分,app可以在manifest裡頭聲明自身運行需要額外的library,但是,這裡僅僅只是聲明,最終還是要看系統有沒有配置這個sharelibrary,配置的方式可查看Android%20PackageManagerService%E8%AF%A6%E8%A7%A3.doc" target="_blank">2.2 初始化SystemConfig,如果app的uses-library在系統中不存在,apk會安裝失敗。

PMS初始化share library代碼:

ArrayMap libConfig = systemConfig.getSharedLibraries();

for (int i=0; i

mSharedLibraries.put(libConfig.keyAt(i),

new SharedLibraryEntry(libConfig.valueAt(i), null));

}

通過library path來初始化SharedLibraryEntry並保存到mSharedLibraries中。

 

在apk數據解析時,會調用updateSharedLibrariesLPw來將apk配置的user library更新到對應的package對象:

private void updateSharedLibrariesLPw(PackageParser.Package pkg,

PackageParser.Package changingLib) throws PackageManagerException {

if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {

final ArraySet usesLibraryFiles = new ArraySet<>();

int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;

for (int i=0; i

final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesLibraries.get(i));

if (file == null) {

throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,

"Package " + pkg.packageName + " requires unavailable shared library "

+ pkg.usesLibraries.get(i) + "; failing!");

}

addSharedLibraryLPw(usesLibraryFiles, file, changingLib);

}

N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;

for (int i=0; i

final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));

if (file == null) {

Slog.w(TAG, "Package " + pkg.packageName

+ " desires unavailable shared library "

+ pkg.usesOptionalLibraries.get(i) + "; ignoring!");

} else {

addSharedLibraryLPw(usesLibraryFiles, file, changingLib);

}

}

N = usesLibraryFiles.size();

if (N > 0) {

pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[N]);

} else {

pkg.usesLibraryFiles = null;

}

}

}

遍歷usesLibraries和usesOptionalLibraries,調用addSharedLibraryLPw依次將share library添加到usesLibraryFiles,並最終保存到pkg.usesLibraryFiles。

private void addSharedLibraryLPw(ArraySet usesLibraryFiles, SharedLibraryEntry file,

PackageParser.Package changingLib) {

if (file.path != null) {

usesLibraryFiles.add(file.path);

return;

}

PackageParser.Package p = mPackages.get(file.apk);

if (changingLib != null && changingLib.packageName.equals(file.apk)) {

// If we are doing this while in the middle of updating a library apk,

// then we need to make sure to use that new apk for determining the

// dependencies here. (We haven't yet finished committing the new apk

// to the package manager state.)

if (p == null || p.packageName.equals(changingLib.packageName)) {

p = changingLib;

}

}

if (p != null) {

usesLibraryFiles.addAll(p.getAllCodePaths());

}

}

file.path不為空,直接添加到usesLibraryFiles即可

 

程序啟動的時候,AcivityThread會通過app對應的application info來創建LoadedApk,然後LoadedApk內部根據dex和usesLibraryFiles來創建app對應的classloader。

2.5 APK文件掃描

APK掃描的過程,其實就是數據收集的過程,掃描的一些代碼,其實在上頭的內容中就有提到, PMS中調用scanPackageLI掃描一個apk文件,為了讓整個思路更加清晰,接下去將基於首次掃描一個nonsystem apk來分析,至於其他的一些細節,這裡就不做更多的描述,大家可自行閱讀源碼。

 

先介紹幾個核心類:

\

從下到上,依次包含,詳細介紹如下

1:PackageParser.Package 對應一個apk包完整的原始數據

2:PackageSetting 包含PackageParser.Package對象實例,說明它也對應一個apk包的數據,不同的是,它還包含apk相關配置數據,比如,apk內部哪些component是被disable等。

3:Settings 包含PackageSetting對象列表,也就是說它包含了系統所有apk數據

 

還有就是PackageParser,顧名思義,負責APK數據解析。

掃描新apk的流程描述:

1) 調用scanPackageLI,傳入要解析的apk文件

2) 創建PackageParser對象,接著調用parsePackage來解析apk清單數據,返回
PackageParser.Package對象pkg,pkg包含了apk原始的清單數據

3) 接著調用collectCertificatesLI獲取apk的簽名數據並保存到pkg中,這個函數的詳細介紹可看1.2.4 PMS中簽名相關代碼介紹

4) 調用scanPackageLI並傳入pkg,接著調用scanPackageDirtyLI

5) 接著判斷pkg.mSharedUserId是否為空,如果不為空,說明apk設置了share user id,那就要調用getSharedUserLPw創建新的share user id

6) 接著調用mSettings.getPackageLPw生成pkg對應的PackageSetting對象pkgSetting

7) 針對非系統app(parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR)== 0),調用updateSharedLibrariesLPw更新pkg的usesLibraryFiles

8) 如果是新安裝app((scanFlags &SCAN_NEW_INSTALL) != 0), 則查看app內部聲明的provider是否已經被其他已安裝的app定義,如果是,拋出異常

9) 調用fixProcessName生成app對應的進程名

10)調用createDataDirsLI在/data/data/下創建app私有目錄

11)調用NativeLibraryHelper.copyNativeBinariesForSupportedAbi拷貝so文件,接著調用setNativeLibraryPaths更新pkg.applicationinfo中的nativeLibraryDir等信息

12)調用performDexOptLI對apk中的dex做優化

13)調用mSettings.insertPackageSettingLPw(pkgSetting, pkg);將app對應的PackageSetting添加到Settings中

14)調用mPackages.put(pkg.applicationInfo.packageName, pkg);將app對應的Package添加到mPackages中

15)將app中定義的providers添加到mProvidersByAuthority,services添加到mServices,

receivers添加到mReceivers,activities添加到mActivities

16)將app中定義的permissionGroups添加到mPermissionGroups,permissions添加到permissionMap,instrumentation添加到mInstrumentation

 

很多細節代碼在前面章節都有過描述,這裡就不再一一展開。

 

2.5 APK安裝

先來了解一個服務:

DefaultContainerService

PMS安裝過程中APK文件的拷貝,都要通過它來完成,所以在安裝時,需要連接到該服務

以獲取對應的BinderProxy來遠程調用其功能。

接著介紹幾個類:

1) PackageHandler

對應變量mHandler,在PMS構造時會創建並綁定到HandlerThread,APK的安裝相關代碼會通過Message執行在這個工作線程。該Handler的主要Message ID如下:

ID

描述

INIT_COPY

將要安裝APK信息放置於msg.obj並發送該Message到Handler,Handler執行後,會做兩件事情:

1:判斷當前是否已經連接到DefaultContainerService,如果未連接,調用connectToService進行連接

2:將要安裝的APK信息添加到mPendingInstalls

3:如果mPendingInstalls長度為0,觸發

MCS_BOUND消息

MCS_BOUND

依次從mPendingInstalls取出HandlerParams來進行安裝

POST_INSTALL

安裝成功後,會收到該消息來執行相關操作

 

2) HandlerParams

抽象類,如果要將安裝操作通過INIT_COPY消息添加到PackageHandler,必須實現

HandlerParams,並將對應的實例放置於msg.obj中,MCS_BOUND命令在處理時,會將msg.obj轉換成HandlerParams,接著調用其函數startCopy來觸發拷貝,拷貝過程中,會回調如下狀態:

abstract void handleStartCopy() throws RemoteException;

abstract void handleServiceError();

abstract void handleReturnCode();

APK拷貝對應的類為:

class InstallParams extends HandlerParams {

}

 

3) InstallArgs

也是一個抽象類,對應的實現類有兩個, FileInstallArgs和AsecInstallArgs,分別對應APK安裝到系統存儲和SD卡,他兩在實際APK數據解析上,沒任何區別,唯一不同的就是拷貝目錄和文件目錄操作存在差異,為了簡單起見,後續我們只基於FileInstallArgs來分析。

 

HanderParams是為了給PackageHandler傳遞參數並觸發拷貝和安裝行為的,所以,它的接口更多的為了配合PackageHandler來設計的

FileInstallArgs則是拷貝的執行者,同時還處理安裝前和安裝後的一些邏輯處理等,它的設計,是跟PMS深度結合在一起的。

2.5.1安裝接口描述

程序可以通過調用PMS. installPackage並傳入APK文件路徑,IPackageInstallObserver2對應的binder proxy, install Flags等來啟動安裝,IPackageInstallObserver2是用於給調用方反饋安裝狀態,install Flag指定安裝命令,比如是否是替換安裝等。

installPackage什麼都沒做,直接轉到installPackageAsUser:

@Override

public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,

int installFlags, String installerPackageName, VerificationParams verificationParams,

String packageAbiOverride, int userId) {

mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);

 

final int callingUid = Binder.getCallingUid();

enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");

 

if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {

try {

if (observer != null) {

observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);

}

} catch (RemoteException re) {

}

return;

}

 

if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {

installFlags |= PackageManager.INSTALL_FROM_ADB;

 

} else {

// Caller holds INSTALL_PACKAGES permission, so we're less strict

// about installerPackageName.

 

installFlags &= ~PackageManager.INSTALL_FROM_ADB;

installFlags &= ~PackageManager.INSTALL_ALL_USERS;

}

 

UserHandle user;

if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {

user = UserHandle.ALL;

} else {

user = new UserHandle(userId);

}

 

verificationParams.setInstallerUid(callingUid);

 

final File originFile = new File(originPath);

final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);

 

final Message msg = mHandler.obtainMessage(INIT_COPY);

msg.obj = new InstallParams(origin, observer, installFlags,

installerPackageName, verificationParams, user, packageAbiOverride);

mHandler.sendMessage(msg);

}

函數開頭先檢查調用程序是否有INSTALL_PACKAGES權限,如果沒有,直接拋出異常。

接著通過調用程度的user id來判斷其是否被限制安裝APK功能,如果是,直接返回

通過UID來判斷是否是通過ADB來安裝,接著基於傳入的參數創建InstallParams實例並保存到INIT_COPY msg.obj中並發送到PackageHandler.

2.5.2完整的安裝流程

安裝從拷貝開始,拷貝由發送INIT_COPY到PackageHandler觸發,完整流程圖:

\

2.5.3安裝包解析

從上面的流程可以看出,APK數據的解析,是通過installPackageLI來完成的,同樣的,下面只基於新安裝包這一情形來分析

看installPackageLI的代碼後會發現,其實她實現的內容跟scanPackageL(File f…)基本上是一致的:

1) 創建PackageParser對象,接著調用parsePackage來解析apk清單數據,返回
PackageParser.Package對象pkg,pkg包含了apk原始的清單數據

2) 調用collectCertificates獲取安裝APK的簽名數據

3) 調用installNewPackageLI並傳入pkg

4) 調用scanPackageLI傳入pkg進行apk數據掃描

5) 調用updateSettingsLI將apk數據更新到Settings

6) updatePermissionsLPw同步系統權限數據

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved