diff options
Diffstat (limited to 'services/java/com/android/server/PackageManagerService.java')
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 1294 |
1 files changed, 938 insertions, 356 deletions
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index c000d8a..e86ff02 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -55,6 +55,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; +import android.content.pm.PackageParser.Package; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -177,7 +178,7 @@ class PackageManagerService extends IPackageManager.Stub { // Lock for state used when installing and doing other long running // operations. Methods that must be called with this lock held have // the prefix "LI". - Object mInstallLock = new Object(); + final Object mInstallLock = new Object(); // These are the directories in the 3rd party applications installed dir // that we have currently loaded packages from. Keys are the application's @@ -674,7 +675,7 @@ class PackageManagerService extends IPackageManager.Stub { } } - int[] appendInt(int[] cur, int val) { + static int[] appendInt(int[] cur, int val) { if (cur == null) { return new int[] { val }; } @@ -690,7 +691,7 @@ class PackageManagerService extends IPackageManager.Stub { return ret; } - int[] appendInts(int[] cur, int[] add) { + static int[] appendInts(int[] cur, int[] add) { if (add == null) return cur; if (cur == null) return add; final int N = add.length; @@ -718,6 +719,9 @@ class PackageManagerService extends IPackageManager.Stub { if (p != null) { return generatePackageInfo(p, flags); } + if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + return generatePackageInfoFromSettingsLP(packageName, flags); + } } return null; } @@ -725,6 +729,14 @@ class PackageManagerService extends IPackageManager.Stub { public int getPackageUid(String packageName) { synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); + if(p != null) { + return p.applicationInfo.uid; + } + PackageSetting ps = mSettings.mPackages.get(packageName); + if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) { + return -1; + } + p = ps.pkg; return p != null ? p.applicationInfo.uid : -1; } } @@ -796,12 +808,39 @@ class PackageManagerService extends IPackageManager.Stub { } } + private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) { + PackageSetting ps = mSettings.mPackages.get(packageName); + if(ps != null) { + if(ps.pkg == null) { + PackageInfo pInfo = generatePackageInfoFromSettingsLP(packageName, flags); + if(pInfo != null) { + return pInfo.applicationInfo; + } + return null; + } + return PackageParser.generateApplicationInfo(ps.pkg, flags); + } + return null; + } + + private PackageInfo generatePackageInfoFromSettingsLP(String packageName, int flags) { + PackageSetting ps = mSettings.mPackages.get(packageName); + if(ps != null) { + if(ps.pkg == null) { + ps.pkg = new PackageParser.Package(packageName); + ps.pkg.applicationInfo.packageName = packageName; + } + return generatePackageInfo(ps.pkg, flags); + } + return null; + } + public ApplicationInfo getApplicationInfo(String packageName, int flags) { synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); if (Config.LOGV) Log.v( - TAG, "getApplicationInfo " + packageName - + ": " + p); + TAG, "getApplicationInfo " + packageName + + ": " + p); if (p != null) { // Note: isEnabledLP() does not apply here - always return info return PackageParser.generateApplicationInfo(p, flags); @@ -809,10 +848,14 @@ class PackageManagerService extends IPackageManager.Stub { if ("android".equals(packageName)||"system".equals(packageName)) { return mAndroidApplication; } + if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + return generateApplicationInfoFromSettingsLP(packageName, flags); + } } return null; } + public void freeApplicationCache(final long freeStorageSize, final IPackageDataObserver observer) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CLEAR_APP_CACHE, null); @@ -1063,6 +1106,19 @@ class PackageManagerService extends IPackageManager.Stub { } return null; } + + public int getUidForSharedUser(String sharedUserName) { + if(sharedUserName == null) { + return -1; + } + synchronized (mPackages) { + SharedUserSetting suid = mSettings.getSharedUserLP(sharedUserName, 0, false); + if(suid == null) { + return -1; + } + return suid.userId; + } + } public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags) { @@ -1391,37 +1447,63 @@ class PackageManagerService extends IPackageManager.Stub { queryIntent(null, intent, resolvedType, flags); } } - + public List<PackageInfo> getInstalledPackages(int flags) { ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>(); synchronized (mPackages) { - Iterator<PackageParser.Package> i = mPackages.values().iterator(); - while (i.hasNext()) { - final PackageParser.Package p = i.next(); - PackageInfo pi = generatePackageInfo(p, flags); - if (pi != null) { - finalList.add(pi); + if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + Iterator<PackageSetting> i = mSettings.mPackages.values().iterator(); + while (i.hasNext()) { + final PackageSetting ps = i.next(); + PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags); + if(psPkg != null) { + finalList.add(psPkg); + } + } + } + else { + Iterator<PackageParser.Package> i = mPackages.values().iterator(); + while (i.hasNext()) { + final PackageParser.Package p = i.next(); + if (p.applicationInfo != null) { + PackageInfo pi = generatePackageInfo(p, flags); + if(pi != null) { + finalList.add(pi); + } + } } } } - return finalList; } public List<ApplicationInfo> getInstalledApplications(int flags) { ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>(); - - synchronized (mPackages) { - Iterator<PackageParser.Package> i = mPackages.values().iterator(); - while (i.hasNext()) { - final PackageParser.Package p = i.next(); - if (p.applicationInfo != null) { - finalList.add(p.applicationInfo); + synchronized(mPackages) { + if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + Iterator<PackageSetting> i = mSettings.mPackages.values().iterator(); + while (i.hasNext()) { + final PackageSetting ps = i.next(); + ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags); + if(ai != null) { + finalList.add(ai); + } + } + } + else { + Iterator<PackageParser.Package> i = mPackages.values().iterator(); + while (i.hasNext()) { + final PackageParser.Package p = i.next(); + if (p.applicationInfo != null) { + ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags); + if(ai != null) { + finalList.add(ai); + } + } } } } - return finalList; } @@ -1569,7 +1651,7 @@ class PackageManagerService extends IPackageManager.Stub { PackageParser.Package pkg, File srcFile, int parseFlags) { if (GET_CERTIFICATES) { if (ps == null || !ps.codePath.equals(srcFile) - || ps.timeStamp != srcFile.lastModified()) { + || ps.getTimeStamp() != srcFile.lastModified()) { Log.i(TAG, srcFile.toString() + " changed; collecting certs"); if (!pp.collectCertificates(pkg, parseFlags)) { mLastScanError = pp.getParseError(); @@ -1580,6 +1662,10 @@ class PackageManagerService extends IPackageManager.Stub { return true; } + /* + * Scan a package and return the newly parsed package. + * Returns null in case of errors and the error code is stored in mLastScanError + */ private PackageParser.Package scanPackageLI(File scanFile, File destCodeFile, File destResourceFile, int parseFlags, int scanMode) { @@ -1595,11 +1681,29 @@ class PackageManagerService extends IPackageManager.Stub { return null; } PackageSetting ps; + PackageSetting updatedPkg; synchronized (mPackages) { ps = mSettings.peekPackageLP(pkg.packageName, scanFile.toString()); + updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName); + } + if (updatedPkg != null) { + // An updated system app will not have the PARSE_IS_SYSTEM flag set initially + parseFlags |= PackageParser.PARSE_IS_SYSTEM; + } + if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { + // Check for updated system applications here + if ((updatedPkg != null) && (ps == null)) { + // The system package has been updated and the code path does not match + // Ignore entry. Just return + Log.w(TAG, "Package:" + pkg.packageName + + " has been updated. Ignoring the one from path:"+scanFile); + mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; + return null; + } } if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) { + Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName); return null; } // The apk is forward locked (not public) if its code and resources @@ -1607,6 +1711,7 @@ class PackageManagerService extends IPackageManager.Stub { if (ps != null && !ps.codePath.equals(ps.resourcePath)) { scanMode |= SCAN_FORWARD_LOCKED; } + // Note that we invoke the following method only if we are about to unpack an application return scanPackageLI(scanFile, destCodeFile, destResourceFile, pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE); } @@ -1652,6 +1757,7 @@ class PackageManagerService extends IPackageManager.Stub { mScanningPath = scanFile; if (pkg == null) { + mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; return null; } @@ -1681,7 +1787,7 @@ class PackageManagerService extends IPackageManager.Stub { mResolveActivity.packageName = mAndroidApplication.packageName; mResolveActivity.processName = mAndroidApplication.processName; mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - mResolveActivity.flags = 0; + mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; mResolveActivity.theme = com.android.internal.R.style.Theme_Dialog_Alert; mResolveActivity.exported = true; mResolveActivity.enabled = true; @@ -1748,6 +1854,11 @@ class PackageManagerService extends IPackageManager.Stub { mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; return null; } + synchronized(mPackages) { + if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) { + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + } + } pkg.applicationInfo.uid = pkgSetting.userId; pkg.mExtras = pkgSetting; @@ -1755,6 +1866,7 @@ class PackageManagerService extends IPackageManager.Stub { if (!verifySignaturesLP(pkgSetting, pkg, parseFlags, (scanMode&SCAN_UPDATE_SIGNATURE) != 0)) { if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) == 0) { + mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; return null; } // The signature has changed, but this package is in the system @@ -1768,6 +1880,7 @@ class PackageManagerService extends IPackageManager.Stub { if (pkgSetting.sharedUser != null) { if (!pkgSetting.sharedUser.signatures.mergeSignatures( pkg.mSignatures, false)) { + mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; return null; } } @@ -1782,6 +1895,7 @@ class PackageManagerService extends IPackageManager.Stub { String msg = "System package " + pkg.packageName + " could not have data directory erased after signature change."; reportSettingsProblem(Log.WARN, msg); + mLastScanError = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; return null; } } @@ -1792,7 +1906,7 @@ class PackageManagerService extends IPackageManager.Stub { long scanFileTime = scanFile.lastModified(); final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0; - final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.timeStamp; + final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp(); // At this point we know it is okay to accept the package, though // errors can still happen as we try to install... @@ -3037,48 +3151,363 @@ class PackageManagerService extends IPackageManager.Stub { PackageRemovedInfo removedInfo; } - PackageInstalledInfo installPackageLI(Uri packageURI, int flags) { - int returnCode = PackageManager.INSTALL_SUCCEEDED; - String installedPackageName = null; - int installedPackageUid = -1; - PackageParser.Package installedPackage = null; + /* + * Install a non-existing package. + */ + private void installNewPackageLI(String pkgName, int parseFlags, + File tmpPackageFile, + String destFilePath, File destPackageFile, File destResourceFile, + PackageParser.Package pkg, boolean forwardLocked, + PackageInstalledInfo res) { + // Remember this for later, in case we need to rollback this install + boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists(); + res.name = pkgName; + synchronized(mPackages) { + if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) { + // Don't allow installation over an existing package with the same name. + Log.w(TAG, "Attempt to re-install " + pkgName + + " without first uninstalling."); + res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; + return; + } + } + if (destPackageFile.exists()) { + // It's safe to do this because we know (from the above check) that the file + // isn't currently used for an installed package. + destPackageFile.delete(); + } + mLastScanError = PackageManager.INSTALL_SUCCEEDED; + PackageParser.Package newPackage = scanPackageLI(tmpPackageFile, destPackageFile, + destResourceFile, pkg, parseFlags, + SCAN_MONITOR | SCAN_FORCE_DEX + | SCAN_UPDATE_SIGNATURE + | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); + if (newPackage == null) { + Log.w(TAG, "Package couldn't be installed in " + destPackageFile); + if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; + } + } else { + updateSettingsLI(pkgName, tmpPackageFile, + destFilePath, destPackageFile, + destResourceFile, pkg, + newPackage, + true, + forwardLocked, + 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, true, + dataDirExists ? PackageManager.DONT_DELETE_DATA : 0, + res.removedInfo); + } + } + } + + private void replacePackageLI(String pkgName, int parseFlags, + File tmpPackageFile, + String destFilePath, File destPackageFile, File destResourceFile, + PackageParser.Package pkg, boolean forwardLocked, + PackageInstalledInfo res) { + PackageParser.Package deletedPackage; + // First find the old package info and check signatures + synchronized(mPackages) { + deletedPackage = mPackages.get(pkgName); + if(checkSignaturesLP(pkg, deletedPackage) != PackageManager.SIGNATURE_MATCH) { + res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; + return; + } + } + boolean sysPkg = ((deletedPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); + if(sysPkg) { + replaceSystemPackageLI(deletedPackage, + parseFlags, + tmpPackageFile, destFilePath, + destPackageFile, destResourceFile, pkg, forwardLocked, res); + } else { + replaceNonSystemPackageLI(deletedPackage, parseFlags, tmpPackageFile, destFilePath, + destPackageFile, destResourceFile, pkg, forwardLocked, res); + } + } + + private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags, + File tmpPackageFile, + String destFilePath, File destPackageFile, File destResourceFile, + PackageParser.Package pkg, boolean forwardLocked, + PackageInstalledInfo res) { + PackageParser.Package newPackage = null; + String pkgName = deletedPackage.packageName; + boolean deletedPkg = true; + boolean updatedSettings = false; + // First delete the existing package while retaining the data directory + if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA, + res.removedInfo)) { + // If the existing package was'nt successfully deleted + res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; + deletedPkg = false; + } else { + // Successfully deleted the old package. Now proceed with re-installation + mLastScanError = PackageManager.INSTALL_SUCCEEDED; + newPackage = scanPackageLI(tmpPackageFile, destPackageFile, + destResourceFile, pkg, parseFlags, + SCAN_MONITOR | SCAN_FORCE_DEX + | SCAN_UPDATE_SIGNATURE + | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); + if (newPackage == null) { + Log.w(TAG, "Package couldn't be installed in " + destPackageFile); + if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; + } + } else { + updateSettingsLI(pkgName, tmpPackageFile, + destFilePath, destPackageFile, + destResourceFile, pkg, + newPackage, + true, + forwardLocked, + res); + updatedSettings = true; + } + } + + if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { + // If we deleted an exisiting package, the old source and resource files that we + // were keeping around in case we needed them (see below) can now be deleted + final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo; + final ApplicationInfo installedPackageAppInfo = + newPackage.applicationInfo; + if (!deletedPackageAppInfo.sourceDir + .equals(installedPackageAppInfo.sourceDir)) { + new File(deletedPackageAppInfo.sourceDir).delete(); + } + if (!deletedPackageAppInfo.publicSourceDir + .equals(installedPackageAppInfo.publicSourceDir)) { + new File(deletedPackageAppInfo.publicSourceDir).delete(); + } + //update signature on the new package setting + //this should always succeed, since we checked the + //signature earlier. + synchronized(mPackages) { + verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg, + parseFlags, true); + } + } else { + // 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. + if(updatedSettings) { + deletePackageLI( + pkgName, true, + PackageManager.DONT_DELETE_DATA, + res.removedInfo); + } + // Since we failed to install the new package we need to restore the old + // package that we deleted. + if(deletedPkg) { + installPackageLI( + Uri.fromFile(new File(deletedPackage.mPath)), + isForwardLocked(deletedPackage) + ? PackageManager.FORWARD_LOCK_PACKAGE + : 0); + } + } + } + + private void replaceSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags, + File tmpPackageFile, + String destFilePath, File destPackageFile, File destResourceFile, + PackageParser.Package pkg, boolean forwardLocked, + PackageInstalledInfo res) { + PackageParser.Package newPackage = null; + boolean updatedSettings = false; + parseFlags |= PackageParser.PARSE_IS_SYSTEM; + String packageName = deletedPackage.packageName; + res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; + if (packageName == null) { + Log.w(TAG, "Attempt to delete null packageName."); + return; + } + PackageParser.Package oldPkg; + PackageSetting oldPkgSetting; + synchronized (mPackages) { + oldPkg = mPackages.get(packageName); + oldPkgSetting = mSettings.mPackages.get(packageName); + if((oldPkg == null) || (oldPkg.applicationInfo == null) || + (oldPkgSetting == null)) { + Log.w(TAG, "Could'nt find package:"+packageName+" information"); + return; + } + } + res.removedInfo.uid = oldPkg.applicationInfo.uid; + res.removedInfo.removedPackage = packageName; + // Remove existing system package + removePackageLI(oldPkg, true); + synchronized (mPackages) { + res.removedInfo.removedUid = mSettings.disableSystemPackageLP(packageName); + } + + // Successfully disabled the old package. Now proceed with re-installation + mLastScanError = PackageManager.INSTALL_SUCCEEDED; + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + newPackage = scanPackageLI(tmpPackageFile, destPackageFile, + destResourceFile, pkg, parseFlags, + SCAN_MONITOR | SCAN_FORCE_DEX + | SCAN_UPDATE_SIGNATURE + | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); + if (newPackage == null) { + Log.w(TAG, "Package couldn't be installed in " + destPackageFile); + if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; + } + } else { + updateSettingsLI(packageName, tmpPackageFile, + destFilePath, destPackageFile, + destResourceFile, pkg, + newPackage, + true, + forwardLocked, + res); + updatedSettings = true; + } + + if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { + //update signature on the new package setting + //this should always succeed, since we checked the + //signature earlier. + synchronized(mPackages) { + verifySignaturesLP(mSettings.mPackages.get(packageName), pkg, + parseFlags, true); + } + } else { + // Re installation failed. Restore old information + // Remove new pkg information + removePackageLI(newPackage, true); + // Add back the old system package + scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath, + oldPkgSetting.resourcePath, + oldPkg, parseFlags, + SCAN_MONITOR + | SCAN_UPDATE_SIGNATURE + | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); + // Restore the old system information in Settings + synchronized(mPackages) { + if(updatedSettings) { + mSettings.enableSystemPackageLP(packageName); + } + mSettings.writeLP(); + } + } + } + + private void updateSettingsLI(String pkgName, File tmpPackageFile, + String destFilePath, File destPackageFile, + File destResourceFile, + PackageParser.Package pkg, + PackageParser.Package newPackage, + boolean replacingExistingPackage, + boolean forwardLocked, + PackageInstalledInfo res) { + synchronized (mPackages) { + //write settings. the installStatus will be incomplete at this stage. + //note that the new package setting would have already been + //added to mPackages. It hasn't been persisted yet. + mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE); + mSettings.writeLP(); + } + + int retCode = 0; + if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { + retCode = mInstaller.movedex(tmpPackageFile.toString(), + destPackageFile.toString()); + if (retCode != 0) { + Log.e(TAG, "Couldn't rename dex file: " + destPackageFile); + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + return; + } + } + // XXX There are probably some big issues here: upon doing + // the rename, we have reached the point of no return (the + // original .apk is gone!), so we can't fail. Yet... we can. + if (!tmpPackageFile.renameTo(destPackageFile)) { + Log.e(TAG, "Couldn't move package file to: " + destPackageFile); + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } else { + res.returnCode = setPermissionsLI(pkgName, newPackage, destFilePath, + destResourceFile, + forwardLocked); + if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) { + return; + } else { + Log.d(TAG, "New package installed in " + destPackageFile); + } + } + if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) { + if (mInstaller != null) { + mInstaller.rmdex(tmpPackageFile.getPath()); + } + } + + synchronized (mPackages) { + grantPermissionsLP(newPackage, true); + res.name = pkgName; + res.uid = newPackage.applicationInfo.uid; + res.pkg = newPackage; + mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE); + res.returnCode = PackageManager.INSTALL_SUCCEEDED; + //to update install status + mSettings.writeLP(); + } + } + + private PackageInstalledInfo installPackageLI(Uri pPackageURI, int pFlags) { File tmpPackageFile = null; - boolean wroteSettings = false; String pkgName = null; - PackageParser.Package newPackage = null; - boolean dataDirExists = false; - PackageParser.Package deletedPackage = null; - PackageRemovedInfo removedInfo = new PackageRemovedInfo(); + boolean forwardLocked = false; + boolean replacingExistingPackage = false; + + // Result object to be returned + PackageInstalledInfo res = new PackageInstalledInfo(); + res.returnCode = PackageManager.INSTALL_SUCCEEDED; + res.uid = -1; + res.pkg = null; + res.removedInfo = new PackageRemovedInfo(); main_flow: try { tmpPackageFile = createTempPackageFile(); if (tmpPackageFile == null) { - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } tmpPackageFile.deleteOnExit(); // paranoia - if (packageURI.getScheme().equals("file")) { - final File srcPackageFile = new File(packageURI.getPath()); + if (pPackageURI.getScheme().equals("file")) { + final File srcPackageFile = new File(pPackageURI.getPath()); // We copy the source package file to a temp file and then rename it to the // destination file in order to eliminate a window where the package directory // 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."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } - } else if (packageURI.getScheme().equals("content")) { + } else if (pPackageURI.getScheme().equals("content")) { ParcelFileDescriptor fd; try { - fd = mContext.getContentResolver().openFileDescriptor(packageURI, "r"); + fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r"); } catch (FileNotFoundException e) { Log.e(TAG, "Couldn't open file descriptor from download service."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + 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)."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } if (Config.LOGV) { @@ -3091,36 +3520,38 @@ class PackageManagerService extends IPackageManager.Stub { // scanner notices the new package file but it's not completely copied yet. if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) { Log.e(TAG, "Couldn't copy package stream to temp file."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } } else { - Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + packageURI); - returnCode = PackageManager.INSTALL_FAILED_INVALID_URI; + Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI); + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_URI; break main_flow; - } + } pkgName = PackageParser.parsePackageName( tmpPackageFile.getAbsolutePath(), 0); if (pkgName == null) { Log.e(TAG, "Couldn't find a package name in : " + tmpPackageFile); - returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; break main_flow; } + res.name = pkgName; //initialize some variables before installing pkg final String pkgFileName = pkgName + ".apk"; - final File destDir = ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) + final File destDir = ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) ? mDrmAppPrivateInstallDir : mAppInstallDir; final File destPackageFile = new File(destDir, pkgFileName); final String destFilePath = destPackageFile.getAbsolutePath(); File destResourceFile; - if ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) { + if ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) { final String publicZipFileName = pkgName + ".zip"; destResourceFile = new File(mAppInstallDir, publicZipFileName); + forwardLocked = true; } else { destResourceFile = destPackageFile; } - //retrieve PackageSettings and parse package + // Retrieve PackageSettings and parse package int parseFlags = PackageParser.PARSE_CHATTY; parseFlags |= mDefParseFlags; PackageParser pp = new PackageParser(tmpPackageFile.getPath()); @@ -3129,204 +3560,79 @@ class PackageManagerService extends IPackageManager.Stub { final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, destPackageFile.getAbsolutePath(), mMetrics, parseFlags); if (pkg == null) { - returnCode = pp.getParseError(); + res.returnCode = pp.getParseError(); break main_flow; } if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) { - returnCode = pp.getParseError(); + res.returnCode = pp.getParseError(); break main_flow; } - boolean replacingExistingPackage = false; - synchronized (mPackages) { //check if installing already existing package - if ((flags&PackageManager.REPLACE_EXISTING_PACKAGE) != 0 + if ((pFlags&PackageManager.REPLACE_EXISTING_PACKAGE) != 0 && mPackages.containsKey(pkgName)) { replacingExistingPackage = true; - deletedPackage = mPackages.get(pkgName); - if(checkSignaturesLP(pkg, deletedPackage) != PackageManager.SIGNATURE_MATCH) { - returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; - break main_flow; - } - } - } - - if (replacingExistingPackage) { - if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA, - removedInfo)) { - returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; - break main_flow; - } - } else { - if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) { - // Don't allow installation over an existing package with the same name. - Log.w(TAG, "Attempt to re-install " + pkgName - + " without first uninstalling."); - returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; - break main_flow; - } - if (destPackageFile.exists()) { - // It's safe to do this because we know (from the above check) that the file - // isn't currently used for an installed package. - destPackageFile.delete(); - } - } - - // Remember this for later, in case we need to rollback this install - dataDirExists = (new File(mAppDataDir, pkgName)).exists(); - mLastScanError = PackageManager.INSTALL_SUCCEEDED; - newPackage = scanPackageLI(tmpPackageFile, destPackageFile, - destResourceFile, pkg, parseFlags, - SCAN_MONITOR | SCAN_FORCE_DEX - | (!replacingExistingPackage ? SCAN_UPDATE_SIGNATURE : 0) - | ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0 - ? SCAN_FORWARD_LOCKED : 0)); - if (newPackage == null) { - if (Config.LOGD) { - Log.w(TAG, "Package couldn't be installed in " + destPackageFile); - } - if ((returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { - returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; } - break main_flow; } - synchronized (mPackages) { - //write settings. the installStatus will be incomplete at this stage. - //note that the new package setting would have already been - //added to mPackages. It hasn't been persisted yet. - mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE); - mSettings.writeLP(); - wroteSettings = true; - } - - int retCode = 0; - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { - retCode = mInstaller.movedex(tmpPackageFile.toString(), - destPackageFile.toString()); - if (retCode != 0) { - Log.e(TAG, "Couldn't rename dex file: " + destPackageFile); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - } - // XXX There are probably some big issues here: upon doing - // the rename, we have reached the point of no return (the - // original .apk is gone!), so we can't fail. Yet... we can. - if (tmpPackageFile.renameTo(destPackageFile)) { - if ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) { - try { - extractPublicFiles(newPackage, destResourceFile); - } catch (IOException e) { - Log.e(TAG, "Couldn't create a new zip file for the public parts of a" + - " forward-locked app."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - if (mInstaller != null) { - retCode = mInstaller.setForwardLockPerm(pkgName, - newPackage.applicationInfo.uid); - } else { - final int filePermissions = - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP; - retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, - newPackage.applicationInfo.uid); - } - } else { - final int filePermissions = - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP - |FileUtils.S_IROTH; - retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1); - } - if (retCode != 0) { - Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath - + ". The return code was: " + retCode); - } - if (Config.LOGD) { - Log.d(TAG, "New package installed in " + destPackageFile); - } - - synchronized (mPackages) { - grantPermissionsLP(newPackage, true); - installedPackageName = pkgName; - installedPackageUid = newPackage.applicationInfo.uid; - installedPackage = newPackage; - if(replacingExistingPackage) { - //update signature on the new package setting - //this should always succeed, since we checked the - //signature earlier. - verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg, - parseFlags, true); - } - mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE); - returnCode = PackageManager.INSTALL_SUCCEEDED; - //to update install status - mSettings.writeLP(); - break main_flow; - } + if(replacingExistingPackage) { + replacePackageLI(pkgName, pFlags, + tmpPackageFile, + destFilePath, destPackageFile, destResourceFile, + pkg, forwardLocked, + res); } else { - Log.e(TAG, "Couldn't move package file to: " + destPackageFile); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; + installNewPackageLI(pkgName, pFlags, + tmpPackageFile, + destFilePath, destPackageFile, destResourceFile, + pkg, forwardLocked, + res); } } finally { if (tmpPackageFile != null && tmpPackageFile.exists()) { tmpPackageFile.delete(); } - - //if install was successful the pkg's installStatus would have - //been updated and hence needs to be persisted. if not - //the pkg info needs to be cleaned up. - if (returnCode == PackageManager.INSTALL_SUCCEEDED) { - if (deletedPackage != null) { - // If we deleted an exisiting package, the old source and resource files that we - // were keeping around in case we needed them (see below) can now be deleted - final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo; - final ApplicationInfo installedPackageAppInfo = - installedPackage.applicationInfo; - if (!deletedPackageAppInfo.sourceDir - .equals(installedPackageAppInfo.sourceDir)) { - new File(deletedPackageAppInfo.sourceDir).delete(); - } - if (!deletedPackageAppInfo.publicSourceDir - .equals(installedPackageAppInfo.publicSourceDir)) { - new File(deletedPackageAppInfo.publicSourceDir).delete(); - } - } + return res; + } + } + + private int setPermissionsLI(String pkgName, + PackageParser.Package newPackage, + String destFilePath, + File destResourceFile, + boolean forwardLocked) { + int retCode; + if (forwardLocked) { + try { + extractPublicFiles(newPackage, destResourceFile); + } catch (IOException e) { + Log.e(TAG, "Couldn't create a new zip file for the public parts of a" + + " forward-locked app."); + return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } finally { + //TODO clean up the extracted public files + } + if (mInstaller != null) { + retCode = mInstaller.setForwardLockPerm(pkgName, + newPackage.applicationInfo.uid); } else { - if (mInstaller != null) { - mInstaller.rmdex(tmpPackageFile.getPath()); - } - if (wroteSettings) { - // 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, true, - dataDirExists ? PackageManager.DONT_DELETE_DATA : 0, - new PackageRemovedInfo()); - if (deletedPackage != null) { - // Since we failed to install the new package we need to restore the old - // package that we deleted. - installPackageLI( - Uri.fromFile(new File(deletedPackage.mPath)), - isForwardLocked(deletedPackage) - ? PackageManager.FORWARD_LOCK_PACKAGE - : 0); - } - } + final int filePermissions = + FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP; + retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, + newPackage.applicationInfo.uid); } + } else { + final int filePermissions = + FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP + |FileUtils.S_IROTH; + retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1); } - - PackageInstalledInfo res = new PackageInstalledInfo(); - res.name = installedPackageName; - res.uid = installedPackageUid; - res.pkg = installedPackage; - res.returnCode = returnCode; - res.removedInfo = removedInfo; - return res; + if (retCode != 0) { + Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath + + ". The return code was: " + retCode); + } + return PackageManager.INSTALL_SUCCEEDED; } private boolean isForwardLocked(PackageParser.Package deletedPackage) { @@ -3470,11 +3776,6 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mInstallLock) { res = deletePackageLI(packageName, deleteCodeAndResources, flags, info); - if (res) { - synchronized (mPackages) { - mSettings.writeLP(); - } - } } if(res && sendBroadCast) { @@ -3500,44 +3801,117 @@ class PackageManagerService extends IPackageManager.Stub { } } - private boolean deletePackageLI(String packageName, + /* + * This method deletes the package from internal data structures. If the DONT_DELETE_DATA + * flag is not set, the data directory is removed as well. + * make sure this flag is set for partially installed apps. If not its meaningless to + * delete a partially installed application. + */ + private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo, + int flags) { + String packageName = p.packageName; + outInfo.removedPackage = packageName; + removePackageLI(p, true); + // Retrieve object to delete permissions for shared user later on + PackageSetting deletedPs; + synchronized (mPackages) { + deletedPs = mSettings.mPackages.get(packageName); + } + if ((flags&PackageManager.DONT_DELETE_DATA) == 0) { + if (mInstaller != null) { + int retCode = mInstaller.remove(packageName); + if (retCode < 0) { + Log.w(TAG, "Couldn't remove app data or cache directory for package: " + + packageName + ", retcode=" + retCode); + // we don't consider this to be a failure of the core package deletion + } + } else { + //for emulator + PackageParser.Package pkg = mPackages.get(packageName); + File dataDir = new File(pkg.applicationInfo.dataDir); + dataDir.delete(); + } + synchronized (mPackages) { + outInfo.removedUid = mSettings.removePackageLP(packageName); + } + } + synchronized (mPackages) { + if ( (deletedPs != null) && (deletedPs.sharedUser != null)) { + // remove permissions associated with package + mSettings.updateSharedUserPerms (deletedPs); + } + // Save settings now + mSettings.writeLP (); + } + } + + /* + * Tries to delete system package. + */ + private boolean deleteSystemPackageLI(PackageParser.Package p, boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { - if (packageName == null) { - Log.w(TAG, "Attempt to delete null packageName."); + ApplicationInfo applicationInfo = p.applicationInfo; + //applicable for non-partially installed applications only + if (applicationInfo == null) { + Log.w(TAG, "Package " + p.packageName + " has no applicationInfo."); return false; } - PackageParser.Package p; + PackageSetting ps = null; + // Confirm if the system package has been updated + // An updated system app can be deleted. This will also have to restore + // the system pkg from system partition synchronized (mPackages) { - p = mPackages.get(packageName); + ps = mSettings.getDisabledSystemPkg(p.packageName); } - if (p == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + if (ps == null) { + Log.w(TAG, "Attempt to delete system package "+ p.packageName); return false; + } else { + Log.i(TAG, "Deleting system pkg from data partition"); } - final ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + packageName + " has no applicationInfo."); + // Delete the updated package + boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo); + if (!ret) { return false; } - - // NB: This is a public nonfinal boolean so it theoretically - // could be altered by anyone. In practice, that can only be - // done from within this same process, and anyway file - // permissions will prevent unauthorized deletion of system - // packages. - if ((applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - Log.w(TAG, "Attempt to delete system package "+ packageName); + synchronized (mPackages) { + // Reinstate the old system package + mSettings.enableSystemPackageLP(p.packageName); + } + // Install the system package + PackageParser.Package newPkg = scanPackageLI(ps.codePath, ps.codePath, ps.resourcePath, + PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM, + SCAN_MONITOR); + + if (newPkg == null) { + Log.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError); return false; } - final File sourceFile = new File(applicationInfo.sourceDir); + synchronized (mPackages) { + mSettings.writeLP(); + } + return true; + } + + private boolean deleteInstalledPackageLI(PackageParser.Package p, + boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { + ApplicationInfo applicationInfo = p.applicationInfo; + if (applicationInfo == null) { + Log.w(TAG, "Package " + p.packageName + " has no applicationInfo."); + return false; + } + // Delete application's source directory + File sourceFile = new File(applicationInfo.sourceDir); if (!sourceFile.exists()) { Log.w(TAG, "Package source " + applicationInfo.sourceDir + " does not exist."); return false; } - outInfo.uid = p.applicationInfo.uid; + outInfo.uid = applicationInfo.uid; - outInfo.removedPackage = packageName; - removePackageLI(p, true); + // Delete package data from internal structures and also remove data if flag is set + removePackageDataLI(p, outInfo, flags); + + // Delete application code and resources if (deleteCodeAndResources) { sourceFile.delete(); final File publicSourceFile = new File(applicationInfo.publicSourceDir); @@ -3548,30 +3922,61 @@ class PackageManagerService extends IPackageManager.Stub { int retCode = mInstaller.rmdex(sourceFile.toString()); if (retCode < 0) { Log.w(TAG, "Couldn't remove dex file for package: " - + packageName + ", retcode=" + retCode); + + p.packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode); // we don't consider this to be a failure of the core package deletion } } } - if ((flags&PackageManager.DONT_DELETE_DATA) == 0) { - if (mInstaller != null) { - int retCode = mInstaller.remove(packageName); - if (retCode < 0) { - Log.w(TAG, "Couldn't remove app data or cache directory for package: " - + packageName + ", retcode=" + retCode); - // we don't consider this to be a failure of the core package deletion + return true; + } + + /* + * This method handles package deletion in general + */ + private boolean deletePackageLI(String packageName, + boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { + if (packageName == null) { + Log.w(TAG, "Attempt to delete null packageName."); + return false; + } + PackageParser.Package p; + boolean dataOnly = false; + synchronized (mPackages) { + p = mPackages.get(packageName); + if (p == null) { + //this retrieves partially installed apps + dataOnly = true; + PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps == null) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; } - } else { - //for emulator - PackageParser.Package pkg = mPackages.get(packageName); - File dataDir = new File(pkg.applicationInfo.dataDir); - dataDir.delete(); - } - synchronized (mPackages) { - outInfo.removedUid = mSettings.removePackageLP(packageName); + p = ps.pkg; } } - return true; + if (p == null) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; + } + + if (dataOnly) { + // Delete application data first + removePackageDataLI(p, outInfo, flags); + return true; + } + // At this point the package should have ApplicationInfo associated with it + if (p.applicationInfo == null) { + Log.w(TAG, "Package " + p.packageName + " has no applicationInfo."); + return false; + } + if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + Log.i(TAG, "Removing system package:"+p.packageName); + // When an updated system application is deleted we delete the existing resources as well and + // fall back to existing code in system partition + return deleteSystemPackageLI(p, true, flags, outInfo); + } + Log.i(TAG, "Removing non-system package:"+p.packageName); + return deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo); } public void clearApplicationUserData(final String packageName, @@ -3582,21 +3987,21 @@ class PackageManagerService extends IPackageManager.Stub { mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); - final boolean succeded; + final boolean succeeded; synchronized (mInstallLock) { - succeded = clearApplicationUserDataLI(packageName); - } - if(succeded) { - //invoke DeviceMemoryMonitor's update method to clear any notifications - DeviceMemoryMonitorService dmm = (DeviceMemoryMonitorService) - ServiceManager.getService("devicememorymonitor"); - if(dmm!=null) { - dmm.updateMemory(); + succeeded = clearApplicationUserDataLI(packageName); + } + if (succeeded) { + // invoke DeviceStorageMonitor's update method to clear any notifications + DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) + ServiceManager.getService(DeviceStorageMonitorService.SERVICE); + if (dsm != null) { + dsm.updateMemory(); } } if(observer != null) { try { - observer.onRemoveCompleted(packageName, succeded); + observer.onRemoveCompleted(packageName, succeeded); } catch (RemoteException e) { Log.i(TAG, "Observer no longer exists."); } @@ -3611,23 +4016,36 @@ class PackageManagerService extends IPackageManager.Stub { return false; } PackageParser.Package p; + boolean dataOnly = false; synchronized (mPackages) { p = mPackages.get(packageName); + if(p == null) { + dataOnly = true; + PackageSetting ps = mSettings.mPackages.get(packageName); + if((ps == null) || (ps.pkg == null)) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; + } + p = ps.pkg; + } } - if (p == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - final ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + packageName + " has no applicationInfo."); - return false; + if(!dataOnly) { + //need to check this only for fully installed applications + if (p == null) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; + } + final ApplicationInfo applicationInfo = p.applicationInfo; + if (applicationInfo == null) { + Log.w(TAG, "Package " + packageName + " has no applicationInfo."); + return false; + } } if (mInstaller != null) { int retCode = mInstaller.clearUserData(packageName); if (retCode < 0) { Log.w(TAG, "Couldn't remove cache files for package: " - + packageName); + + packageName); return false; } } @@ -3716,22 +4134,31 @@ class PackageManagerService extends IPackageManager.Stub { return false; } PackageParser.Package p; + boolean dataOnly = false; synchronized (mPackages) { p = mPackages.get(packageName); + if(p == null) { + dataOnly = true; + PackageSetting ps = mSettings.mPackages.get(packageName); + if((ps == null) || (ps.pkg == null)) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; + } + p = ps.pkg; + } } - if (p == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - final ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + packageName + " has no applicationInfo."); - return false; + String publicSrcDir = null; + if(!dataOnly) { + final ApplicationInfo applicationInfo = p.applicationInfo; + if (applicationInfo == null) { + Log.w(TAG, "Package " + packageName + " has no applicationInfo."); + return false; + } + publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null; } if (mInstaller != null) { int res = mInstaller.getSizeInfo(packageName, p.mPath, - isForwardLocked(p) ? applicationInfo.publicSourceDir : null, - pStats); + publicSrcDir, pStats); if (res < 0) { return false; } else { @@ -4051,7 +4478,7 @@ class PackageManagerService extends IPackageManager.Stub { if (ps.pkg != null) { pw.println(" dataDir=" + ps.pkg.applicationInfo.dataDir); } - pw.println(" timeStamp=" + ps.timeStamp); + pw.println(" timeStamp=" + ps.getTimeStampStr()); pw.println(" signatures=" + ps.signatures); pw.println(" permissionsFixed=" + ps.permissionsFixed + " pkgFlags=0x" + Integer.toHexString(ps.pkgFlags) @@ -4569,8 +4996,8 @@ class PackageManagerService extends IPackageManager.Stub { final String codePathString; final File resourcePath; final String resourcePathString; - long timeStamp; - String timeStampString = "0"; + private long timeStamp; + private String timeStampString = "0"; PackageSignatures signatures = new PackageSignatures(); @@ -4612,6 +5039,14 @@ class PackageManagerService extends IPackageManager.Stub { timeStamp = newStamp; timeStampString = newStampStr; } + + public long getTimeStamp() { + return timeStamp; + } + + public String getTimeStampStr() { + return timeStampString; + } public void copyFrom(PackageSettingBase base) { grantedPermissions = base.grantedPermissions; @@ -4709,6 +5144,10 @@ class PackageManagerService extends IPackageManager.Stub { // First is the most preferred. private final ArrayList<PackageSetting> mPreferredPackages = new ArrayList<PackageSetting>(); + // List of replaced system applications + final HashMap<String, PackageSetting> mDisabledSysPackages = + new HashMap<String, PackageSetting>(); + // The user's preferred activities associated with particular intent // filters. private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities = @@ -4781,6 +5220,7 @@ class PackageManagerService extends IPackageManager.Stub { final String name = pkg.packageName; PackageSetting p = getPackageLP(name, sharedUser, codePath, resourcePath, pkgFlags, create); + if (p != null) { p.pkg = pkg; } @@ -4836,6 +5276,39 @@ class PackageManagerService extends IPackageManager.Stub { return s; } + int disableSystemPackageLP(String name) { + PackageSetting p = mPackages.get(name); + if(p == null) { + Log.w(TAG, "Package:"+name+" is not an installed package"); + return -1; + } + PackageSetting dp = mDisabledSysPackages.get(name); + // always make sure the system package code and resource paths dont change + if(dp == null) { + if((p.pkg != null) && (p.pkg.applicationInfo != null)) { + p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + } + mDisabledSysPackages.put(name, p); + } + return removePackageLP(name); + } + + PackageSetting enableSystemPackageLP(String name) { + PackageSetting p = mDisabledSysPackages.get(name); + if(p == null) { + Log.w(TAG, "Package:"+name+" is not disabled"); + return null; + } + // Reset flag in ApplicationInfo object + if((p.pkg != null) && (p.pkg.applicationInfo != null)) { + p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + } + PackageSetting ret = addPackageLP(name, p.codePath, + p.resourcePath, p.userId, p.pkgFlags); + mDisabledSysPackages.remove(name); + return ret; + } + PackageSetting addPackageLP(String name, File codePath, File resourcePath, int uid, int pkgFlags) { PackageSetting p = mPackages.get(name); @@ -4881,10 +5354,22 @@ class PackageManagerService extends IPackageManager.Stub { PackageSetting p = mPackages.get(name); if (p != null) { if (!p.codePath.equals(codePath)) { - reportSettingsProblem(Log.WARN, - "Package " + name + " codePath changed from " + p.codePath - + " to " + codePath + "; replacing with new"); - p = null; + // Check to see if its a disabled system app + PackageSetting ps = mDisabledSysPackages.get(name); + if((ps != null) && ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) { + // Could be a replaced system package + // Note that if the user replaced a system app, the user has to physically + // delete the new one in order to revert to the system app. So even + // if the user updated the system app via an update, the user still + // has to delete the one installed in the data partition in order to pick up the + // new system package. + return p; + } else { + reportSettingsProblem(Log.WARN, + "Package " + name + " codePath changed from " + p.codePath + + " to " + codePath + "; replacing with new"); + p = null; + } } else if (p.sharedUser != sharedUser) { reportSettingsProblem(Log.WARN, "Package " + name + " shared user changed from " @@ -4896,10 +5381,13 @@ class PackageManagerService extends IPackageManager.Stub { } } if (p == null) { + // Create a new PackageSettings entry. this can end up here because + // of code path mismatch or user id mismatch of an updated system partition if (!create) { return null; } p = new PackageSetting(name, codePath, resourcePath, pkgFlags); + p.setTimeStamp(codePath.lastModified()); if (sharedUser != null) { p.userId = sharedUser.userId; } else if (MULTIPLE_APPLICATION_UIDS) { @@ -4935,10 +5423,45 @@ class PackageManagerService extends IPackageManager.Stub { p.sharedUser = sharedUser; p.userId = sharedUser.userId; } - return p; } + private void updateSharedUserPerms (PackageSetting deletedPs) { + if ( (deletedPs == null) || (deletedPs.pkg == null)) { + Log.i(TAG, "Trying to update info for null package. Just ignoring"); + return; + } + // No sharedUserId + if (deletedPs.sharedUser == null) { + return; + } + SharedUserSetting sus = deletedPs.sharedUser; + // Update permissions + for (String eachPerm: deletedPs.pkg.requestedPermissions) { + boolean used = false; + if (!sus.grantedPermissions.contains (eachPerm)) { + continue; + } + for (PackageSetting pkg:sus.packages) { + if (pkg.grantedPermissions.contains (eachPerm)) { + used = true; + break; + } + } + if (!used) { + // can safely delete this permission from list + sus.grantedPermissions.remove(eachPerm); + sus.loadedPermissions.remove(eachPerm); + } + } + // Update gids + int newGids[] = null; + for (PackageSetting pkg:sus.packages) { + newGids = appendInts(newGids, pkg.gids); + } + sus.gids = newGids; + } + private int removePackageLP(String name) { PackageSetting p = mPackages.get(name); if (p != null) { @@ -5047,16 +5570,17 @@ class PackageManagerService extends IPackageManager.Stub { serializer.endTag(null, "permissions"); for (PackageSetting pkg : mPackages.values()) { - serializer.startTag(null, "package"); + writePackage(serializer, pkg); + } + + for (PackageSetting pkg : mDisabledSysPackages.values()) { + serializer.startTag(null, "updated-package"); serializer.attribute(null, "name", pkg.name); serializer.attribute(null, "codePath", pkg.codePathString); + serializer.attribute(null, "ts", pkg.getTimeStampStr()); if (!pkg.resourcePathString.equals(pkg.codePathString)) { serializer.attribute(null, "resourcePath", pkg.resourcePathString); } - serializer.attribute(null, "system", - (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 - ? "true" : "false"); - serializer.attribute(null, "ts", pkg.timeStampString); if (pkg.sharedUser == null) { serializer.attribute(null, "userId", Integer.toString(pkg.userId)); @@ -5064,50 +5588,9 @@ class PackageManagerService extends IPackageManager.Stub { serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId)); } - if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { - serializer.attribute(null, "enabled", - pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED - ? "true" : "false"); - } - if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) { - serializer.attribute(null, "installStatus", "false"); - } - pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); - if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { - serializer.startTag(null, "perms"); - if (pkg.sharedUser == null) { - // If this is a shared user, the permissions will - // be written there. We still need to write an - // empty permissions list so permissionsFixed will - // be set. - for (String name : pkg.grantedPermissions) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - } - serializer.endTag(null, "perms"); - } - if (pkg.disabledComponents.size() > 0) { - serializer.startTag(null, "disabled-components"); - for (String name : pkg.disabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "disabled-components"); - } - if (pkg.enabledComponents.size() > 0) { - serializer.startTag(null, "enabled-components"); - for (String name : pkg.enabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "enabled-components"); - } - serializer.endTag(null, "package"); + serializer.endTag(null, "updated-package"); } + serializer.startTag(null, "preferred-packages"); int N = mPreferredPackages.size(); @@ -5169,7 +5652,71 @@ class PackageManagerService extends IPackageManager.Stub { //Debug.stopMethodTracing(); } - + + void writePackage(XmlSerializer serializer, final PackageSetting pkg) + throws java.io.IOException { + serializer.startTag(null, "package"); + serializer.attribute(null, "name", pkg.name); + serializer.attribute(null, "codePath", pkg.codePathString); + if (!pkg.resourcePathString.equals(pkg.codePathString)) { + serializer.attribute(null, "resourcePath", pkg.resourcePathString); + } + serializer.attribute(null, "system", + (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 + ? "true" : "false"); + serializer.attribute(null, "ts", pkg.getTimeStampStr()); + if (pkg.sharedUser == null) { + serializer.attribute(null, "userId", + Integer.toString(pkg.userId)); + } else { + serializer.attribute(null, "sharedUserId", + Integer.toString(pkg.userId)); + } + if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { + serializer.attribute(null, "enabled", + pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED + ? "true" : "false"); + } + if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) { + serializer.attribute(null, "installStatus", "false"); + } + pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); + if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { + serializer.startTag(null, "perms"); + if (pkg.sharedUser == null) { + // If this is a shared user, the permissions will + // be written there. We still need to write an + // empty permissions list so permissionsFixed will + // be set. + for (final String name : pkg.grantedPermissions) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + } + serializer.endTag(null, "perms"); + } + if (pkg.disabledComponents.size() > 0) { + serializer.startTag(null, "disabled-components"); + for (final String name : pkg.disabledComponents) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + serializer.endTag(null, "disabled-components"); + } + if (pkg.enabledComponents.size() > 0) { + serializer.startTag(null, "enabled-components"); + for (final String name : pkg.enabledComponents) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + serializer.endTag(null, "enabled-components"); + } + serializer.endTag(null, "package"); + } + void writePermission(XmlSerializer serializer, BasePermission bp) throws XmlPullParserException, java.io.IOException { if (bp.type != BasePermission.TYPE_BUILTIN @@ -5281,6 +5828,34 @@ class PackageManagerService extends IPackageManager.Stub { readPreferredPackagesLP(parser); } else if (tagName.equals("preferred-activities")) { readPreferredActivitiesLP(parser); + } else if(tagName.equals("updated-package")) { + String name = parser.getAttributeValue(null, "name"); + String codePathStr = parser.getAttributeValue(null, "codePath"); + String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); + if(resourcePathStr == null) { + resourcePathStr = codePathStr; + } + + int pkgFlags = 0; + pkgFlags |= ApplicationInfo.FLAG_SYSTEM; + PackageSetting ps = new PackageSetting(name, + new File(codePathStr), + new File(resourcePathStr), pkgFlags); + String timeStampStr = parser.getAttributeValue(null, "ts"); + if (timeStampStr != null) { + try { + long timeStamp = Long.parseLong(timeStampStr); + ps.setTimeStamp(timeStamp, timeStampStr); + } catch (NumberFormatException e) { + } + } + String idStr = parser.getAttributeValue(null, "userId"); + ps.userId = idStr != null ? Integer.parseInt(idStr) : 0; + if(ps.userId <= 0) { + String sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); + ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; + } + mDisabledSysPackages.put(name, ps); } else { Log.w(TAG, "Unknown element under <packages>: " + parser.getName()); @@ -5811,6 +6386,13 @@ class PackageManagerService extends IPackageManager.Stub { mUserIds.add(obj); return FIRST_APPLICATION_UID + N; } + + public PackageSetting getDisabledSystemPkg(String name) { + synchronized(mPackages) { + PackageSetting ps = mDisabledSysPackages.get(name); + return ps; + } + } boolean isEnabledLP(ComponentInfo componentInfo, int flags) { final PackageSetting packageSettings = mPackages.get(componentInfo.packageName); |