diff options
9 files changed, 366 insertions, 100 deletions
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index c003355..0964425 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -151,7 +151,7 @@ public class PackageInfo implements Parcelable { */ public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2; /** - * The launch mode style requested by the activity. From the + * The install location requested by the activity. From the * {@link android.R.attr#installLocation} attribute, one of * {@link #INSTALL_LOCATION_AUTO}, * {@link #INSTALL_LOCATION_INTERNAL_ONLY}, diff --git a/core/java/android/content/pm/PackageInfoLite.aidl b/core/java/android/content/pm/PackageInfoLite.aidl new file mode 100755 index 0000000..2c80942 --- /dev/null +++ b/core/java/android/content/pm/PackageInfoLite.aidl @@ -0,0 +1,20 @@ +/* //device/java/android/android/view/WindowManager.aidl +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm; + +parcelable PackageInfoLite; diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java new file mode 100644 index 0000000..2f38ece --- /dev/null +++ b/core/java/android/content/pm/PackageInfoLite.java @@ -0,0 +1,63 @@ +package android.content.pm; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Basic information about a package as specified in its manifest. + * Utility class used in PackageManager methods + * @hide + */ +public class PackageInfoLite implements Parcelable { + /** + * The name of this package. From the <manifest> tag's "name" + * attribute. + */ + public String packageName; + + /** + * Specifies the recommended install location. Can be one of + * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage + * {@link #PackageHelper.RECOMMEND_INSTALL_EXTERNAL} to install on external media + * {@link PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE} for storage errors + * {@link PackageHelper.RECOMMEND_FAILED_INVALID_APK} for parse errors. + */ + public int recommendedInstallLocation; + public int installLocation; + + public PackageInfoLite() { + } + + public String toString() { + return "PackageInfoLite{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + packageName + "}"; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int parcelableFlags) { + dest.writeString(packageName); + dest.writeInt(recommendedInstallLocation); + dest.writeInt(installLocation); + } + + public static final Parcelable.Creator<PackageInfoLite> CREATOR + = new Parcelable.Creator<PackageInfoLite>() { + public PackageInfoLite createFromParcel(Parcel source) { + return new PackageInfoLite(source); + } + + public PackageInfoLite[] newArray(int size) { + return new PackageInfoLite[size]; + } + }; + + private PackageInfoLite(Parcel source) { + packageName = source.readString(); + recommendedInstallLocation = source.readInt(); + installLocation = source.readInt(); + } +}
\ No newline at end of file diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 7a0337cd..5da7fd1 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -136,7 +136,20 @@ public class PackageParser { enabledRes = _enabledRes; } } - + + /* Light weight package info. + * @hide + */ + public static class PackageLite { + public String packageName; + public int installLocation; + public String mScanPath; + public PackageLite(String packageName, int installLocation) { + this.packageName = packageName; + this.installLocation = installLocation; + } + } + private ParsePackageItemArgs mParseInstrumentationArgs; private ParseComponentArgs mParseActivityArgs; private ParseComponentArgs mParseActivityAliasArgs; @@ -562,7 +575,14 @@ public class PackageParser { return true; } - public static String parsePackageName(String packageFilePath, int flags) { + /* + * Utility method that retrieves just the package name and install + * location from the apk location at the given file path. + * @param packageFilePath file location of the apk + * @param flags Special parse flags + * @return PackageLite object with package information. + */ + public static PackageLite parsePackageLite(String packageFilePath, int flags) { XmlResourceParser parser = null; AssetManager assmgr = null; try { @@ -577,9 +597,9 @@ public class PackageParser { } AttributeSet attrs = parser; String errors[] = new String[1]; - String packageName = null; + PackageLite packageLite = null; try { - packageName = parsePackageName(parser, attrs, flags, errors); + packageLite = parsePackageLite(parser, attrs, flags, errors); } catch (IOException e) { Log.w(TAG, packageFilePath, e); } catch (XmlPullParserException e) { @@ -588,11 +608,11 @@ public class PackageParser { if (parser != null) parser.close(); if (assmgr != null) assmgr.close(); } - if (packageName == null) { - Log.e(TAG, "parsePackageName error: " + errors[0]); + if (packageLite == null) { + Log.e(TAG, "parsePackageLite error: " + errors[0]); return null; } - return packageName; + return packageLite; } private static String validateName(String name, boolean requiresSeparator) { @@ -656,6 +676,49 @@ public class PackageParser { return pkgName.intern(); } + private static PackageLite parsePackageLite(XmlPullParser parser, + AttributeSet attrs, int flags, String[] outError) + throws IOException, XmlPullParserException { + + int type; + while ((type=parser.next()) != parser.START_TAG + && type != parser.END_DOCUMENT) { + ; + } + + if (type != parser.START_TAG) { + outError[0] = "No start tag found"; + return null; + } + if ((flags&PARSE_CHATTY) != 0 && Config.LOGV) Log.v( + TAG, "Root element name: '" + parser.getName() + "'"); + if (!parser.getName().equals("manifest")) { + outError[0] = "No <manifest> tag"; + return null; + } + String pkgName = attrs.getAttributeValue(null, "package"); + if (pkgName == null || pkgName.length() == 0) { + outError[0] = "<manifest> does not specify package"; + return null; + } + String nameError = validateName(pkgName, true); + if (nameError != null && !"android".equals(pkgName)) { + outError[0] = "<manifest> specifies bad package name \"" + + pkgName + "\": " + nameError; + return null; + } + int installLocation = PackageInfo.INSTALL_LOCATION_AUTO; + for (int i = 0; i < attrs.getAttributeCount(); i++) { + String attr = attrs.getAttributeName(i); + if (attr.equals("installLocation")) { + installLocation = attrs.getAttributeIntValue(i, + PackageInfo.INSTALL_LOCATION_AUTO); + break; + } + } + return new PackageLite(pkgName.intern(), installLocation); + } + /** * Temporary. */ diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl index c0e9587..fd1fd58 100755 --- a/core/java/com/android/internal/app/IMediaContainerService.aidl +++ b/core/java/com/android/internal/app/IMediaContainerService.aidl @@ -18,6 +18,7 @@ package com.android.internal.app; import android.net.Uri; import android.os.ParcelFileDescriptor; +import android.content.pm.PackageInfoLite; interface IMediaContainerService { String copyResourceToContainer(in Uri packageURI, @@ -25,5 +26,5 @@ interface IMediaContainerService { String key, String resFileName); boolean copyResource(in Uri packageURI, in ParcelFileDescriptor outStream); - int getRecommendedInstallLocation(in Uri fileUri); + PackageInfoLite getMinimalPackageInfo(in Uri fileUri); }
\ No newline at end of file diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index 04a10b9..de6a175 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -36,6 +36,8 @@ public class PackageHelper { public static final int RECOMMEND_INSTALL_EXTERNAL = 2; public static final int RECOMMEND_FAILED_INSUFFICIENT_STORAGE = -1; public static final int RECOMMEND_FAILED_INVALID_APK = -2; + public static final int RECOMMEND_FAILED_INVALID_LOCATION = -3; + public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4; private static final boolean localLOGV = true; private static final String TAG = "PackageHelper"; diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index 02e1f07..4635f48 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -5,6 +5,7 @@ import com.android.internal.content.PackageHelper; import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; +import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.Package; @@ -28,6 +29,7 @@ import java.io.IOException; import java.io.InputStream; import android.os.FileUtils; +import android.os.storage.IMountService; import android.provider.Settings; /* @@ -86,46 +88,51 @@ public class DefaultContainerService extends IntentService { * specified by file uri location. * @param fileUri the uri of resource to be copied. Should be a * file uri - * @return Returns - * PackageHelper.RECOMMEND_INSTALL_INTERNAL to install on internal storage - * PackageHelper.RECOMMEND_INSTALL_EXTERNAL to install on external media - * PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE for storage errors - * PackageHelper.RECOMMEND_FAILED_INVALID_APK for parse errors. + * @return Returns PackageInfoLite object containing + * the package info and recommended app location. */ - public int getRecommendedInstallLocation(final Uri fileUri) { + public PackageInfoLite getMinimalPackageInfo(final Uri fileUri) { + PackageInfoLite ret = new PackageInfoLite(); if (fileUri == null) { Log.i(TAG, "Invalid package uri " + fileUri); - return PackageHelper.RECOMMEND_FAILED_INVALID_APK; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; + return ret; } String scheme = fileUri.getScheme(); if (scheme != null && !scheme.equals("file")) { Log.w(TAG, "Falling back to installing on internal storage only"); - return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL; + return ret; } String archiveFilePath = fileUri.getPath(); PackageParser packageParser = new PackageParser(archiveFilePath); File sourceFile = new File(archiveFilePath); DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); - PackageParser.Package pkg = packageParser.parsePackage(sourceFile, - archiveFilePath, metrics, 0); + PackageParser.PackageLite pkg = packageParser.parsePackageLite( + archiveFilePath, 0); + ret.packageName = pkg.packageName; + ret.installLocation = pkg.installLocation; // Nuke the parser reference right away and force a gc Runtime.getRuntime().gc(); packageParser = null; if (pkg == null) { Log.w(TAG, "Failed to parse package"); - return PackageHelper.RECOMMEND_FAILED_INVALID_APK; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; + return ret; } - int loc = recommendAppInstallLocation(pkg); + ret.packageName = pkg.packageName; + int loc = recommendAppInstallLocation(pkg.installLocation, archiveFilePath); if (loc == PackageManager.INSTALL_EXTERNAL) { - return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } else if (loc == ERR_LOC) { Log.i(TAG, "Failed to install insufficient storage"); - return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } else { // Implies install on internal storage. - return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL; } + return ret; } }; @@ -171,62 +178,37 @@ public class DefaultContainerService extends IntentService { String codePath = packageURI.getPath(); File codeFile = new File(codePath); String newCachePath = null; - final int CREATE_FAILED = 1; - final int COPY_FAILED = 2; - final int FINALIZE_FAILED = 3; - final int PASS = 4; - int errCode = CREATE_FAILED; // Create new container if ((newCachePath = PackageHelper.createSdDir(codeFile, - newCid, key, Process.myUid())) != null) { - if (localLOGV) Log.i(TAG, "Created container for " + newCid - + " at path : " + newCachePath); - File resFile = new File(newCachePath, resFileName); - errCode = COPY_FAILED; - // Copy file from codePath - if (FileUtils.copyFile(new File(codePath), resFile)) { - if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile); - errCode = FINALIZE_FAILED; - if (PackageHelper.finalizeSdDir(newCid)) { - if (localLOGV) Log.i(TAG, "Finalized container " + newCid); - errCode = PASS; - } - } - } - // Print error based on errCode - String errMsg = ""; - switch (errCode) { - case CREATE_FAILED: - errMsg = "CREATE_FAILED"; - break; - case COPY_FAILED: - errMsg = "COPY_FAILED"; - if (localLOGV) Log.i(TAG, "Destroying " + newCid + - " at path " + newCachePath + " after " + errMsg); - PackageHelper.destroySdDir(newCid); - break; - case FINALIZE_FAILED: - errMsg = "FINALIZE_FAILED"; - if (localLOGV) Log.i(TAG, "Destroying " + newCid + - " at path " + newCachePath + " after " + errMsg); - PackageHelper.destroySdDir(newCid); - break; - default: - errMsg = "PASS"; - if (PackageHelper.isContainerMounted(newCid)) { - if (localLOGV) Log.i(TAG, "Unmounting " + newCid + - " at path " + newCachePath + " after " + errMsg); - // Force a gc to avoid being killed. - Runtime.getRuntime().gc(); - PackageHelper.unMountSdDir(newCid); - } else { - if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted"); - } - break; + newCid, key, Process.myUid())) == null) { + Log.e(TAG, "Failed to create container " + newCid); + return null; } - if (errCode != PASS) { + if (localLOGV) Log.i(TAG, "Created container for " + newCid + + " at path : " + newCachePath); + File resFile = new File(newCachePath, resFileName); + if (!FileUtils.copyFile(new File(codePath), resFile)) { + Log.e(TAG, "Failed to copy " + codePath + " to " + resFile); + // Clean up container + PackageHelper.destroySdDir(newCid); return null; } + if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile); + if (!PackageHelper.finalizeSdDir(newCid)) { + Log.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath); + // Clean up container + PackageHelper.destroySdDir(newCid); + } + if (localLOGV) Log.i(TAG, "Finalized container " + newCid); + if (PackageHelper.isContainerMounted(newCid)) { + if (localLOGV) Log.i(TAG, "Unmounting " + newCid + + " at path " + newCachePath); + // Force a gc to avoid being killed. + Runtime.getRuntime().gc(); + PackageHelper.unMountSdDir(newCid); + } else { + if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted"); + } return newCachePath; } @@ -307,29 +289,28 @@ public class DefaultContainerService extends IntentService { private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); private static final int ERR_LOC = -1; - public int recommendAppInstallLocation(Package pkg) { + private int recommendAppInstallLocation(int installLocation, + String archiveFilePath) { // Initial implementation: // Package size = code size + cache size + data size // If code size > 1 MB, install on SD card. // Else install on internal NAND flash, unless space on NAND is less than 10% - - if (pkg == null) { - return ERR_LOC; + String status = Environment.getExternalStorageState(); + long availSDSize = -1; + if (status.equals(Environment.MEDIA_MOUNTED)) { + StatFs sdStats = new StatFs( + Environment.getExternalStorageDirectory().getPath()); + availSDSize = (long)sdStats.getAvailableBlocks() * + (long)sdStats.getBlockSize(); } + StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath()); + long totalInternalSize = (long)internalStats.getBlockCount() * + (long)internalStats.getBlockSize(); + long availInternalSize = (long)internalStats.getAvailableBlocks() * + (long)internalStats.getBlockSize(); - StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath()); - StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath()); - - long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() * - (long)internalFlashStats.getBlockSize(); - long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() * - (long)internalFlashStats.getBlockSize(); - long availSDSize = (long)sdcardStats.getAvailableBlocks() * - (long)sdcardStats.getBlockSize(); - - double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize; + double pctNandFree = (double)availInternalSize / (double)totalInternalSize; - final String archiveFilePath = pkg.mScanPath; File apkFile = new File(archiveFilePath); long pkgLen = apkFile.length(); @@ -339,15 +320,15 @@ public class DefaultContainerService extends IntentService { // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now. long reqInternalSize = 0; boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); - boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize); + boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize); boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk && - (reqInternalSize < availInternalFlashSize); + (reqInternalSize < availInternalSize); boolean fitsOnInt = intThresholdOk && intAvailOk; // Consider application flags preferences as well... - boolean installOnlyOnSd = (pkg.installLocation == + boolean installOnlyOnSd = (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - boolean installOnlyInternal = (pkg.installLocation == + boolean installOnlyInternal = (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); if (installOnlyInternal) { // If set explicitly in manifest, diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 1ff0244..371fa37 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -51,6 +51,7 @@ import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageStats; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; @@ -78,12 +79,14 @@ import android.os.Environment; import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; +import android.os.StatFs; import android.os.storage.StorageResultCode; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; +import android.provider.Settings; import android.security.SystemKeyStore; import android.util.*; import android.view.Display; @@ -4568,21 +4571,79 @@ class PackageManagerService extends IPackageManager.Stub { this.installerPackageName = installerPackageName; } + private int installLocationPolicy(PackageInfoLite pkgLite, int flags) { + String packageName = pkgLite.packageName; + int installLocation = pkgLite.installLocation; + boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0; + synchronized (mPackages) { + PackageParser.Package pkg = mPackages.get(packageName); + if (pkg != null) { + if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { + // Check for updated system application. + if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + if (onSd) { + Log.w(TAG, "Cannot install update to system app on sdcard"); + return PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION; + } + return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + } else { + // When replacing apps make sure we honour + // the existing app location if not overwritten by other options + boolean prevOnSd = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0; + if (onSd) { + // Install flag overrides everything. + return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; + } + // If current upgrade does not specify install location. + if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { + // Application explicitly specified internal. + return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) { + // App explictly prefers external. Let policy decide + } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) { + // Prefer previous location + return prevOnSd ? PackageHelper.RECOMMEND_INSTALL_EXTERNAL: + PackageHelper.RECOMMEND_INSTALL_INTERNAL; + } + } + } else { + // Invalid install. Return error code + return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS; + } + } + } + // All the special cases have been taken care of. + // Return result based on recommended install location. + if (onSd) { + return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; + } + return pkgLite.recommendedInstallLocation; + } + public void handleStartCopy() throws RemoteException { int ret = PackageManager.INSTALL_SUCCEEDED; + boolean fwdLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0; + boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0; // Dont need to invoke getInstallLocation for forward locked apps. - if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) { - flags &= ~PackageManager.INSTALL_EXTERNAL; + if (fwdLocked && onSd) { + Log.w(TAG, "Cannot install fwd locked apps on sdcard"); + ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { // Remote call to find out default install location - int loc = mContainerService.getRecommendedInstallLocation(packageURI); + PackageInfoLite pkgLite = mContainerService.getMinimalPackageInfo(packageURI); + int loc = installLocationPolicy(pkgLite, flags); // Use install location to create InstallArgs and temporary // install location - if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){ + if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION){ + ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; + } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS){ + ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; + } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){ ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) { ret = PackageManager.INSTALL_FAILED_INVALID_APK; } else { + // Override install location with flags if ((flags & PackageManager.INSTALL_EXTERNAL) == 0){ if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { // Set the flag to install on external media. diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java index 50eca02..0b69020 100755 --- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java @@ -932,11 +932,86 @@ public class PackageManagerTests extends AndroidTestCase { 0, true, false, -1, PackageInfo.INSTALL_LOCATION_AUTO); } + public void testManifestInstallLocationFwdLockedFlagSdcard() { + installFromRawResource("install.apk", R.raw.install_loc_unspecified, + PackageManager.INSTALL_FORWARD_LOCK | + PackageManager.INSTALL_EXTERNAL, true, true, + PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION, + PackageInfo.INSTALL_LOCATION_AUTO); + } + public void testManifestInstallLocationFwdLockedSdcard() { installFromRawResource("install.apk", R.raw.install_loc_sdcard, PackageManager.INSTALL_FORWARD_LOCK, true, false, -1, - PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + + private void replaceManifestLocation(int iFlags, int rFlags) { + InstallParams ip = sampleInstallFromRawResource(iFlags, false); + GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName); + int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING; + try { + assertEquals(invokeInstallPackage(ip.packageURI, replaceFlags, + ip.pkg.packageName, receiver), true); + assertInstall(ip.pkg, replaceFlags, ip.pkg.installLocation); + } catch (Exception e) { + failStr("Failed with exception : " + e); + } finally { + cleanUpInstall(ip); + } + } + + public void testReplaceFlagInternalSdcard() { + replaceManifestLocation(0, PackageManager.INSTALL_EXTERNAL); + } + + public void testReplaceFlagSdcardInternal() { + replaceManifestLocation(PackageManager.INSTALL_EXTERNAL, 0); + } + + public void testManifestInstallLocationReplaceInternalSdcard() { + int iFlags = 0; + int iApk = R.raw.install_loc_unspecified; + int rFlags = 0; + int rApk = R.raw.install_loc_sdcard; + InstallParams ip = installFromRawResource("install.apk", iApk, + iFlags, false, + false, -1, PackageInfo.INSTALL_LOCATION_AUTO); + GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName); + int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING; + try { + InstallParams rp = installFromRawResource("install.apk", rApk, + rFlags, false, + false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + assertInstall(rp.pkg, replaceFlags, rp.pkg.installLocation); + } catch (Exception e) { + failStr("Failed with exception : " + e); + } finally { + cleanUpInstall(ip); + } + } + + public void testManifestInstallLocationReplaceSdcardInternal() { + int iFlags = 0; + int iApk = R.raw.install_loc_sdcard; + int rFlags = 0; + int rApk = R.raw.install_loc_unspecified; + InstallParams ip = installFromRawResource("install.apk", iApk, + iFlags, false, + false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName); + int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING; + try { + InstallParams rp = installFromRawResource("install.apk", rApk, + rFlags, false, + false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + assertInstall(rp.pkg, replaceFlags, ip.pkg.installLocation); + } catch (Exception e) { + failStr("Failed with exception : " + e); + } finally { + cleanUpInstall(ip); + } } public void xxxtestClearAllSecureContainers() { |