场景:应用本身安装在system/app
路径下,然后我们通过adb install -r
安装应用后重启手机,发现应用还是用的以前的不是我们更新的
分析:
首先adb install -r
安装的应用是在data/app/
下,由于apk
在system/app
中已经存在,所以系统会在data/app/
的应用包名后添加-1
作为标记抓取开机log
有如下log
打印:
01-01 19:19:38.103 787 787 D PackageManager: scan package: /system/app/P92Service , start at: 10513ms.
01-01 19:19:38.103 787 787 D PackageManager: Parsing: /system/app/P92Service
01-01 19:19:38.111 787 787 D PackageManager: updatedPkg = PackageSetting{387114ae com.allinpay.usdk.service/1000}
01-01 19:19:38.111 787 787 D PackageManager: Path changing from /data/app/com.allinpay.usdk.service-1
01-01 19:19:38.112 787 787 W PackageManager: Package com.allinpay.usdk.service at /system/app/P92Service reverting from /data/app/com.allinpay.usdk.service-1: new version 1 better than installed 1
01-01 19:19:38.153 787 787 W PackageManager: Trying to update system app code path from /data/app/com.allinpay.usdk.service-1 to /system/app/P92Service
01-01 19:19:38.160 787 787 I PackageManager: Perform pre-dex opt for package: com.allinpay.usdk.service
01-01 19:19:38.162 787 787 W PackageManager: Code path for pkg : com.allinpay.usdk.service changing from /data/app/com.allinpay.usdk.service-1 to /system/app/P92Service
01-01 19:19:38.162 787 787 W PackageManager: Resource path for pkg : com.allinpay.usdk.service changing from /data/app/com.allinpay.usdk.service-1 to /system/app/P92Service
01-01 19:19:38.164 787 787 D PackageManager: scan package: /system/app/P92Service , end at: 10574ms. elapsed time = 61ms.
对我们有用的信息是:
01-01 19:19:38.112 787 787 W PackageManager: Package com.allinpay.usdk.service at /system/app/P92Service reverting from /data/app/com.allinpay.usdk.service-1: new version 1 better than installed 1
而这段log对应在系统中的代码如下:
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
PackageSetting ps = null;
PackageSetting updatedPkg;
// reader
synchronized (mPackages) {
// Look to see if we already know about this package.
String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
// This package has been renamed to its original name. Let's
// use that.
ps = mSettings.peekPackageLPr(oldName);
}
// If there was no original package, see one for the real package name.
if (ps == null) {
ps = mSettings.peekPackageLPr(pkg.packageName);
}
// Check to see if this package could be hiding/updating a system
// package. Must look for it either under the original or real
// package name depending on our state.
updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
}
boolean updatedPkgBetter = false;
// First check if this is a system package that may involve an update
/** M: [Operator] Package in vendor folder should also be checked @{ */
if (updatedPkg != null &&
(((parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0) ||
((parseFlags & PackageParser.PARSE_IS_OPERATOR) != 0))) {
/** @} */
// If new package is not located in "/system/priv-app" (e.g. due to an OTA),
// it needs to drop FLAG_PRIVILEGED.
if (locationIsPrivileged(scanFile)) {
updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
} else {
updatedPkg.pkgFlags &= ~ApplicationInfo.FLAG_PRIVILEGED;
}
if (ps != null && !ps.codePath.equals(scanFile)) {
// The path has changed from what was last scanned... check the
// version of the new path against what we have stored to determine
// what to do.
if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath); android.util.Log.i("weiyw","pkg.mVersionCode:"+pkg.mVersionCode+",pkg.codePath:"+
pkg.codePath); android.util.Log.i("weiyw","ps.versionCode:"+ps.versionCode+",ps.codePathString:"+
ps.codePathString);
/** M: [Operator] Allow vendor package downgrade. @{ */
/// Always install the updated one on data partition
if (pkg.mVersionCode < ps.versionCode || ((parseFlags & PackageParser.PARSE_IS_OPERATOR) != 0)) {
/** @} */
// The system package has been updated and the code path does not match
// Ignore entry. Skip it.
Slog.i(TAG, "Package " + ps.name + " at " + scanFile
+ " ignored: updated version " + ps.versionCode
+ " better than this " + pkg.mVersionCode);
if (!updatedPkg.codePath.equals(scanFile)) {
Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : "
+ ps.name + " changing from " + updatedPkg.codePathString
+ " to " + scanFile);
updatedPkg.codePath = scanFile;
updatedPkg.codePathString = scanFile.toString();
}
updatedPkg.pkg = pkg;
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
} else {
// The current app on the system partition is better than
// what we have updated to on the data partition; switch
// back to the system partition version.
// At this point, its safely assumed that package installation for
// apps in system partition will go through. If not there won't be a working
// version of the app
// writer
synchronized (mPackages) {
// Just remove the loaded entries from package lists.
mPackages.remove(ps.name);
}
logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
+ " reverting from " + ps.codePathString
+ ": new version " + pkg.mVersionCode
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
synchronized (mPackages) {
mSettings.enableSystemPackageLPw(ps.name);
}
updatedPkgBetter = true;
}
在这里我们可以看到打印出的log信息,看后面的代码是会去删除data
分区的apk
,以system
分区的为准,如果我们想让data
分区的为主,那我们就不能进else
,需要进入if
里面,看下判断条件
if (pkg.mVersionCode < ps.versionCode || ((parseFlags & PackageParser.PARSE_IS_OPERATOR) != 0))
PackageParser.PARSE_IS_OPERATOR
是判断是不是operator apps
的,我们明显不是,那就看versioncode
了
Package com.allinpay.usdk.service at /system/app/P92Service reverting from /data/app/com.allinpay.usdk.service-1: new version 1 better than installed 1
logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + scanFile
+ " reverting from " + ps.codePathString
+ ": new version " + pkg.mVersionCode
+ " better than installed " + ps.versionCode);
通过log我们可知scanFile
是/system/app/目录下,通过之前的代码:pkg = pp.parsePackage(scanFile, parseFlags)
可以pkg
代表的是系统分区下的app
通过代码
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
// This package has been renamed to its original name. Let's
// use that.
ps = mSettings.peekPackageLPr(oldName);
}
// If there was no original package, see one for the real package name.
if (ps == null) {
ps = mSettings.peekPackageLPr(pkg.packageName);
}
可知ps
是根据pkg
提供的包名在其他分区去搜索,所以ps
代表的是其他分区的,也就是这里的data分区
只要我们满足pkg.mVersionCode
< ps.versionCode
这个条件,那我们就会进入if里面,在if里面会去隐藏system分区里的应用,将data的应用优先级提高,满足这个条件很简单,只要相应的应用在AndroidManifest.xml
里面将versioncode
升级一下就可以了,比如system/app
里面的versioncode
是1,那新的应用只需将versioncode
修改成2即可,这样adb install -r
安装后重启用的还是data
分区的应用