diff options
10 files changed, 369 insertions, 367 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 68373cb..ff16c6e 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -600,7 +600,7 @@ public final class Pm { } else if (opt.equals("-t")) { installFlags |= PackageManager.INSTALL_ALLOW_TEST; } else if (opt.equals("-s")) { - installFlags |= PackageManager.INSTALL_ON_SDCARD; + installFlags |= PackageManager.INSTALL_EXTERNAL; } else { System.err.println("Error: Unknown option: " + opt); showUsage(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index b4fe698..db6a4bf 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2659,102 +2659,6 @@ class ContextImpl extends Context { return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; } - // Constants related to app heuristics - // No-installation limit for internal flash: 10% or less space available - private static final double LOW_NAND_FLASH_TRESHOLD = 0.1; - - // SD-to-internal app size threshold: currently set to 1 MB - private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); - - public int recommendAppInstallLocation(Package pkg) { - // 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 INSTALL_PARSE_FAILED_NOT_APK; - } - - 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; - - final String archiveFilePath = pkg.mScanPath; - File apkFile = new File(archiveFilePath); - long pkgLen = apkFile.length(); - - boolean auto = true; - // To make final copy - long reqInstallSize = pkgLen; - // For dex files - long reqInternalSize = 1 * pkgLen; - boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); - boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize); - boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk && - (reqInternalSize < availInternalFlashSize); - boolean fitsOnInt = intThresholdOk && intAvailOk; - - // Consider application flags preferences as well... - boolean installOnlyOnSd = (pkg.installLocation == - PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - boolean installOnlyInternal = (pkg.installLocation == - PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); - if (installOnlyInternal) { - // If set explicitly in manifest, - // let that override everything else - auto = false; - } else if (installOnlyOnSd){ - // Check if this can be accommodated on the sdcard - if (fitsOnSd) { - auto = false; - } - } else { - // Check if user option is enabled - boolean setInstallLoc = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, 0) != 0; - if (setInstallLoc) { - // Pick user preference - int installPreference = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.DEFAULT_INSTALL_LOCATION, - PackageInfo.INSTALL_LOCATION_AUTO); - if (installPreference == 1) { - installOnlyInternal = true; - auto = false; - } else if (installPreference == 2) { - installOnlyOnSd = true; - auto = false; - } - } - } - if (!auto) { - if (installOnlyOnSd) { - return fitsOnSd ? INSTALL_ON_SDCARD : INSTALL_FAILED_INSUFFICIENT_STORAGE; - } else if (installOnlyInternal){ - // Check on internal flash - return fitsOnInt ? INSTALL_ON_INTERNAL_FLASH : INSTALL_FAILED_INSUFFICIENT_STORAGE; - } - } - // Try to install internally - if (fitsOnInt) { - return INSTALL_ON_INTERNAL_FLASH; - } - // Try the sdcard now. - if (fitsOnSd) { - return INSTALL_ON_SDCARD; - } - // Return error code - return INSTALL_FAILED_INSUFFICIENT_STORAGE; - } - private final ContextImpl mContext; private final IPackageManager mPM; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 17bee48..ff2ed3d 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -258,14 +258,7 @@ public abstract class PackageManager { * package has to be installed on the sdcard. * @hide */ - public static final int INSTALL_ON_SDCARD = 0x00000008; - - /** - * Convenience flag parameter to indicate that this package has to be installed - * on internal flash. - * @hide - */ - public static final int INSTALL_ON_INTERNAL_FLASH = 0x00000000; + public static final int INSTALL_EXTERNAL = 0x00000008; /** * Flag parameter for @@ -529,6 +522,14 @@ public abstract class PackageManager { public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109; /** + * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} + * if the system failed to install the package because of system issues. + * @hide + */ + public static final int INSTALL_FAILED_INTERNAL_ERROR = -110; + + /** * Indicates the state of installation. Used by PackageManager to * figure out incomplete installations. Say a package is being installed * (the state is set to PKG_INSTALL_INCOMPLETE) and remains so till @@ -627,23 +628,6 @@ public abstract class PackageManager { */ public static final String ACTION_CLEAN_EXTERNAL_STORAGE = "android.content.pm.CLEAN_EXTERNAL_STORAGE"; - - /** - * Determines best place to install an application: either SD or internal FLASH. - * If applications explicitly set installLocation in their manifest, that - * preference takes precedence. If not a recommended location is returned - * based on current available storage on internal flash or sdcard. - * @param pkgInfo PackageParser.Package of the package that is to be installed. - * Call utility method to obtain. - * @return {@link INSTALL_ON_INTERNAL_FLASH} if it is best to install package on internal - * storage, {@link INSTALL_ON_SDCARD} if it is best to install package on SD card, - * and {@link INSTALL_FAILED_INSUFFICIENT_STORAGE} if insufficient space to safely install - * the application. {@link INSTALL_PARSE_FAILED_NOT_APK} Is returned if any input - * parameter is <code>null</code>. - * This recommendation does take into account the package's own flags. - * @hide - */ - public abstract int recommendAppInstallLocation(PackageParser.Package pkg); /** * Retrieve overall information about an application package that is diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl index 726e28f..c0e9587 100755 --- a/core/java/com/android/internal/app/IMediaContainerService.aidl +++ b/core/java/com/android/internal/app/IMediaContainerService.aidl @@ -25,4 +25,5 @@ interface IMediaContainerService { String key, String resFileName); boolean copyResource(in Uri packageURI, in ParcelFileDescriptor outStream); + int getRecommendedInstallLocation(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 new file mode 100644 index 0000000..4d7d2d1 --- /dev/null +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2009 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 com.android.internal.content; + +/** + * Constants used internally between the PackageManager + * and media container service transports. + */ +public class PackageHelper { + public static final int RECOMMEND_INSTALL_INTERNAL = 1; + 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; +} diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml index 5ec72df..078daa7 100755 --- a/packages/DefaultContainerService/AndroidManifest.xml +++ b/packages/DefaultContainerService/AndroidManifest.xml @@ -6,6 +6,7 @@ <uses-permission android:name="android.permission.ASEC_DESTROY"/> <uses-permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" /> <application android:label="@string/service_name"> diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index c418ccb..8e030e5 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -1,10 +1,13 @@ package com.android.defcontainer; import com.android.internal.app.IMediaContainerService; - +import com.android.internal.content.PackageHelper; import android.content.Intent; import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.Package; import android.net.Uri; import android.os.Debug; import android.os.Environment; @@ -15,8 +18,10 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.StatFs; import android.app.IntentService; import android.app.Service; +import android.util.DisplayMetrics; import android.util.Log; import java.io.File; @@ -28,6 +33,7 @@ import java.io.InputStream; import java.io.OutputStream; import android.os.FileUtils; +import android.provider.Settings; /* * This service copies a downloaded apk to a file passed in as @@ -79,6 +85,44 @@ public class DefaultContainerService extends IntentService { autoOut = new ParcelFileDescriptor.AutoCloseOutputStream(outStream); return copyFile(packageURI, autoOut); } + + /* + * Determine the recommended install location for package + * 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. + */ + public int getRecommendedInstallLocation(final Uri fileUri) { + if (!fileUri.getScheme().equals("file")) { + Log.w(TAG, "Falling back to installing on internal storage only"); + return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + } + final 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); + if (pkg == null) { + Log.w(TAG, "Failed to parse package"); + return PackageHelper.RECOMMEND_FAILED_INVALID_APK; + } + int loc = recommendAppInstallLocation(pkg); + if (loc == PackageManager.INSTALL_EXTERNAL) { + return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; + } else if (loc == ERR_LOC) { + Log.i(TAG, "Failed to install insufficient storage"); + return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; + } else { + // Implies install on internal storage. + return 0; + } + } }; public DefaultContainerService() { @@ -111,7 +155,6 @@ public class DefaultContainerService extends IntentService { } } } - //Log.i(TAG, "Deleting: " + path); path.delete(); } @@ -341,4 +384,104 @@ public class DefaultContainerService extends IntentService { } return true; } + + // Constants related to app heuristics + // No-installation limit for internal flash: 10% or less space available + private static final double LOW_NAND_FLASH_TRESHOLD = 0.1; + + // SD-to-internal app size threshold: currently set to 1 MB + private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); + private static final int ERR_LOC = -1; + + public int recommendAppInstallLocation(Package pkg) { + // 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; + } + + 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; + + final String archiveFilePath = pkg.mScanPath; + File apkFile = new File(archiveFilePath); + long pkgLen = apkFile.length(); + + boolean auto = true; + // To make final copy + long reqInstallSize = pkgLen; + // For dex files + long reqInternalSize = 1 * pkgLen; + boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); + boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize); + boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk && + (reqInternalSize < availInternalFlashSize); + boolean fitsOnInt = intThresholdOk && intAvailOk; + + // Consider application flags preferences as well... + boolean installOnlyOnSd = (pkg.installLocation == + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + boolean installOnlyInternal = (pkg.installLocation == + PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + if (installOnlyInternal) { + // If set explicitly in manifest, + // let that override everything else + auto = false; + } else if (installOnlyOnSd){ + // Check if this can be accommodated on the sdcard + if (fitsOnSd) { + auto = false; + } + } else { + // Check if user option is enabled + boolean setInstallLoc = Settings.System.getInt(getApplicationContext() + .getContentResolver(), + Settings.System.SET_INSTALL_LOCATION, 0) != 0; + if (setInstallLoc) { + // Pick user preference + int installPreference = Settings.System.getInt(getApplicationContext() + .getContentResolver(), + Settings.System.DEFAULT_INSTALL_LOCATION, + PackageInfo.INSTALL_LOCATION_AUTO); + if (installPreference == 1) { + installOnlyInternal = true; + auto = false; + } else if (installPreference == 2) { + installOnlyOnSd = true; + auto = false; + } + } + } + if (!auto) { + if (installOnlyOnSd) { + return fitsOnSd ? PackageManager.INSTALL_EXTERNAL : ERR_LOC; + } else if (installOnlyInternal){ + // Check on internal flash + return fitsOnInt ? 0 : ERR_LOC; + } + } + // Try to install internally + if (fitsOnInt) { + return 0; + } + // Try the sdcard now. + if (fitsOnSd) { + return PackageManager.INSTALL_EXTERNAL; + } + // Return error code + return ERR_LOC; + } + } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index a5213a0..812ff64 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -20,6 +20,7 @@ import com.android.internal.app.IMediaContainerService; import com.android.internal.app.ResolverActivity; import com.android.common.FastXmlSerializer; import com.android.common.XmlUtils; +import com.android.internal.content.PackageHelper; import com.android.server.JournaledFile; import org.xmlpull.v1.XmlPullParser; @@ -304,6 +305,7 @@ class PackageManagerService extends IPackageManager.Stub { static final int INIT_COPY = 5; static final int MCS_UNBIND = 6; static final int START_CLEANING_PACKAGE = 7; + static final int FIND_INSTALL_LOC = 8; // Delay time in millisecs static final int BROADCAST_DELAY = 10 * 1000; private ServiceConnection mDefContainerConn = new ServiceConnection() { @@ -319,8 +321,8 @@ class PackageManagerService extends IPackageManager.Stub { }; class PackageHandler extends Handler { - final ArrayList<InstallArgs> mPendingInstalls = - new ArrayList<InstallArgs>(); + final ArrayList<InstallParams> mPendingInstalls = + new ArrayList<InstallParams>(); // Service Connection to remote media container service to copy // package uri's from external media onto secure containers // or internal storage. @@ -332,21 +334,20 @@ class PackageManagerService extends IPackageManager.Stub { public void handleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { - InstallArgs args = (InstallArgs) msg.obj; - args.createCopyFile(); + InstallParams params = (InstallParams) msg.obj; Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); if (mContainerService != null) { // No need to add to pending list. Use remote stub directly - handleStartCopy(args); + handleStartCopy(params); } else { if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) { - mPendingInstalls.add(args); + mPendingInstalls.add(params); } else { Log.e(TAG, "Failed to bind to media container service"); // Indicate install failure TODO add new error code - processPendingInstall(args, - PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE); + processPendingInstall(createInstallArgs(params), + PackageManager.INSTALL_FAILED_INTERNAL_ERROR); } } break; @@ -357,9 +358,9 @@ class PackageManagerService extends IPackageManager.Stub { mContainerService = (IMediaContainerService) msg.obj; } if (mPendingInstalls.size() > 0) { - InstallArgs args = mPendingInstalls.remove(0); - if (args != null) { - handleStartCopy(args); + InstallParams params = mPendingInstalls.remove(0); + if (params != null) { + handleStartCopy(params); } } break; @@ -423,22 +424,56 @@ class PackageManagerService extends IPackageManager.Stub { // Utility method to initiate copying apk via media // container service. - private void handleStartCopy(InstallArgs args) { - int ret = PackageManager.INSTALL_SUCCEEDED; - if (mContainerService == null) { - // Install error - ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - } else { - ret = args.copyApk(mContainerService); + private void handleStartCopy(InstallParams params) { + int ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + if (mContainerService != null) { + // Remote call to find out default install location + int loc = params.getInstallLocation(mContainerService); + // Use install location to create InstallArgs and temporary + // install location + 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 { + if ((params.flags & PackageManager.INSTALL_EXTERNAL) == 0){ + if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { + // Set the flag to install on external media. + params.flags |= PackageManager.INSTALL_EXTERNAL; + } else { + // Make sure the flag for installing on external + // media is unset + params.flags &= ~PackageManager.INSTALL_EXTERNAL; + } + } + // Disable forward locked apps on sdcard. + if ((params.flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 && + (params.flags & PackageManager.INSTALL_EXTERNAL) != 0) { + // Make sure forward locked apps can only be installed + // on internal storage + Log.w(TAG, "Cannot install protected apps on sdcard"); + ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; + } else { + ret = PackageManager.INSTALL_SUCCEEDED; + } + } } mHandler.sendEmptyMessage(MCS_UNBIND); + // Create the file args now. + InstallArgs args = createInstallArgs(params); + if (ret == PackageManager.INSTALL_SUCCEEDED) { + // Create copy only if we are not in an erroneous state. + args.createCopyFile(); + // Remote call to initiate copy + ret = args.copyApk(mContainerService); + } processPendingInstall(args, ret); } } static boolean installOnSd(int flags) { if (((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) || - ((flags & PackageManager.INSTALL_ON_SDCARD) == 0)) { + ((flags & PackageManager.INSTALL_EXTERNAL) == 0)) { return false; } return true; @@ -4249,29 +4284,11 @@ class PackageManagerService extends IPackageManager.Stub { android.Manifest.permission.INSTALL_PACKAGES, null); Message msg = mHandler.obtainMessage(INIT_COPY); - msg.obj = createInstallArgs(packageURI, observer, flags, installerPackageName); + msg.obj = new InstallParams(packageURI, observer, flags, + installerPackageName); mHandler.sendMessage(msg); } - private InstallArgs createInstallArgs(Uri packageURI, IPackageInstallObserver observer, - int flags, String installerPackageName) { - if (installOnSd(flags)) { - return new SdInstallArgs(packageURI, observer, flags, - installerPackageName); - } else { - return new FileInstallArgs(packageURI, observer, flags, - installerPackageName); - } - } - - private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) { - if (installOnSd(flags)) { - return new SdInstallArgs(fullCodePath, fullResourcePath); - } else { - return new FileInstallArgs(fullCodePath, fullResourcePath); - } - } - private void processPendingInstall(final InstallArgs args, final int currentStatus) { // Queue up an async operation since the package installation may take a little while. mHandler.post(new Runnable() { @@ -4327,6 +4344,45 @@ class PackageManagerService extends IPackageManager.Stub { }); } + static final class InstallParams { + final IPackageInstallObserver observer; + int flags; + final Uri packageURI; + final String installerPackageName; + InstallParams(Uri packageURI, + IPackageInstallObserver observer, int flags, + String installerPackageName) { + this.packageURI = packageURI; + this.flags = flags; + this.observer = observer; + this.installerPackageName = installerPackageName; + } + + public int getInstallLocation(IMediaContainerService imcs) { + try { + return imcs.getRecommendedInstallLocation(packageURI); + } catch (RemoteException e) { + } + return -1; + } + }; + + private InstallArgs createInstallArgs(InstallParams params) { + if (installOnSd(params.flags)) { + return new SdInstallArgs(params); + } else { + return new FileInstallArgs(params); + } + } + + private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) { + if (installOnSd(flags)) { + return new SdInstallArgs(fullCodePath, fullResourcePath); + } else { + return new FileInstallArgs(fullCodePath, fullResourcePath); + } + } + static abstract class InstallArgs { final IPackageInstallObserver observer; final int flags; @@ -4359,10 +4415,9 @@ class PackageManagerService extends IPackageManager.Stub { String codeFileName; String resourceFileName; - FileInstallArgs(Uri packageURI, - IPackageInstallObserver observer, int flags, - String installerPackageName) { - super(packageURI, observer, flags, installerPackageName); + FileInstallArgs(InstallParams params) { + super(params.packageURI, params.observer, + params.flags, params.installerPackageName); } FileInstallArgs(String fullCodePath, String fullResourcePath) { @@ -4373,6 +4428,10 @@ class PackageManagerService extends IPackageManager.Stub { resourceFileName = fullResourcePath; } + String getCodePath() { + return codeFileName; + } + void createCopyFile() { boolean fwdLocked = isFwdLocked(flags); installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir; @@ -4380,10 +4439,6 @@ class PackageManagerService extends IPackageManager.Stub { resourceFileName = getResourcePathFromCodePath(); } - String getCodePath() { - return codeFileName; - } - int copyApk(IMediaContainerService imcs) { // Get a ParcelFileDescriptor to write to the output file File codeFile = new File(codeFileName); @@ -4528,10 +4583,9 @@ class PackageManagerService extends IPackageManager.Stub { String cachePath; static final String RES_FILE_NAME = "pkg.apk"; - SdInstallArgs(Uri packageURI, - IPackageInstallObserver observer, int flags, - String installerPackageName) { - super(packageURI, observer, flags, installerPackageName); + SdInstallArgs(InstallParams params) { + super(params.packageURI, params.observer, + params.flags, params.installerPackageName); } SdInstallArgs(String fullCodePath, String fullResourcePath) { @@ -5105,7 +5159,7 @@ class PackageManagerService extends IPackageManager.Stub { String installerPackageName = args.installerPackageName; File tmpPackageFile = new File(args.getCodePath()); boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0); - boolean onSd = ((pFlags & PackageManager.INSTALL_ON_SDCARD) != 0); + boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0); boolean replace = false; int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE | (newInstall ? SCAN_NEW_INSTALL : 0); @@ -5136,14 +5190,6 @@ class PackageManagerService extends IPackageManager.Stub { res.returnCode = pp.getParseError(); return; } - // Some preinstall checks - if (forwardLocked && onSd) { - // Make sure forward locked apps can only be installed - // on internal storage - Log.w(TAG, "Cannot install protected apps on sdcard"); - res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; - return; - } // Get rid of all references to package scan path via parser. pp = null; String oldCodePath = null; @@ -5560,7 +5606,7 @@ class PackageManagerService extends IPackageManager.Stub { if (deleteCodeAndResources) { // TODO can pick up from PackageSettings as well int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD)!=0) ? - PackageManager.INSTALL_ON_SDCARD : 0; + PackageManager.INSTALL_EXTERNAL : 0; installFlags |= ((p.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK)!=0) ? PackageManager.INSTALL_FORWARD_LOCK : 0; outInfo.args = createInstallArgs(installFlags, diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java index 2a4b3f7..f1ba44a 100644 --- a/test-runner/android/test/mock/MockPackageManager.java +++ b/test-runner/android/test/mock/MockPackageManager.java @@ -449,12 +449,4 @@ public class MockPackageManager extends PackageManager { public boolean isSafeMode() { throw new UnsupportedOperationException(); } - - /** - * @hide - */ - @Override - public int recommendAppInstallLocation(PackageParser.Package pkg) { - throw new UnsupportedOperationException(); - } } diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java index 07bd489..8f4d0a1 100755 --- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java @@ -192,6 +192,27 @@ public class PackageManagerTests extends AndroidTestCase { } } + public boolean invokeInstallPackageFail(Uri packageURI, int flags, + final String pkgName, int result) throws Exception { + PackageInstallObserver observer = new PackageInstallObserver(); + try { + // Wait on observer + synchronized(observer) { + getPm().installPackage(packageURI, observer, flags, null); + long waitTime = 0; + while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } + if(!observer.isDone()) { + throw new Exception("Timed out waiting for packageInstalled callback"); + } + return (observer.returnCode == result); + } + } finally { + } + } + Uri getInstallablePackage(int fileResId, File outFile) { Resources res = mContext.getResources(); InputStream is = null; @@ -238,7 +259,7 @@ public class PackageManagerTests extends AndroidTestCase { assertEquals(publicSrcPath, appInstallPath); } else { assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); - if ((flags & PackageManager.INSTALL_ON_SDCARD) != 0) { + if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) { assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0); // Hardcoded for now assertTrue(srcPath.startsWith("/asec")); @@ -253,6 +274,13 @@ public class PackageManagerTests extends AndroidTestCase { failStr("failed with exception : " + e); } } + private void assertNotInstalled(String pkgName) { + try { + ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0); + fail(pkgName + " shouldnt be installed"); + } catch (NameNotFoundException e) { + } + } class InstallParams { String outFileName; @@ -265,30 +293,42 @@ public class PackageManagerTests extends AndroidTestCase { } } + private InstallParams sampleInstallFromRawResource(int flags, boolean cleanUp) { + return installFromRawResource("install.apk", R.raw.install, flags, cleanUp, + false, -1); + } /* * Utility function that reads a apk bundled as a raw resource * copies it into own data directory and invokes * PackageManager api to install it. */ - public InstallParams installFromRawResource(int flags, boolean cleanUp) { - String outFileName = "install.apk"; + private InstallParams installFromRawResource(String outFileName, + int rawResId, int flags, boolean cleanUp, boolean fail, int result) { File filesDir = mContext.getFilesDir(); File outFile = new File(filesDir, outFileName); - Uri packageURI = getInstallablePackage(R.raw.install, outFile); + Uri packageURI = getInstallablePackage(rawResId, outFile); PackageParser.Package pkg = parsePackage(packageURI); assertNotNull(pkg); - InstallReceiver receiver = new InstallReceiver(pkg.packageName); InstallParams ip = null; try { try { - assertTrue(invokeInstallPackage(packageURI, flags, - pkg.packageName, receiver)); + if (fail) { + // Make sure it doesn't exist + getPm().deletePackage(pkg.packageName, null, 0); + assertTrue(invokeInstallPackageFail(packageURI, flags, + pkg.packageName, result)); + assertNotInstalled(pkg.packageName); + } else { + InstallReceiver receiver = new InstallReceiver(pkg.packageName); + assertTrue(invokeInstallPackage(packageURI, flags, + pkg.packageName, receiver)); + // Verify installed information + assertInstall(pkg.packageName, flags); + ip = new InstallParams(pkg, outFileName, packageURI); + } } catch (Exception e) { failStr("Failed with exception : " + e); } - // Verify installed information - assertInstall(pkg.packageName, flags); - ip = new InstallParams(pkg, outFileName, packageURI); return ip; } finally { if (cleanUp) { @@ -299,17 +339,17 @@ public class PackageManagerTests extends AndroidTestCase { @MediumTest public void testInstallNormalInternal() { - installFromRawResource(0, true); + sampleInstallFromRawResource(0, true); } @MediumTest public void testInstallFwdLockedInternal() { - installFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true); + sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true); } @MediumTest public void testInstallSdcard() { - installFromRawResource(PackageManager.INSTALL_ON_SDCARD, true); + sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, true); } /* ------------------------- Test replacing packages --------------*/ @@ -373,7 +413,7 @@ public class PackageManagerTests extends AndroidTestCase { * again. */ public void replaceFromRawResource(int flags) { - InstallParams ip = installFromRawResource(flags, false); + InstallParams ip = sampleInstallFromRawResource(flags, false); boolean replace = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0); GenericReceiver receiver; if (replace) { @@ -409,7 +449,7 @@ public class PackageManagerTests extends AndroidTestCase { @MediumTest public void testReplaceFailSdcard() { - replaceFromRawResource(PackageManager.INSTALL_ON_SDCARD); + replaceFromRawResource(PackageManager.INSTALL_EXTERNAL); } @MediumTest @@ -426,7 +466,7 @@ public class PackageManagerTests extends AndroidTestCase { @MediumTest public void testReplaceSdcard() { replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING | - PackageManager.INSTALL_ON_SDCARD); + PackageManager.INSTALL_EXTERNAL); } /* -------------- Delete tests ---*/ @@ -508,7 +548,7 @@ public class PackageManagerTests extends AndroidTestCase { } public void deleteFromRawResource(int iFlags, int dFlags) { - InstallParams ip = installFromRawResource(iFlags, false); + InstallParams ip = sampleInstallFromRawResource(iFlags, false); boolean retainData = ((dFlags & PackageManager.DONT_DELETE_DATA) != 0); GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName); DeleteObserver observer = new DeleteObserver(); @@ -550,7 +590,7 @@ public class PackageManagerTests extends AndroidTestCase { @MediumTest public void testDeleteSdcard() { - deleteFromRawResource(PackageManager.INSTALL_ON_SDCARD, 0); + deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, 0); } @MediumTest @@ -565,7 +605,7 @@ public class PackageManagerTests extends AndroidTestCase { @MediumTest public void testDeleteSdcardRetainData() { - deleteFromRawResource(PackageManager.INSTALL_ON_SDCARD, PackageManager.DONT_DELETE_DATA); + deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DONT_DELETE_DATA); } /* sdcard mount/unmount tests ******/ @@ -696,7 +736,7 @@ public class PackageManagerTests extends AndroidTestCase { private boolean mountFromRawResource() { // Install pkg on sdcard - InstallParams ip = installFromRawResource(PackageManager.INSTALL_ON_SDCARD | + InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL | PackageManager.INSTALL_REPLACE_EXISTING, false); if (localLOGV) Log.i(TAG, "Installed pkg on sdcard"); boolean origState = getMediaState(); @@ -764,169 +804,32 @@ public class PackageManagerTests extends AndroidTestCase { } } - public void invokeRecommendAppInstallLocation(String outFileName, - int fileResId, int expected) { - int origSetting = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, 0); - try { - // Make sure the set install location setting is diabled. - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, 0); - File filesDir = mContext.getFilesDir(); - File outFile = new File(filesDir, outFileName); - Uri packageURI = getInstallablePackage(fileResId, outFile); - PackageParser.Package pkg = parsePackage(packageURI); - assertNotNull(pkg); - int installLoc = getPm().recommendAppInstallLocation(pkg); - Log.i(TAG, "expected=" + expected +", installLoc="+installLoc); - // Atleast one of the specified expected flags should be set. - boolean onFlash = (installLoc & - PackageManager.INSTALL_ON_INTERNAL_FLASH) != 0; - boolean onSd = (installLoc & - PackageManager.INSTALL_ON_SDCARD) != 0; - boolean expOnFlash = (expected & - PackageManager.INSTALL_ON_INTERNAL_FLASH) != 0; - boolean expOnSd = (expected & - PackageManager.INSTALL_ON_SDCARD) != 0; - assertTrue(expOnFlash == onFlash || expOnSd == onSd); - } finally { - // Restore original setting - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, origSetting); - } + public void testManifestInstallLocationInternal() { + installFromRawResource("install.apk", R.raw.install_loc_internal, + 0, true, false, -1); } - /* - * Tests if an apk can be installed on internal flash by - * explicitly specifying in its manifest. - */ - public void testInstallLocationInternal() { - invokeRecommendAppInstallLocation("install.apk", - R.raw.install_loc_internal, PackageManager.INSTALL_ON_INTERNAL_FLASH); + public void testManifestInstallLocationSdcard() { + installFromRawResource("install.apk", R.raw.install_loc_sdcard, + PackageManager.INSTALL_EXTERNAL, true, false, -1); } - /* - * Tests if an apk can be installed on internal flash by - * explicitly specifying in its manifest and filling up - * internal flash. Should fail to install. - * TODO - */ - public void xxxtestInstallLocationInternalFail() { + public void testManifestInstallLocationAuto() { + installFromRawResource("install.apk", R.raw.install_loc_auto, + 0, true, false, -1); } - /* - * Tests if an apk can be installed on sdcard by - * explicitly specifying in its manifest. - */ - public void testInstallLocationSdcard() { - // TODO No guarantee this will be on sdcard. - invokeRecommendAppInstallLocation("install.apk", - R.raw.install_loc_sdcard, PackageManager.INSTALL_ON_SDCARD - | PackageManager.INSTALL_ON_INTERNAL_FLASH); + public void testManifestInstallLocationUnspecified() { + installFromRawResource("install.apk", R.raw.install_loc_unspecified, + 0, true, false, -1); } - /* - * Tests if an apk can be installed on sdcard by - * explicitly specifying in its manifest and filling up - * the sdcard. Should result in install failure - * TODO - */ - public void xxxtestInstallLocationSdcardFail() { + public void testManifestInstallLocationFwdLockedSdcard() { + installFromRawResource("install.apk", R.raw.install_loc_sdcard, + PackageManager.INSTALL_FORWARD_LOCK | + PackageManager.INSTALL_EXTERNAL, true, true, + PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION); } - - /* - * Tests if an apk can be installed by specifying - * auto for install location - */ - public void xxxtestInstallLocationAutoInternal() { - // TODO clear and make room on internal flash - invokeRecommendAppInstallLocation("install.apk", - R.raw.install_loc_auto, PackageManager.INSTALL_ON_INTERNAL_FLASH); - } - - /* - * Tests if an apk can be installed by specifying - * auto for install location - */ - public void testInstallLocationAutoSdcard() { - // TODO clear and make room on sdcard. - // Fill up internal - invokeRecommendAppInstallLocation("install.apk", - R.raw.install_loc_auto, PackageManager.INSTALL_ON_SDCARD | - PackageManager.INSTALL_ON_INTERNAL_FLASH); - } - - /* - * Tests if an apk can be installed by specifying - * auto for install location - * fill up both internal and sdcard - * TODO - */ - public void xxxtestInstallLocationAutoFail() { - } - /* - * Tests where an apk gets installed based - * on a not specifying anything in manifest. - */ - public void testInstallLocationUnspecifiedInt() { - invokeRecommendAppInstallLocation("install.apk", - R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH); - } - - public void xxxtestInstallLocationUnspecifiedStorage() { - // TODO Fill up internal storage - invokeRecommendAppInstallLocation("install.apk", - R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_SDCARD - | PackageManager.INSTALL_ON_INTERNAL_FLASH); - } - - /* - * Tests where an apk gets installed by expcitly setting - * the user specified install location - */ - public void testInstallLocationUserSpecifiedInternal() { - // Enable user setting - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, 1); - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.DEFAULT_INSTALL_LOCATION, 1); - invokeRecommendAppInstallLocation("install.apk", - R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH); - } - - /* - * Tests where an apk gets installed by expcitly setting - * the user specified install location - */ - public void testInstallLocationUserSpecifiedSdcard() { - // Enable user setting - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, 1); - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.DEFAULT_INSTALL_LOCATION, 2); - int i = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.DEFAULT_INSTALL_LOCATION, 0); - invokeRecommendAppInstallLocation("install.apk", - R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_SDCARD); - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, 0); - } - /* - * Tests where an apk gets installed by expcitly setting - * the user specified install location - */ - public void testInstallLocationUserSpecifiedAuto() { - // Enable user setting - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, 1); - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.DEFAULT_INSTALL_LOCATION, 0); - invokeRecommendAppInstallLocation("install.apk", - R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH); - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, 0); - } - /* * TODO's * check version numbers for upgrades |