Merge change 25157 into eclair
* changes: Remove deadlock in PackageManager when installing or upgrading packages. PM first creates a temporary file from the input package uri before installing it. if the package uri points to a content uri, the content provider has to be retrieved via the ActivityManager which could cause deadlocks with the package manager locks being held. Clean up by always copying or creating temporary files before acquiring these locks. Fix issue when restoring a failed upgrade for third party apps.
This commit is contained in:
@@ -3611,9 +3611,18 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
mHandler.post(new Runnable() {
|
mHandler.post(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
mHandler.removeCallbacks(this);
|
mHandler.removeCallbacks(this);
|
||||||
PackageInstalledInfo res;
|
// Result object to be returned
|
||||||
synchronized (mInstallLock) {
|
PackageInstalledInfo res = new PackageInstalledInfo();
|
||||||
res = installPackageLI(packageURI, flags, true, installerPackageName);
|
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
|
||||||
|
res.uid = -1;
|
||||||
|
res.pkg = null;
|
||||||
|
res.removedInfo = new PackageRemovedInfo();
|
||||||
|
// Make a temporary copy of file from given packageURI
|
||||||
|
File tmpPackageFile = copyTempInstallFile(packageURI, res);
|
||||||
|
if (tmpPackageFile != null) {
|
||||||
|
synchronized (mInstallLock) {
|
||||||
|
installPackageLI(packageURI, flags, true, installerPackageName, tmpPackageFile, res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (observer != null) {
|
if (observer != null) {
|
||||||
try {
|
try {
|
||||||
@@ -3828,11 +3837,30 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
// Since we failed to install the new package we need to restore the old
|
// Since we failed to install the new package we need to restore the old
|
||||||
// package that we deleted.
|
// package that we deleted.
|
||||||
if(deletedPkg) {
|
if(deletedPkg) {
|
||||||
|
File restoreFile = new File(deletedPackage.mPath);
|
||||||
|
if (restoreFile == null) {
|
||||||
|
Log.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File restoreTmpFile = createTempPackageFile();
|
||||||
|
if (restoreTmpFile == null) {
|
||||||
|
Log.e(TAG, "Failed creating temp file when restoring pkg : " + pkgName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!FileUtils.copyFile(restoreFile, restoreTmpFile)) {
|
||||||
|
Log.e(TAG, "Failed copying temp file when restoring pkg : " + pkgName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PackageInstalledInfo restoreRes = new PackageInstalledInfo();
|
||||||
|
restoreRes.removedInfo = new PackageRemovedInfo();
|
||||||
installPackageLI(
|
installPackageLI(
|
||||||
Uri.fromFile(new File(deletedPackage.mPath)),
|
Uri.fromFile(restoreFile),
|
||||||
isForwardLocked(deletedPackage)
|
isForwardLocked(deletedPackage)
|
||||||
? PackageManager.INSTALL_FORWARD_LOCK
|
? PackageManager.INSTALL_FORWARD_LOCK
|
||||||
: 0, false, oldInstallerPackageName);
|
: 0, false, oldInstallerPackageName, restoreTmpFile, restoreRes);
|
||||||
|
if (restoreRes.returnCode != PackageManager.INSTALL_SUCCEEDED) {
|
||||||
|
Log.e(TAG, "Failed restoring pkg : " + pkgName + " after failed upgrade");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3995,50 +4023,36 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
return new File(mAppInstallDir, publicZipFileName);
|
return new File(mAppInstallDir, publicZipFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PackageInstalledInfo installPackageLI(Uri pPackageURI,
|
private File copyTempInstallFile(Uri pPackageURI,
|
||||||
int pFlags, boolean newInstall, String installerPackageName) {
|
PackageInstalledInfo res) {
|
||||||
File tmpPackageFile = null;
|
File tmpPackageFile = createTempPackageFile();
|
||||||
String pkgName = null;
|
int retCode = PackageManager.INSTALL_SUCCEEDED;
|
||||||
boolean forwardLocked = false;
|
if (tmpPackageFile == null) {
|
||||||
boolean replacingExistingPackage = false;
|
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||||
// Result object to be returned
|
return null;
|
||||||
PackageInstalledInfo res = new PackageInstalledInfo();
|
}
|
||||||
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
|
|
||||||
res.uid = -1;
|
|
||||||
res.pkg = null;
|
|
||||||
res.removedInfo = new PackageRemovedInfo();
|
|
||||||
|
|
||||||
main_flow: try {
|
if (pPackageURI.getScheme().equals("file")) {
|
||||||
tmpPackageFile = createTempPackageFile();
|
final File srcPackageFile = new File(pPackageURI.getPath());
|
||||||
if (tmpPackageFile == null) {
|
// We copy the source package file to a temp file and then rename it to the
|
||||||
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
// destination file in order to eliminate a window where the package directory
|
||||||
break main_flow;
|
// scanner notices the new package file but it's not completely copied yet.
|
||||||
|
if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
|
||||||
|
Log.e(TAG, "Couldn't copy package file to temp file.");
|
||||||
|
retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||||
}
|
}
|
||||||
tmpPackageFile.deleteOnExit(); // paranoia
|
} else if (pPackageURI.getScheme().equals("content")) {
|
||||||
if (pPackageURI.getScheme().equals("file")) {
|
ParcelFileDescriptor fd = null;
|
||||||
final File srcPackageFile = new File(pPackageURI.getPath());
|
try {
|
||||||
// We copy the source package file to a temp file and then rename it to the
|
fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r");
|
||||||
// destination file in order to eliminate a window where the package directory
|
} catch (FileNotFoundException e) {
|
||||||
// scanner notices the new package file but it's not completely copied yet.
|
Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e);
|
||||||
if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
|
retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||||
Log.e(TAG, "Couldn't copy package file to temp file.");
|
}
|
||||||
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
if (fd == null) {
|
||||||
break main_flow;
|
Log.e(TAG, "Couldn't open file descriptor from download service (null).");
|
||||||
}
|
retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||||
} else if (pPackageURI.getScheme().equals("content")) {
|
} else {
|
||||||
ParcelFileDescriptor fd;
|
|
||||||
try {
|
|
||||||
fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r");
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Log.e(TAG, "Couldn't open file descriptor from download service.");
|
|
||||||
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
|
||||||
break main_flow;
|
|
||||||
}
|
|
||||||
if (fd == null) {
|
|
||||||
Log.e(TAG, "Couldn't open file descriptor from download service (null).");
|
|
||||||
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
|
||||||
break main_flow;
|
|
||||||
}
|
|
||||||
if (Config.LOGV) {
|
if (Config.LOGV) {
|
||||||
Log.v(TAG, "Opened file descriptor from download service.");
|
Log.v(TAG, "Opened file descriptor from download service.");
|
||||||
}
|
}
|
||||||
@@ -4049,14 +4063,34 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
// scanner notices the new package file but it's not completely copied yet.
|
// scanner notices the new package file but it's not completely copied yet.
|
||||||
if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) {
|
if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) {
|
||||||
Log.e(TAG, "Couldn't copy package stream to temp file.");
|
Log.e(TAG, "Couldn't copy package stream to temp file.");
|
||||||
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||||
break main_flow;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
|
|
||||||
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_URI;
|
|
||||||
break main_flow;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
|
||||||
|
retCode = PackageManager.INSTALL_FAILED_INVALID_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.returnCode = retCode;
|
||||||
|
if (retCode != PackageManager.INSTALL_SUCCEEDED) {
|
||||||
|
if (tmpPackageFile != null && tmpPackageFile.exists()) {
|
||||||
|
tmpPackageFile.delete();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tmpPackageFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void installPackageLI(Uri pPackageURI,
|
||||||
|
int pFlags, boolean newInstall, String installerPackageName,
|
||||||
|
File tmpPackageFile, PackageInstalledInfo res) {
|
||||||
|
String pkgName = null;
|
||||||
|
boolean forwardLocked = false;
|
||||||
|
boolean replacingExistingPackage = false;
|
||||||
|
// Result object to be returned
|
||||||
|
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
|
||||||
|
|
||||||
|
main_flow: try {
|
||||||
pkgName = PackageParser.parsePackageName(
|
pkgName = PackageParser.parsePackageName(
|
||||||
tmpPackageFile.getAbsolutePath(), 0);
|
tmpPackageFile.getAbsolutePath(), 0);
|
||||||
if (pkgName == null) {
|
if (pkgName == null) {
|
||||||
@@ -4128,7 +4162,6 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
tmpPackageFile.delete();
|
tmpPackageFile.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int setPermissionsLI(String pkgName,
|
private int setPermissionsLI(String pkgName,
|
||||||
|
|||||||
Reference in New Issue
Block a user