Android中APK的安裝流程
這篇文章,來學習apk的安裝流程,在開始之前,先看看我們在APP中是通過下面程式碼來安裝apk的
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");
context.startActivity(intent);
構造一個intent,並且setDataAndType,然後啟動這個activity,此時系統預設的安裝apk的PackageInstallerActivity介面就出現了。
使用PackageInstallerActivity安裝apk的流程
在PackageInstallerActivity中定義了這樣的字串
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
這個是在PackageManagerService中匹配的。
PackageInstallerActivity也是一個activity,所以當該介面顯示的時候,會首先呼叫其onCreate方法,我們來看看。
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mPm = getPackageManager(); //是一個PackageManager例項,具體用來執行安裝操作的
mInstaller = mPm.getPackageInstaller(); // PackageInstaller例項,在該例項中包含了安裝apk的基本資訊
mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
final Intent intent = getIntent();
//set view
setContentView(R.layout.install_start);
mInstallConfirm = findViewById(R.id.install_confirm_panel);
mInstallConfirm.setVisibility(View.INVISIBLE);
// Block the install attempt on the Unknown Sources setting if necessary.
if (!requestFromUnknownSource) {
// 為安裝操作,執行一些初始化的工作
initiateInstall();
return;
}
}
可以看到,在onCreate中,主要通過initiateInstall();為安裝操作,執行一些初始化的工作。
private void initiateInstall() {
// 當前apk的包名
String pkgName = mPkgInfo.packageName;
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
}
try {
// 通過PackageManager從系統中獲取沒有安裝的apk的資訊
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.GET_UNINSTALLED_PACKAGES);
// 如果已經安裝,在後面會給出使用者是否替換的提示
if ((mAppInfo.flags& ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (PackageManager.NameNotFoundException e) {
mAppInfo = null;
}
// 呼叫startInstallConfirm進行進一步的安裝操作
startInstallConfirm();
}
上面程式碼最終主要該通過startInstallConfirm來進一步安裝apk
private void startInstallConfirm() {
mInstallConfirm.setVisibility(View.VISIBLE);
mOk = (Button)findViewById(R.id.ok_button);
mCancel = (Button)findViewById(R.id.cancel_button);
mOk.setOnClickListener(this);
mCancel.setOnClickListener(this);
}
PackageInstallerActivity實現了OnClicklistener
public void onClick(View v) {
if (v == mOk) {
startInstall();
} else if(v == mCancel) {
// Cancel and finish
setResult(RESULT_CANCELED);
finish();
}
}
private void startInstall() {
// 安裝apk,構造intent,這裡會跳轉到InstallAppProgress裡
Intent newIntent = new Intent();
// 傳遞資料
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallAppProgress.class);
newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);
newIntent.putExtra(
InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != VerificationParams.NO_UID) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
}
// 進入InstallAppProgress
startActivity(newIntent);
finish();
}
可以看到在startInstall方法中,主要構造一個intent,並且傳遞必要的資料,跳轉到InstallAppProgress類,在該類中有一個initView方法
public void initView() {
setContentView(R.layout.op_progress);
int installFlags = 0;
PackageManager pm = getPackageManager();
// 判斷當前apk是否已經安裝過
try {
PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
} catch (PackageManager.NameNotFoundException e) {
}
// 省略程式碼
// 構造一個PackageInstallObserver,當安裝完成以後,回撥對應的方法
PackageInstallObserver observer = new PackageInstallObserver();
if ("package".equals(mPackageURI.getScheme())) {
try {
// 呼叫PackageManagerService服務的installExistingPackage進行安裝
pm.installExistingPackage(mAppInfo.packageName);
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_SUCCEEDED);
} catch (PackageManager.NameNotFoundException e) {
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_FAILED_INVALID_APK);
}
} else {
pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
installerPackageName, verificationParams, null);
}
}
這裡具體的PackageManagerService服務安裝的過程我們稍後會進行學習,先看下當安裝完成以後通過PackageInstallObserver執行的回撥方法
class PackageInstallObserver extends IPackageInstallObserver.Stub {
public void packageInstalled(String packageName, int returnCode) {
Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
msg.arg1 = returnCode;
mHandler.sendMessage(msg);
}
}
傳送”INSTALL_COMPLETE”這樣的訊息到自身,在handleMessage中主要做了下面的操作:
mLaunchIntent = getPackageManager().getLaunchIntentForPackage(
mAppInfo.packageName);
mLaunchButton.setOnClickListener(InstallAppProgress.this);
mDoneButton.setOnClickListener(InstallAppProgress.this);
獲取啟動當前apk的intent,並且為done和lunch按鈕設定點選事件
public void onClick(View v) {
if(v == mDoneButton) {
if (mAppInfo.packageName != null) {
Log.i(TAG, "Finished installing "+mAppInfo.packageName);
}
finish();
} else if(v == mLaunchButton) {
startActivity(mLaunchIntent);
finish();
}
}
好了,到現在為止,使用PackageInstallerActivity安裝apk的整個流程已經梳理完畢,實際上真正執行安裝操作的都是交給了PackageManagerService服務的installExistingPackage進行安裝的
PackageManagerService安裝apk流程
平時我們可以使用下面兩個命令來安裝apk
pm get-install-location 查詢安裝apk的位置 一般預設 為0[auto]
pm set-install-location 設定位置
這裡最終都是通過PackageManagerService來實現安裝具體包的操作
呼叫PackageManagerService#installPackage方法開始apk的安裝過程
public void installPackage(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride) {
installPackageAsUser(originPath, observer, installFlags, installerPackageName,
verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
}
@Override
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride, int userId) {
// 檢查是否有install許可權
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");
// 判斷當前使用者是否被Restricted,回撥onPackageInstalled方法,安裝失敗
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
try {
if (observer != null) {
observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
}
} catch (RemoteException re) {
}
return;
}
// 程式碼省略,主要是判斷當前安裝的方式設定對應的installFlags
final File originFile = new File(originPath);
final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
// 傳送"INIT_COPY" 訊息,構造InstallParams引數
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
null, verificationParams, user, packageAbiOverride, null);
mHandler.sendMessage(msg);
}
整個PackageHandler是PackageManagerService的一個內部類
witch (msg.what) {
case INIT_COPY: {
HandlerParams params = (HandlerParams) msg.obj;
//這裡獲取當前需要安裝的apk個數,mPendingInstalls儲存著所有需要安裝的apk解析出來的HandlerParams引數
int idx = mPendingInstalls.size();
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
// 如果沒有繫結DefaultContainerService,則進行那個繫結,DefaultContainerService主要負責計算當前儲存和拷貝工作
if (!mBound) {
if (!connectToService()) {
params.serviceError();
return;
} else {
mPendingInstalls.add(idx, params);
}
} else {
mPendingInstalls.add(idx, params);
if (idx == 0) {
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
break;
}
繼續傳送”MCS_BOUND”引數到自己處理,表示繫結DefaultContainerService服務完成
case MCS_BOUND: {
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
}
if (mContainerService == null) {
// 繫結DefaultContainerService服務失敗,回撥serviceError方法
if (!mBound) {
Slog.e(TAG, "Cannot bind to media container service");
for (HandlerParams params : mPendingInstalls) {
params.serviceError();
}
mPendingInstalls.clear();
} else {
Slog.w(TAG, "Waiting to connect to media container service");
}
} else if (mPendingInstalls.size() > 0) {
// 總是安裝佇列中的第一個
HandlerParams params = mPendingInstalls.get(0);
if (params != null) {
if (params.startCopy()) { //首先拷貝當前apk到對應的目錄下
// We are done... look for more work or to
// go idle.
if (mPendingInstalls.size() > 0) { // 將第一個移除當前佇列
mPendingInstalls.remove(0);
}
if (mPendingInstalls.size() == 0) { //size等於0,表示所有的apk都已經安裝完成,unbind當前DefaultContainerService服務
if (mBound) {
if (DEBUG_SD_INSTALL) Log.i(TAG,
"Posting delayed MCS_UNBIND");
removeMessages(MCS_UNBIND);
Message ubmsg = obtainMessage(MCS_UNBIND);
// Unbind after a little delay, to avoid
// continual thrashing.
sendMessageDelayed(ubmsg, 10000);
}
} else {
//繼續安裝下一個需要安裝的包
mHandler.sendEmptyMessage(MCS_BOUND);
}
}
}
} else {
Slog.w(TAG, "Empty queue");
}
break;
}
可以看到,其實所有的安裝apk的程式碼都放到了HandlerParams#startCopy方法中,看下HandlerParams
private abstract class HandlerParams {
final boolean startCopy() {
boolean res;
try {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
if (++mRetries > MAX_RETRIES) {
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mHandler.sendEmptyMessage(MCS_GIVE_UP);
handleServiceError();
return false;
} else {
// 這裡的具體copy處理是由其子類來完成的
handleStartCopy();
res = true;
}
} catch (RemoteException e) {
if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
mHandler.sendEmptyMessage(MCS_RECONNECT);
res = false;
}
// handleReturnCode,該方法會在handleStartCopy執行玩拷貝相關動作之後,根據在handleStartCopy中的做進一步處理
handleReturnCode();
return res;
}
final void serviceError() {
if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
handleServiceError();
handleReturnCode();
}
abstract void handleStartCopy() throws RemoteException;
abstract void handleServiceError();
abstract void handleReturnCode();
}
}
這裡是由InstallParams來處理copy操作的。
public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
if (origin.staged) {
if (origin.file != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
} else if (origin.cid != null) {
installFlags |= PackageManager.INSTALL_EXTERNAL;
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
}
// 是否安裝到sdcard或者內部儲存中
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
PackageInfoLite pkgLite = null;
if (onInt && onSd) {
// 使用者同時設定安裝到sdcard和內部儲存
Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
packageAbiOverride);
.......
//程式碼省略,主要根據儲存情況,釋放當前儲存空間
}
// 根據當前InstallParams構造具體的InstallArgs實現類,在該實現類中做具體的拷貝操作
final InstallArgs args = createInstallArgs(this);
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
/*
* ADB installs appear as UserHandle.USER_ALL, and can only be performed by
* UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
*/
int userIdentifier = getUser().getIdentifier();
if (userIdentifier == UserHandle.USER_ALL
&& ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) {
userIdentifier = UserHandle.USER_OWNER;
}
final int requiredUid = mRequiredVerifierPackage == null ? -1
: getPackageUid(mRequiredVerifierPackage, userIdentifier);
if (!origin.existing && requiredUid != -1
&& isVerificationEnabled(userIdentifier, installFlags) &&
isVerificationRequired()) { // 對當前的包做驗證操作
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
final List<ResolveInfo> receivers = queryIntentReceivers(verification,
PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS,
0 /* TODO: Which userId? */);
final int verificationId = mPendingVerificationToken++;
verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
installerPackageName);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
installFlags);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
pkgLite.packageName);
verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
pkgLite.versionCode);
if (verificationParams != null) {
if (verificationParams.getVerificationURI() != null) {
verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI,
verificationParams.getVerificationURI());
}
if (verificationParams.getOriginatingURI() != null) {
verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
verificationParams.getOriginatingURI());
}
if (verificationParams.getReferrer() != null) {
verification.putExtra(Intent.EXTRA_REFERRER,
verificationParams.getReferrer());
}
if (verificationParams.getOriginatingUid() >= 0) {
verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
verificationParams.getOriginatingUid());
}
if (verificationParams.getInstallerUid() >= 0) {
verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
verificationParams.getInstallerUid());
}
}
final PackageVerificationState verificationState = new PackageVerificationState(
requiredUid, args);
mPendingVerification.append(verificationId, verificationState);
final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
receivers, verificationState);
// Apps installed for "all" users use the device owner to verify the app
UserHandle verifierUser = getUser();
if (verifierUser == UserHandle.ALL) {
verifierUser = UserHandle.OWNER;
}
/*
* If any sufficient verifiers were listed in the package
* manifest, attempt to ask them.
*/
if (sufficientVerifiers != null) {
final int N = sufficientVerifiers.size();
if (N == 0) {
Slog.i(TAG, "Additional verifiers required, but none installed.");
ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
} else {
for (int i = 0; i < N; i++) {
final ComponentName verifierComponent = sufficientVerifiers.get(i);
final Intent sufficientIntent = new Intent(verification);
sufficientIntent.setComponent(verifierComponent);
mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
}
}
}
final ComponentName requiredVerifierComponent = matchComponentForVerifier(
mRequiredVerifierPackage, receivers);
if (ret == PackageManager.INSTALL_SUCCEEDED
&& mRequiredVerifierPackage != null) {
/*
* Send the intent to the required verification agent,
* but only start the verification timeout after the
* target BroadcastReceivers have run.
*/
verification.setComponent(requiredVerifierComponent);
mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final Message msg = mHandler
.obtainMessage(CHECK_PENDING_VERIFICATION);
msg.arg1 = verificationId;
mHandler.sendMessageDelayed(msg, getVerificationTimeout());
}
}, null, 0, null, null);
/*
* We don't want the copy to proceed until verification
* succeeds, so null out this field.
*/
mArgs = null;
}
} else {
// 執行拷貝操作
ret = args.copyApk(mContainerService, true);
}
}
mRet = ret;
}
上面主要做了這樣的事情:
1. 判斷安裝預設儲存
2. 若當前儲存不夠,則釋放儲存空間
3. 如果需要,對當前包做驗證操作
4. 執行拷貝操作
就安裝而言,最重要的還是最後的執行拷貝操作,這裡是InstallArgs#copyApk
static abstract class InstallArgs
包含三個子類
1. FileInstallArgs apk安裝到內部儲存器時使用。
2. AsecInstallArgs 安裝到sdcard或者ForwardLocked時使用
3. MoveInstallArgs 移動包的位置,比如從內部儲存移動到sdcard上
在構造方法中根據InstallParams會構造出具體型別
private InstallArgs createInstallArgs(InstallParams params) {
if (params.move != null) {
return new MoveInstallArgs(params);
} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
return new AsecInstallArgs(params);
} else {
return new FileInstallArgs(params);
}
}
這裡我們以AsecInstallArgs為例,進行說明
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.cid + " already staged; skipping copy");
cid = origin.cid;
setMountPath(PackageHelper.getSdDir(cid));
return PackageManager.INSTALL_SUCCEEDED;
}
if (temp) {
createCopyFile();
} else {
/*
* Pre-emptively destroy the container since it's destroyed if
* copying fails due to it existing anyway.
*/
PackageHelper.destroySdDir(cid);
}
//copyPackageToContainer執行真正的拷貝操作
final String newMountPath = imcs.copyPackageToContainer(
origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternalAsec(),
isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */));
if (newMountPath != null) {
setMountPath(newMountPath);
return PackageManager.INSTALL_SUCCEEDED; //這裡安裝成功之後,會將mRet賦值為PackageManager.INSTALL_SUCCEEDED
} else {
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
}
}
到現在為止,copyApk的操作已經完成,接下來交給handleReturnCode處理
@Override
void handleReturnCode() {
// mArgs是在handleStartCopy中建立的
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
}
}
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
// 由於安裝可能耗時操作,所以這裡開啟了一個執行緒
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo();
res.returnCode = currentStatus;
res.uid = -1;
res.pkg = null;
res.removedInfo = new PackageRemovedInfo();
// 如果之前copyApk正常執行完成,這裡res.returnCode == PackageManager.INSTALL_SUCCEEDED成立
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
args.doPreInstall(res.returnCode); //安裝前的準備工作
synchronized (mInstallLock) {
installPackageLI(args, res); //執行安裝操作
}
args.doPostInstall(res.returnCode, res.uid); //安裝完成以後的曹操作
}
.........
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); // 安裝完成後傳送"POST_INSTALL"廣播
mHandler.sendMessage(msg);
}
});
}
看下進一步安裝的相關步驟
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
......
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setRuntimeSkinBlacklist(mRuntimeSkinManager.getBlacklistedPackages());
final PackageParser.Package pkg;
try {
// PackageParser解析manifest檔案
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParser.PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
}
// Mark that we have an install time CPU ABI override.
pkg.cpuAbiOverride = args.abiOverride;
String pkgName = res.name = pkg.packageName;
// Mark that we have an install time CPU ABI override.
pkg.cpuAbiOverride = args.abiOverride;
String pkgName = res.name = pkg.packageName;
// 根據使用者策略,判斷當前使用者是否允許安裝apk,否則直接返回
boolean installForAllUsers = ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0);
int user = args.user == null ? -1 : args.user.getIdentifier();
if (isInstallationBlockedByDevicePolicy(pkgName, installForAllUsers, user)) {
res.returnCode = PackageManager.INSTALL_FAILED_USER_RESTRICTED;
return;
}
// 簽名相關資訊
try {
pp.collectCertificates(pkg, parseFlags);
pp.collectManifestDigest(pkg);
} catch (PackageParser.PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
return;
}
........
// 如果已經安裝當前應用,則替換,否則安裝
if (replace) {
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, volumeUuid, res);
} else {
installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res);
}
}
可以看到上面的程式碼主要做了下面操作:
1. 解析manifest檔案,並且將解析結果封裝成PackageParser物件
2. 判斷當前安裝條件四是否滿足,否則直接返回,比如:根據使用者策略,判斷當前使用者是否允許安裝apk,否則直接返回
3. 獲取簽名相關資訊,並且做校驗
4. 安裝或者替換當前應用installNewPackageLI或者replacePackageLI
PackageParser解析manifest檔案,PackageParser#parsePackage —-> PackageParser#parseClusterPackage —> PackageParser#parseBaseApk
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
if (apkPath.startsWith(MNT_EXPAND)) {
final int end = apkPath.indexOf('/', MNT_EXPAND.length());
volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
}
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
Resources res = null;
XmlResourceParser parser = null;
try {
res = new Resources(assets, mMetrics, null);
assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
// 解析manifest檔案
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
final Package pkg = parseBaseApk(res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}
pkg.volumeUuid = volumeUuid;
pkg.applicationInfo.volumeUuid = volumeUuid;
pkg.baseCodePath = apkPath;
pkg.mSignatures = null;
return pkg;
} catch (PackageParserException e) {
throw e;
} catch (Exception e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
}
}
通過installNewPackageLI執行安裝操作
/*
* Install a non-existing package.
*/
private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName;
.......
try {
// 核心的呼叫
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
//如果安裝失敗,則執行回退操作,刪除建立的資料夾等快取檔案
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
res.removedInfo, true);
}
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
}
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
boolean success = false;
try {
final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
currentTime, user);
success = true;
// 程式走到這裡說明安裝成功了,這裡會返回根據解析構建的Package物件,該物件中包含了該apk對應的manifest中的資訊
return res;
} finally {
if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
removeDataDirsLI(pkg.volumeUuid, pkg.packageName);
}
}
}
**終於走到了scanPackageDirtyLI方法,安裝apk的核心方法:
在該方法中,會根據之前解析出來的內容,新增到對應的list中,方便以後query查詢**
// Currently known shared libraries.
final ArrayMap<String, SharedLibraryEntry> mSharedLibraries =
new ArrayMap<String, SharedLibraryEntry>();
// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
new ActivityIntentResolver();
// All available receivers, for your resolving pleasure.
final ActivityIntentResolver mReceivers =
new ActivityIntentResolver();
// All available services, for your resolving pleasure.
final ServiceIntentResolver mServices = new ServiceIntentResolver();
// All available providers, for your resolving pleasure.
final ProviderIntentResolver mProviders = new ProviderIntentResolver();
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
.......
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
// 新增provider
mProviders.addProvider(p);
p.syncable = p.info.isSyncable;
if (p.info.authority != null) {
String names[] = p.info.authority.split(";");
p.info.authority = null;
for (int j = 0; j < names.length; j++) {
if (j == 1 && p.syncable) {
// We only want the first authority for a provider to possibly be
// syncable, so if we already added this provider using a different
// authority clear the syncable flag.