android 应用安装过程,Android应用程序安装过程浅析(3)

本文来自网易云社区

作者:孙有军

这里post一个Runnable来执行内部的逻辑,主要做了如下操作:        1,锁定后安装包,通过调用installPackageLI来进行的        2,接下来都是执行备份操作,备份是通过BackupManagerService来完成的。备份完成后,通过发送what为POST_INSTALL的message来继续处理 我们先来看看installPackageLI的执行过程:

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {

//...... 初始化参数....

PackageParser pp = new PackageParser();

pp.setSeparateProcesses(mSeparateProcesses);

pp.setDisplayMetrics(mMetrics);

final PackageParser.Package pkg;

try {

pkg = pp.parsePackage(tmpPackageFile, parseFlags);

} catch (PackageParserException e) {

res.setError("Failed parse during installPackageLI", e);

return;

}

.................

String oldCodePath = null;

boolean systemApp = false;

synchronized (mPackages) {

// Check if installing already existing package

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

String oldName = mSettings.mRenamedPackages.get(pkgName);

if (pkg.mOriginalPackages != null

&& pkg.mOriginalPackages.contains(oldName)

&& mPackages.containsKey(oldName)) {

// This package is derived from an original package,

// and this device has been updating from that original

// name. We must continue using the original name, so

// rename the new package here.

pkg.setPackageName(oldName);

pkgName = pkg.packageName;

replace = true;

if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="

+ oldName + " pkgName=" + pkgName);

} else if (mPackages.containsKey(pkgName)) {

// This package, under its official name, already exists

// on the device; we should replace it.

replace = true;

if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);

}

// Prevent apps opting out from runtime permissions

if (replace) {

PackageParser.Package oldPackage = mPackages.get(pkgName);

final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;

final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;

if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1

&& newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {

res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,

"Package " + pkg.packageName + " new target SDK " + newTargetSdk

+ " doesn't support runtime permissions but the old"

+ " target SDK " + oldTargetSdk + " does.");

return;

}

}

}

...............

// Check whether the newly-scanned package wants to define an already-defined perm

int N = pkg.permissions.size();

for (int i = N-1; i >= 0; i--) {

PackageParser.Permission perm = pkg.permissions.get(i);

BasePermission bp = mSettings.mPermissions.get(perm.info.name);

if (bp != null) {

// If the defining package is signed with our cert, it's okay. This

// also includes the "updating the same package" case, of course.

// "updating same package" could also involve key-rotation.

final boolean sigsOk;

if (bp.sourcePackage.equals(pkg.packageName)

&& (bp.packageSetting instanceof PackageSetting)

&& (shouldCheckUpgradeKeySetLP((PackageSetting) bp.packageSetting,

scanFlags))) {

sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);

} else {

sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,

pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;

}

if (!sigsOk) {

// If the owning package is the system itself, we log but allow

// install to proceed; we fail the install on all other permission

// redefinitions.

if (!bp.sourcePackage.equals("android")) {

res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "

+ pkg.packageName + " attempting to redeclare permission "

+ perm.info.name + " already owned by " + bp.sourcePackage);

res.origPermission = perm.info.name;

res.origPackage = bp.sourcePackage;

return;

} else {

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

+ " attempting to redeclare system permission "

+ perm.info.name + "; ignoring new declaration");

pkg.permissions.remove(i);

}

}

}

}

}

if (systemApp && onExternal) {

// Disable updates to system apps on sdcard

res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,

"Cannot install updates to system apps on sdcard");

return;

}

if (args.move != null) {

// We did an in-place move, so dex is ready to roll

scanFlags |= SCAN_NO_DEX;

scanFlags |= SCAN_MOVE;

synchronized (mPackages) {

final PackageSetting ps = mSettings.mPackages.get(pkgName);

if (ps == null) {

res.setError(INSTALL_FAILED_INTERNAL_ERROR,

"Missing settings for moved package " + pkgName);

}

// We moved the entire application as-is, so bring over the

// previously derived ABI information.

pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;

pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;

}

} else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {

// Enable SCAN_NO_DEX flag to skip dexopt at a later stage

scanFlags |= SCAN_NO_DEX;

try {

derivePackageAbi(pkg, new File(pkg.codePath), args.abiOverride,

true /* extract libs */);

} catch (PackageManagerException pme) {

Slog.e(TAG, "Error deriving application ABI", pme);

res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");

return;

}

// Run dexopt before old package gets removed, to minimize time when app is unavailable

int result = mPackageDexOptimizer

.performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,

false /* defer */, false /* inclDependencies */);

if (result == PackageDexOptimizer.DEX_OPT_FAILED) {

res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);

return;

}

}

if (!args.doRename(res.returnCode, pkg, oldCodePath)) {

res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");

return;

}

startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);

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);

}

synchronized (mPackages) {

final PackageSetting ps = mSettings.mPackages.get(pkgName);

if (ps != null) {

res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);

}

}

}

主要是执行了以下操作:

1,初始一些参数 2,调用PackageParser来解析包 3,判断是否是当前已有应用升级还是全新安装,这两个都需要坚持签名

4,检测权限,检测新扫描的权限是否是已经定义的权限 5,根据条件是否进行derivePackageAbi操作,这个操作的注释为Derive the ABI of a non-system package located at {@code scanFile}. This information is derived purely on the basis of the contents of {@code scanFile} and{@code cpuAbiOverride}. 6,开始intent filter验证

7,根据是否是已有应用进行升级还是全新安装执行不同的操作

这里重要的主要是第2点和第7点,但是由于这里主要讲述android过程,因此对第2点不做详述,之后来详解该内容,我们假设这里是全新安装着调用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;

if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);

final boolean dataDirExists = Environment

.getDataUserPackageDirectory(volumeUuid, UserHandle.USER_OWNER, pkgName).exists();

...........

try {

PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,

System.currentTimeMillis(), user);

updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);

// delete the partially installed application. the data directory will have to be

// restored if it was already existing

if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {

// remove package from internal structures. Note that we want deletePackageX to

// delete the package data and cache directories that it created in

// scanPackageLocked, unless those directories existed before we even tried to

// install.

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);

}

}

主要是调用了scanPackageLI来进行包的安装,之后调用了updateSettingsLI,updateSettingsLI主要是更新了包的PackageSetting对象,主要更新了权限信息与安装完成信息。这里我们继续查看scanPackageLI的执行:

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;

return res;

} finally {

if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {

removeDataDirsLI(pkg.volumeUuid, pkg.packageName);

}

}

}

网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值