上篇PackageInstaller源码分析(一)对PackageInstaller源码分析了一半,本篇接着分析,分别分析对于App更新和新App安装的处理。
一、 新App的安装
新App的安装从installNewPackageLI()开始,我们查看其源码。
private void installNewPackageLI(PackageParser.Package pkg,
int parseFlags, int scanFlags, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
````
boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
// A package with the same name is already installed, though
// it has been renamed to an older name. The package we
// are trying to install should be installed as an update to
// the existing one, but that has not been requested, so bail.
res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
+ " without first uninstalling package running as "
+ mSettings.mRenamedPackages.get(pkgName));
return;
}
if (mPackages.containsKey(pkgName)) {
// Don't allow installation over an existing package with the same name.
res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
+ " without first uninstalling.");
return;
}
}
````
}
这段代码首先判断了是否建立了App的data数据目录。而后,对于要安装的app的包名若已存在的情况作了处理。对于包名已经存在,但是并非更新的情况,抛出异常。
紧接着,程序调用scanPackageLI()重新获取apk的Package结构,这个函数比较复杂,就是从apk中提取有用信息,这个和PackageInstaller源码分析(一)中PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile)应该是非常类似的,后面再选择一个分析。而后,调用updateSettingsLI()将安装的App写入设置,最后判断App是否完整安装,若没有完整安装,则调用deletePackageLI()将未完整安装的App删除,包括建立的data目录和cache目录。关于这个,在此处不做分析,这些操作和卸载App一定的相似性。以下将分析安装app细节的核心函数updateSettingsLI()。
private void installNewPackageLI(PackageParser.Package pkg,
int parseFlags, int scanFlags, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
````
try {
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, null, null, res);
// 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);
}
}
查看updateSettingsLI()源码,对mPackages的同步处理中,调用了Setting的writeLPr()方法。
private void updateSettingsLI(PackageParser.Package newPackage,
String installerPackageName,
int[] allUsers, boolean[] perUserInstalled,
PackageInstalledInfo res) {
String pkgName = newPackage.packageName;
synchronized (mPackages) {
//write settings. the installStatus will be incomplete at this stage.