summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--core/java/android/app/ContextImpl.java96
-rw-r--r--core/java/android/content/pm/PackageManager.java34
-rwxr-xr-xcore/java/com/android/internal/app/IMediaContainerService.aidl1
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java28
-rwxr-xr-xpackages/DefaultContainerService/AndroidManifest.xml1
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java147
-rw-r--r--services/java/com/android/server/PackageManagerService.java168
-rw-r--r--test-runner/android/test/mock/MockPackageManager.java8
-rwxr-xr-xtests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java251
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