summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuchi Amalapurapu <asuchitra@google.com>2010-03-11 16:49:16 -0800
committerSuchi Amalapurapu <asuchitra@google.com>2010-03-16 16:36:26 -0700
commit8a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2d (patch)
treef445dbf1504f02783b550a80a01ee06d45fbcb4a
parent50fdbef2fbcd390035517090bc54220c265f5c75 (diff)
downloadframeworks_base-8a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2d.zip
frameworks_base-8a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2d.tar.gz
frameworks_base-8a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2d.tar.bz2
Do storage checks before initiating a move.
Add new remote method to check for insufficient error conditions. Some fixes in MountService when updating media status on PackageManagerService Fix size calculation condition in installd. Add new error code if media is unavailable. New tests for testing error codes. Some additional debugging statements in MountService. Change-Id: Ibfe90d5ed6c71d57f9c1c67806f38b5ae9ecdfbf
-rw-r--r--cmds/installd/commands.c16
-rw-r--r--core/java/android/content/pm/PackageManager.java17
-rwxr-xr-xcore/java/com/android/internal/app/IMediaContainerService.aidl1
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java3
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java77
-rw-r--r--services/java/com/android/server/MountService.java56
-rw-r--r--services/java/com/android/server/PackageManagerService.java62
-rwxr-xr-xtests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java145
8 files changed, 292 insertions, 85 deletions
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 654ee68..b8ba3f6 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -389,9 +389,10 @@ int get_size(const char *pkgname, const char *apkpath,
int cachesize = 0;
/* count the source apk as code -- but only if it's not
- * on the /system partition
+ * on the /system partition and its not on the sdcard.
*/
- if (strncmp(apkpath, "/system", 7) != 0) {
+ if (strncmp(apkpath, "/system", 7) != 0 &&
+ strncmp(apkpath, SDCARD_DIR_PREFIX, 7) != 0) {
if (stat(apkpath, &s) == 0) {
codesize += stat_size(&s);
}
@@ -403,17 +404,6 @@ int get_size(const char *pkgname, const char *apkpath,
codesize += stat_size(&s);
}
}
-
- /* count the source apk as code -- but only if it's not
- * installed on the sdcard
- */
- if (strncmp(apkpath, SDCARD_DIR_PREFIX, 7) != 0) {
- if (stat(apkpath, &s) == 0) {
- codesize += stat_size(&s);
- }
- }
-
-
/* count the cached dexfile as code */
if (!create_cache_path(path, apkpath)) {
if (stat(path, &s) == 0) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 271f477..e1fbe48 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -439,6 +439,15 @@ public abstract class PackageManager {
public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
/**
+ * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+ * the new package couldn't be installed in the specified install
+ * location because the media is not available.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
+
+ /**
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser was given a path that is not a file, or does not end with the expected
@@ -586,6 +595,14 @@ public abstract class PackageManager {
public static final int MOVE_FAILED_INVALID_LOCATION = -5;
/**
+ * Error code that is passed to the {@link IPackageMoveObserver} by
+ * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
+ * if the specified package cannot be moved to the specified location.
+ * @hide
+ */
+ public static final int MOVE_FAILED_INTERNAL_ERROR = -6;
+
+ /**
* Flag parameter for {@link #movePackage} to indicate that
* the package should be moved to internal storage if its
* been installed on external media.
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index fd1fd58..badabb0 100755
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -27,4 +27,5 @@ interface IMediaContainerService {
boolean copyResource(in Uri packageURI,
in ParcelFileDescriptor outStream);
PackageInfoLite getMinimalPackageInfo(in Uri fileUri);
+ boolean checkFreeStorage(boolean external, 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 80efca4..4d0a9e0 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -38,6 +38,7 @@ public class PackageHelper {
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;
+ public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5;
private static final boolean localLOGV = true;
private static final String TAG = "PackageHelper";
// App installation location settings values
@@ -70,7 +71,7 @@ public class PackageHelper {
try {
int rc = mountService.createSecureContainer(
- cid, mbLen, "vfat", sdEncKey, uid);
+ cid, mbLen, "fat", sdEncKey, uid);
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, "Failed to create secure container " + cid);
return null;
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index c6b617d..77d11cc 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -24,7 +24,6 @@ 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;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;
@@ -45,7 +44,6 @@ import java.io.IOException;
import java.io.InputStream;
import android.os.FileUtils;
-import android.os.storage.IMountService;
import android.provider.Settings;
/*
@@ -130,26 +128,21 @@ public class DefaultContainerService extends IntentService {
ret.packageName = pkg.packageName;
ret.installLocation = pkg.installLocation;
// Nuke the parser reference right away and force a gc
- Runtime.getRuntime().gc();
packageParser = null;
+ Runtime.getRuntime().gc();
if (pkg == null) {
Log.w(TAG, "Failed to parse package");
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
return ret;
}
ret.packageName = pkg.packageName;
- int loc = recommendAppInstallLocation(pkg.installLocation, archiveFilePath);
- if (loc == PackageManager.INSTALL_EXTERNAL) {
- ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
- } else if (loc == ERR_LOC) {
- Log.i(TAG, "Failed to install insufficient storage");
- ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
- } else {
- // Implies install on internal storage.
- ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL;
- }
+ ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath);
return ret;
}
+
+ public boolean checkFreeStorage(boolean external, Uri fileUri) {
+ return checkFreeStorageInner(external, fileUri);
+ }
};
public DefaultContainerService() {
@@ -190,6 +183,12 @@ public class DefaultContainerService extends IntentService {
}
private String copyResourceInner(Uri packageURI, String newCid, String key, String resFileName) {
+ // Make sure the sdcard is mounted.
+ String status = Environment.getExternalStorageState();
+ if (!status.equals(Environment.MEDIA_MOUNTED)) {
+ Log.w(TAG, "Make sure sdcard is mounted.");
+ return null;
+ }
// Create new container at newCachePath
String codePath = packageURI.getPath();
File codeFile = new File(codePath);
@@ -313,11 +312,13 @@ public class DefaultContainerService extends IntentService {
// Else install on internal NAND flash, unless space on NAND is less than 10%
String status = Environment.getExternalStorageState();
long availSDSize = -1;
+ boolean mediaAvailable = false;
if (status.equals(Environment.MEDIA_MOUNTED)) {
StatFs sdStats = new StatFs(
Environment.getExternalStorageDirectory().getPath());
availSDSize = (long)sdStats.getAvailableBlocks() *
(long)sdStats.getBlockSize();
+ mediaAvailable = true;
}
StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
long totalInternalSize = (long)internalStats.getBlockCount() *
@@ -337,7 +338,8 @@ public class DefaultContainerService extends IntentService {
long reqInternalSize = 0;
boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize);
- boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk &&
+ boolean fitsOnSd = mediaAvailable && (reqInstallSize < availSDSize)
+ && intThresholdOk &&
(reqInternalSize < availInternalSize);
boolean fitsOnInt = intThresholdOk && intAvailOk;
@@ -377,21 +379,58 @@ public class DefaultContainerService extends IntentService {
}
if (!auto) {
if (installOnlyOnSd) {
- return fitsOnSd ? PackageManager.INSTALL_EXTERNAL : ERR_LOC;
+ if (fitsOnSd) {
+ return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+ }
+ if (!mediaAvailable) {
+ return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;
+ }
+ return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
} else if (installOnlyInternal){
// Check on internal flash
- return fitsOnInt ? 0 : ERR_LOC;
+ return fitsOnInt ? PackageHelper.RECOMMEND_INSTALL_INTERNAL :
+ PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
// Try to install internally
if (fitsOnInt) {
- return 0;
+ return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
}
// Try the sdcard now.
if (fitsOnSd) {
- return PackageManager.INSTALL_EXTERNAL;
+ return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
// Return error code
- return ERR_LOC;
+ return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
+ }
+
+ private boolean checkFreeStorageInner(boolean external, Uri packageURI) {
+ File apkFile = new File(packageURI.getPath());
+ long size = apkFile.length();
+ if (external) {
+ 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();
+ }
+ return availSDSize > size;
+ }
+ StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
+ long totalInternalSize = (long)internalStats.getBlockCount() *
+ (long)internalStats.getBlockSize();
+ long availInternalSize = (long)internalStats.getAvailableBlocks() *
+ (long)internalStats.getBlockSize();
+
+ double pctNandFree = (double)availInternalSize / (double)totalInternalSize;
+ // To make final copy
+ long reqInstallSize = size;
+ // 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) < availInternalSize);
+ return intThresholdOk && intAvailOk;
}
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index b8b94a1..d50f591 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -51,6 +51,8 @@ import java.util.HashSet;
class MountService extends IMountService.Stub
implements INativeDaemonConnectorCallbacks {
private static final boolean LOCAL_LOGD = false;
+ private static final boolean DEBUG_UNMOUNT = false;
+ private static final boolean DEBUG_EVENTS = false;
private static final String TAG = "MountService";
@@ -156,6 +158,7 @@ class MountService extends IMountService.Stub
}
void handleFinished() {
+ if (DEBUG_UNMOUNT) Log.i(TAG, "Unmounting " + path);
doUnmountVolume(path, true);
}
}
@@ -205,22 +208,27 @@ class MountService extends IMountService.Stub
void registerReceiver() {
mRegistered = true;
+ if (DEBUG_UNMOUNT) Log.i(TAG, "Registering receiver");
mContext.registerReceiver(mPmReceiver, mPmFilter);
}
void unregisterReceiver() {
mRegistered = false;
+ if (DEBUG_UNMOUNT) Log.i(TAG, "Unregistering receiver");
mContext.unregisterReceiver(mPmReceiver);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case H_UNMOUNT_PM_UPDATE: {
+ if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_UPDATE");
UnmountCallBack ucb = (UnmountCallBack) msg.obj;
mForceUnmounts.add(ucb);
+ if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mRegistered);
// Register only if needed.
if (!mRegistered) {
registerReceiver();
+ if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status");
boolean hasExtPkgs = mPms.updateExternalMediaStatus(false);
if (!hasExtPkgs) {
// Unregister right away
@@ -230,6 +238,7 @@ class MountService extends IMountService.Stub
break;
}
case H_UNMOUNT_PM_DONE: {
+ if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_DONE");
// Unregister now.
if (mRegistered) {
unregisterReceiver();
@@ -286,6 +295,7 @@ class MountService extends IMountService.Stub
break;
}
case H_UNMOUNT_MS : {
+ if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_MS");
UnmountCallBack ucb = (UnmountCallBack) msg.obj;
ucb.handleFinished();
break;
@@ -393,7 +403,12 @@ class MountService extends IMountService.Stub
Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
return;
}
-
+ // Update state on PackageManager
+ if (Environment.MEDIA_UNMOUNTED.equals(state)) {
+ mPms.updateExternalMediaStatus(false);
+ } else if (Environment.MEDIA_MOUNTED.equals(state)) {
+ mPms.updateExternalMediaStatus(true);
+ }
String oldState = mLegacyState;
mLegacyState = state;
@@ -456,6 +471,7 @@ class MountService extends IMountService.Stub
}
}
if (state != null) {
+ if (DEBUG_EVENTS) Log.i(TAG, "Updating valid state " + state);
updatePublicVolumeState(path, state);
}
} catch (Exception e) {
@@ -484,6 +500,18 @@ class MountService extends IMountService.Stub
public boolean onEvent(int code, String raw, String[] cooked) {
Intent in = null;
+ if (DEBUG_EVENTS) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("onEvent::");
+ builder.append(" raw= " + raw);
+ if (cooked != null) {
+ builder.append(" cooked = " );
+ for (String str : cooked) {
+ builder.append(" " + str);
+ }
+ }
+ Log.i(TAG, builder.toString());
+ }
if (code == VoldResponseCode.VolumeStateChange) {
/*
* One of the volumes we're managing has changed state.
@@ -541,18 +569,22 @@ class MountService extends IMountService.Stub
return true;
}
/* Send the media unmounted event first */
+ if (DEBUG_EVENTS) Log.i(TAG, "Sending unmounted event first");
updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
mContext.sendBroadcast(in);
+ if (DEBUG_EVENTS) Log.i(TAG, "Sending media removed");
updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path));
} else if (code == VoldResponseCode.VolumeBadRemoval) {
+ if (DEBUG_EVENTS) Log.i(TAG, "Sending unmounted event first");
/* Send the media unmounted event first */
updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
mContext.sendBroadcast(in);
+ if (DEBUG_EVENTS) Log.i(TAG, "Sending media bad removal");
updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path));
} else {
@@ -570,6 +602,7 @@ class MountService extends IMountService.Stub
private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
String vs = getVolumeState(path);
+ if (DEBUG_EVENTS) Log.i(TAG, "notifyVolumeStateChanged::" + vs);
Intent in = null;
@@ -591,29 +624,31 @@ class MountService extends IMountService.Stub
Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
Environment.MEDIA_NOFS) && !vs.equals(
Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
+ if (DEBUG_EVENTS) Log.i(TAG, "updating volume state for media bad removal nofs and unmountable");
updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
}
} else if (newState == VolumeState.Pending) {
} else if (newState == VolumeState.Checking) {
+ if (DEBUG_EVENTS) Log.i(TAG, "updating volume state checking");
updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path));
} else if (newState == VolumeState.Mounted) {
+ if (DEBUG_EVENTS) Log.i(TAG, "updating volume state mounted");
updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
- // Update media status on PackageManagerService to mount packages on sdcard
- mPms.updateExternalMediaStatus(true);
in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path));
in.putExtra("read-only", false);
} else if (newState == VolumeState.Unmounting) {
- mPms.updateExternalMediaStatus(false);
in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path));
} else if (newState == VolumeState.Formatting) {
} else if (newState == VolumeState.Shared) {
+ if (DEBUG_EVENTS) Log.i(TAG, "Updating volume state media mounted");
/* Send the media unmounted event first */
updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
mContext.sendBroadcast(in);
+ if (DEBUG_EVENTS) Log.i(TAG, "Updating media shared");
updatePublicVolumeState(path, Environment.MEDIA_SHARED);
in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path));
if (LOCAL_LOGD) Log.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
@@ -657,6 +692,7 @@ class MountService extends IMountService.Stub
private int doMountVolume(String path) {
int rc = StorageResultCode.OperationSucceeded;
+ if (DEBUG_EVENTS) Log.i(TAG, "doMountVolume: Mouting " + path);
try {
mConnector.doCommand(String.format("volume mount %s", path));
} catch (NativeDaemonConnectorException e) {
@@ -671,6 +707,7 @@ class MountService extends IMountService.Stub
*/
rc = StorageResultCode.OperationFailedNoMedia;
} else if (code == VoldResponseCode.OpFailedMediaBlank) {
+ if (DEBUG_EVENTS) Log.i(TAG, " updating volume state :: media nofs");
/*
* Media is blank or does not contain a supported filesystem
*/
@@ -678,6 +715,7 @@ class MountService extends IMountService.Stub
in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
rc = StorageResultCode.OperationFailedMediaBlank;
} else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
+ if (DEBUG_EVENTS) Log.i(TAG, "updating volume state media corrupt");
/*
* Volume consistency check failed
*/
@@ -1040,6 +1078,16 @@ class MountService extends IMountService.Stub
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
+ String volState = getVolumeState(path);
+ if (DEBUG_UNMOUNT) Log.i(TAG, "Unmounting " + path + " force = " + force);
+ if (Environment.MEDIA_UNMOUNTED.equals(volState) ||
+ Environment.MEDIA_REMOVED.equals(volState) ||
+ Environment.MEDIA_SHARED.equals(volState) ||
+ Environment.MEDIA_UNMOUNTABLE.equals(volState)) {
+ // Media already unmounted or cannot be unmounted.
+ // TODO return valid return code when adding observer call back.
+ return;
+ }
UnmountCallBack ucb = new UnmountCallBack(path, force);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 139c05f..818e99e 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4613,6 +4613,12 @@ class PackageManagerService extends IPackageManager.Stub {
return pkgLite.recommendedInstallLocation;
}
+ /*
+ * Invoke remote method to get package information and install
+ * location values. Override install location based on default
+ * policy if needed and then create install arguments based
+ * on the install location.
+ */
public void handleStartCopy() throws RemoteException {
int ret = PackageManager.INSTALL_SUCCEEDED;
boolean fwdLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
@@ -4624,9 +4630,7 @@ class PackageManagerService extends IPackageManager.Stub {
} else {
// Remote call to find out default install location
PackageInfoLite pkgLite = mContainerService.getMinimalPackageInfo(packageURI);
- int loc = installLocationPolicy(pkgLite, flags);
- // Use install location to create InstallArgs and temporary
- // install location
+ int loc = pkgLite.recommendedInstallLocation;
if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION){
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS){
@@ -4635,7 +4639,11 @@ class PackageManagerService extends IPackageManager.Stub {
ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
ret = PackageManager.INSTALL_FAILED_INVALID_APK;
+ } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
+ ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
} else {
+ // Override with defaults if needed.
+ loc = installLocationPolicy(pkgLite, flags);
// Override install location with flags
if ((flags & PackageManager.INSTALL_EXTERNAL) == 0){
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
@@ -4701,6 +4709,12 @@ class PackageManagerService extends IPackageManager.Stub {
}
public void handleStartCopy() throws RemoteException {
+ mRet = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ // Check for storage space on target medium
+ if (!targetArgs.checkFreeStorage(mContainerService)) {
+ Log.w(TAG, "Insufficient storage to install");
+ return;
+ }
// Create the file args now.
mRet = targetArgs.copyApk(mContainerService, false);
targetArgs.doPreInstall(mRet);
@@ -4714,15 +4728,20 @@ class PackageManagerService extends IPackageManager.Stub {
builder.append(" target : ");
builder.append(targetArgs.getCodePath());
}
- Log.i(TAG, "Posting move MCS_UNBIND for " + builder.toString());
+ Log.i(TAG, builder.toString());
}
}
@Override
void handleReturnCode() {
targetArgs.doPostInstall(mRet);
- // TODO invoke pending move
- processPendingMove(this, mRet);
+ int currentStatus = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ currentStatus = PackageManager.MOVE_SUCCEEDED;
+ } else if (mRet == PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE){
+ currentStatus = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ }
+ processPendingMove(this, currentStatus);
}
@Override
@@ -4782,6 +4801,7 @@ class PackageManagerService extends IPackageManager.Stub {
// Need installer lock especially for dex file removal.
abstract void cleanUpResourcesLI();
abstract boolean doPostDeleteLI(boolean delete);
+ abstract boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException;
}
class FileInstallArgs extends InstallArgs {
@@ -4812,6 +4832,10 @@ class PackageManagerService extends IPackageManager.Stub {
resourceFileName = getResourcePathFromCodePath();
}
+ boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
+ return imcs.checkFreeStorage(false, packageURI);
+ }
+
String getCodePath() {
return codeFileName;
}
@@ -5013,6 +5037,10 @@ class PackageManagerService extends IPackageManager.Stub {
cid = getTempContainerId();
}
+ boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
+ return imcs.checkFreeStorage(true, packageURI);
+ }
+
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (temp) {
createCopyFile();
@@ -9109,6 +9137,9 @@ class PackageManagerService extends IPackageManager.Stub {
public boolean updateExternalMediaStatus(final boolean mediaStatus) {
final boolean ret;
synchronized (mPackages) {
+ Log.i(TAG, "Updating external media status from " +
+ (mMediaMounted ? "mounted" : "unmounted") + " to " +
+ (mediaStatus ? "mounted" : "unmounted"));
if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
mediaStatus+", mMediaMounted=" + mMediaMounted);
if (mediaStatus == mMediaMounted) {
@@ -9117,6 +9148,14 @@ class PackageManagerService extends IPackageManager.Stub {
mMediaMounted = mediaStatus;
Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_EXTERNAL_STORAGE);
ret = appList != null && appList.size() > 0;
+ if (DEBUG_SD_INSTALL) {
+ if (appList != null) {
+ for (String app : appList) {
+ Log.i(TAG, "Should enable " + app + " on sdcard");
+ }
+ }
+ }
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus returning " + ret);
}
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
@@ -9134,6 +9173,7 @@ class PackageManagerService extends IPackageManager.Stub {
// enabled or disabled.
final String list[] = PackageHelper.getSecureContainerList();
if (list == null || list.length == 0) {
+ Log.i(TAG, "No secure containers on sdcard");
return;
}
@@ -9141,16 +9181,6 @@ class PackageManagerService extends IPackageManager.Stub {
int num = 0;
HashSet<String> removeCids = new HashSet<String>();
HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
- /*HashMap<String, String> cidPathMap = new HashMap<String, String>();
- // Don't hold any locks when getting cache paths
- for (String cid : list) {
- String cpath = PackageHelper.getSdDir(cid);
- if (cpath == null) {
- removeCids.add(cid);
- } else {
- cidPathMap.put(cid, cpath);
- }
- }*/
synchronized (mPackages) {
for (String cid : list) {
SdInstallArgs args = new SdInstallArgs(cid);
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 8c8b00c..a06a13b 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -72,8 +72,8 @@ import android.provider.Settings.SettingNotFoundException;
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
public static final String TAG="PackageManagerTests";
- public final long MAX_WAIT_TIME=120*1000;
- public final long WAIT_TIME_INCR=20*1000;
+ public final long MAX_WAIT_TIME = 25*1000;
+ public final long WAIT_TIME_INCR = 5*1000;
private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec";
private static final int APP_INSTALL_AUTO = PackageHelper.APP_INSTALL_AUTO;
private static final int APP_INSTALL_DEVICE = PackageHelper.APP_INSTALL_INTERNAL;
@@ -378,39 +378,50 @@ public class PackageManagerTests extends AndroidTestCase {
private InstallParams installFromRawResource(String outFileName,
int rawResId, int flags, boolean cleanUp, boolean fail, int result,
int expInstallLocation) {
+ PackageManager pm = mContext.getPackageManager();
File filesDir = mContext.getFilesDir();
File outFile = new File(filesDir, outFileName);
Uri packageURI = getInstallablePackage(rawResId, outFile);
PackageParser.Package pkg = parsePackage(packageURI);
assertNotNull(pkg);
- InstallParams ip = null;
- // Make sure the package doesn't exist
- getPm().deletePackage(pkg.packageName, null, 0);
- // Clean up the containers as well
- clearSecureContainersForPkg(pkg.packageName);
- try {
+ if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) == 0) {
+ // Make sure the package doesn't exist
try {
- if (fail) {
- 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, flags, expInstallLocation);
- ip = new InstallParams(pkg, outFileName, packageURI);
- }
+ ApplicationInfo appInfo = pm.getApplicationInfo(pkg.packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
+ invokeDeletePackage(packageURI, 0,
+ pkg.packageName, receiver);
+ } catch (NameNotFoundException e1) {
} catch (Exception e) {
- failStr("Failed with exception : " + e);
+ failStr(e);
+ }
+ // Clean up the containers as well
+ clearSecureContainersForPkg(pkg.packageName);
+ }
+ InstallParams ip = null;
+ try {
+ if (fail) {
+ 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, flags, expInstallLocation);
+ ip = new InstallParams(pkg, outFileName, packageURI);
}
return ip;
+ } catch (Exception e) {
+ failStr("Failed with exception : " + e);
} finally {
if (cleanUp) {
cleanUpInstall(ip);
}
}
+ return ip;
}
@MediumTest
@@ -820,7 +831,7 @@ public class PackageManagerTests extends AndroidTestCase {
try {
// Wait on observer
synchronized(observer) {
- getMs().unmountVolume(path, false);
+ getMs().unmountVolume(path, true);
long waitTime = 0;
while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
observer.wait(WAIT_TIME_INCR);
@@ -949,14 +960,21 @@ public class PackageManagerTests extends AndroidTestCase {
PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
}
- private void replaceManifestLocation(int iFlags, int rFlags) {
+ /*
+ * Install a package on internal flash via PackageManager install flag. Replace
+ * the package via flag to install on sdcard. Make sure the new flag overrides
+ * the old install location.
+ */
+ public void testReplaceFlagInternalSdcard() {
+ int iFlags = 0;
+ int rFlags = PackageManager.INSTALL_EXTERNAL;
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);
+ assertInstall(ip.pkg, rFlags, ip.pkg.installLocation);
} catch (Exception e) {
failStr("Failed with exception : " + e);
} finally {
@@ -964,12 +982,26 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
- public void testReplaceFlagInternalSdcard() {
- replaceManifestLocation(0, PackageManager.INSTALL_EXTERNAL);
- }
-
+ /*
+ * Install a package on sdcard via PackageManager install flag. Replace
+ * the package with no flags or manifest option and make sure the old
+ * install location is retained.
+ */
public void testReplaceFlagSdcardInternal() {
- replaceManifestLocation(PackageManager.INSTALL_EXTERNAL, 0);
+ int iFlags = PackageManager.INSTALL_EXTERNAL;
+ int rFlags = 0;
+ 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, iFlags, ip.pkg.installLocation);
+ } catch (Exception e) {
+ failStr("Failed with exception : " + e);
+ } finally {
+ cleanUpInstall(ip);
+ }
}
public void testManifestInstallLocationReplaceInternalSdcard() {
@@ -984,7 +1016,7 @@ public class PackageManagerTests extends AndroidTestCase {
int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING;
try {
InstallParams rp = installFromRawResource("install.apk", rApk,
- rFlags, false,
+ replaceFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
assertInstall(rp.pkg, replaceFlags, rp.pkg.installLocation);
} catch (Exception e) {
@@ -1002,11 +1034,10 @@ public class PackageManagerTests extends AndroidTestCase {
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,
+ replaceFlags, false,
false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
assertInstall(rp.pkg, replaceFlags, ip.pkg.installLocation);
} catch (Exception e) {
@@ -1211,6 +1242,56 @@ public class PackageManagerTests extends AndroidTestCase {
moveFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.MOVE_INTERNAL,
PackageManager.MOVE_SUCCEEDED);
}
+
+ /*
+ * Test that an install error code is returned when media is unmounted
+ * and package installed on sdcard via package manager flag.
+ */
+ public void testInstallSdcardUnmount() {
+ boolean origState = getMediaState();
+ try {
+ // Unmount sdcard
+ assertTrue(unmountMedia());
+ // Try to install and make sure an error code is returned.
+ assertNull(installFromRawResource("install.apk", R.raw.install,
+ PackageManager.INSTALL_EXTERNAL, false,
+ true, PackageManager.INSTALL_FAILED_CONTAINER_ERROR,
+ PackageInfo.INSTALL_LOCATION_AUTO));
+ } finally {
+ // Restore original media state
+ if (origState) {
+ mountMedia();
+ } else {
+ unmountMedia();
+ }
+ }
+ }
+
+ /*
+ * Unmount sdcard. Try installing an app with manifest option to install
+ * on sdcard. Make sure it gets installed on internal flash.
+ */
+ public void testInstallManifestSdcardUnmount() {
+ boolean origState = getMediaState();
+ try {
+ // Unmount sdcard
+ assertTrue(unmountMedia());
+ // Try to install and make sure an error code is returned.
+ assertNotNull(installFromRawResource("install.apk", R.raw.install_loc_sdcard,
+ 0, false,
+ false, -1,
+ PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY));
+ } finally {
+ // Restore original media state
+ if (origState) {
+ mountMedia();
+ } else {
+ unmountMedia();
+ }
+ }
+ }
+
+ /*---------- Recommended install location tests ----*/
/*
* TODO's
* check version numbers for upgrades