在android 5.0 項目上開發的時候,進入U盤目錄,通過pm 命令安裝apk,發現安裝失敗,提示apk路徑不對。
安裝log信息如下:
cd /mnt/usb/2D80-E3ED/APK_backup
shell@yjw:/mnt/usb/2D80-E3ED/APK_backup # pm install AndyKeyTest.apk
pkg: AndyKeyTest.apk
Failure [INSTALL_FAILED_INVALID_URI]
logcat信息:
01-01 08:20:49.955 D/AndroidRuntime( 2952): Calling main entry com.android.commands.pm.Pm
01-01 08:20:49.968 W/asset ( 2734): Asset path /AndyKeyTest.apk is neither a directory nor file (type=1).
--------- beginning of system
01-01 08:20:49.968 W/DefContainer( 2734): Failed to parse package at /AndyKeyTest.apk: android.content.pm.PackageParser$PackageParserException: Failed to parse /AndyKeyTest.apk
通過log信息及測試發現,原來在android5.0中不能直接在u盤目錄下執行pm install 安裝apk ,必須到要在pm 命令帶上apk所在路勁。更早的android版本沒有這個要求
改爲在根目錄下,執行下面命令,則安裝apk成功
shell@yjw:/ # pm install mnt/usb/2D80-E3ED/APK_backup/AndyKeyTest.apk
pkg: mnt/usb/2D80-E3ED/APK_backup/AndyKeyTest.apk
Success
針對上面的問題,查看了一下源碼,發現android 5.0 的parsePackage功能在細節上有一些更改,所以出現上面的情況。
相關代碼如下:
PackageParser.java@
/**
* Parse only lightweight details about the package at the given location.
* Automatically detects if the package is a monolithic style (single APK
* file) or cluster style (directory of APKs).
* <p>
* This performs sanity checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
*
* @see PackageParser#parsePackage(File, int)
*/
public static PackageLite parsePackageLite(File packageFile, int flags)
throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackageLite(packageFile, flags);
} else {
return parseMonolithicPackageLite(packageFile, flags);
}
}
DefaultContainerService.java@
/**
* Parse given package and return minimal details.
*
* @param packagePath absolute path to the package to be copied. Can be
* a single monolithic APK file or a cluster directory
* containing one or more APKs.
*/
@Override
public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
String abiOverride) {
final Context context = DefaultContainerService.this;
final boolean isForwardLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
PackageInfoLite ret = new PackageInfoLite();
if (packagePath == null) {
Slog.i(TAG, "Invalid package file " + packagePath);
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
return ret;
}
final File packageFile = new File(packagePath);
final PackageParser.PackageLite pkg;
final long sizeBytes;
try {
pkg = PackageParser.parsePackageLite(packageFile, 0);
sizeBytes = PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
} catch (PackageParserException | IOException e) {
Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
if (!packageFile.exists()) {
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
} else {
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
}
return ret;
}
ret.packageName = pkg.packageName;
ret.versionCode = pkg.versionCode;
ret.installLocation = pkg.installLocation;
ret.verifiers = pkg.verifiers;
ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
pkg.packageName, pkg.installLocation, sizeBytes, flags);
ret.multiArch = pkg.multiArch;
return ret;
}