Merge "Mount/Unmount secure containers Persist flags in PackageSetting. Flags are relevant to ApplicationInfo.FLAG_SYSTEM, Application.FLAG_ON_SDCARD, ApplicationInfo.FLAG_FORWARD_LOCK. New pm command to simulate mount/unmount in Pm. This will be removed when MountService/vold event generation gets fixed. Calls from MountService into PackageManager when media gets mounted/unmounted. Scan the packages and grant permissions when the sdcard gets mounted. This api might change again."
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 4953f5d..68373cb 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -92,6 +92,11 @@
return;
}
+ if ("mountsd".equals(op)) {
+ runMountSd();
+ return;
+ }
+
if ("uninstall".equals(op)) {
runUninstall();
return;
@@ -637,6 +642,37 @@
}
}
+ private void runMountSd() {
+ String opt;
+ boolean mount = false;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("-m")) {
+ String mountStr = nextOptionData();
+ if (mountStr == null) {
+ System.err.println("Error: no value specified for -m");
+ showUsage();
+ return;
+ }
+ if ("true".equalsIgnoreCase(mountStr)) {
+ mount = true;
+ } else if ("false".equalsIgnoreCase(mountStr)) {
+ mount = false;
+ } else {
+ System.err.println("Error: no value specified for -m");
+ showUsage();
+ return;
+ }
+ }
+ }
+
+ try {
+ mPm.updateExternalMediaStatus(mount);
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(PM_NOT_RUNNING_ERR);
+ }
+ }
+
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
boolean finished;
boolean result;
@@ -826,6 +862,7 @@
System.err.println(" pm path PACKAGE");
System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] PATH");
System.err.println(" pm uninstall [-k] PACKAGE");
+ System.err.println(" pm mountsd [-m true/false]");
System.err.println(" pm enable PACKAGE_OR_COMPONENT");
System.err.println(" pm disable PACKAGE_OR_COMPONENT");
System.err.println("");
@@ -862,6 +899,9 @@
System.err.println(" -k: keep the data and cache directories around.");
System.err.println("after the package removal.");
System.err.println("");
+ System.err.println("The mountsd command simulates mounting/unmounting sdcard.Options:");
+ System.err.println(" -m: true or false.");
+ System.err.println("");
System.err.println("The enable and disable commands change the enabled state of");
System.err.println("a given package or component (written as \"package/class\").");
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index f8f8742..0d9f98f 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -28,6 +28,7 @@
import android.net.Uri;
import android.os.IMountService;
import android.os.Environment;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UEventObserver;
import android.os.Handler;
@@ -131,6 +132,8 @@
private String mLegacyState = Environment.MEDIA_REMOVED;
+ private PackageManagerService mPms;
+
/**
* Constructs a new MountService instance
*
@@ -139,6 +142,7 @@
public MountService(Context context) {
mContext = context;
+ mPms = (PackageManagerService) ServiceManager.getService("package");
// Register a BOOT_COMPLETED handler so that we can start
// our NativeDaemonConnector. We defer the startup so that we don't
// start processing events before we ought-to
@@ -509,6 +513,8 @@
void handlePossibleExplicitUnmountBroadcast(String path) {
if (mMounted) {
mMounted = false;
+ // Update media status on PackageManagerService to unmount packages on sdcard
+ mPms.updateExternalMediaStatus(false);
Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
Uri.parse("file://" + path));
mContext.sendBroadcast(intent);
@@ -739,6 +745,8 @@
updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
+ // Update media status on PackageManagerService to unmount packages on sdcard
+ mPms.updateExternalMediaStatus(false);
if (mShowSafeUnmountNotificationWhenUnmounted) {
setMediaStorageNotification(
com.android.internal.R.string.ext_media_safe_unmount_notification_title,
@@ -800,6 +808,8 @@
void notifyMediaMounted(String path, boolean readOnly) {
updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
+ // Update media status on PackageManagerService to mount packages on sdcard
+ mPms.updateExternalMediaStatus(true);
setMediaStorageNotification(0, 0, 0, false, false, null);
updateUsbMassStorageNotification(false, false);
Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 1b6a56a..cafc804 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4753,13 +4753,18 @@
ret = deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
}
if (ret && onSd) {
- // Post a delayed destroy on the container since there might
- // be active processes holding open file handles to package
- // resources which will get killed by the process killer when
- // destroying the container. This might even kill the current
- // process and crash the system. Delay the destroy a bit so
- // that the active processes get to handle the uninstall broadcasts.
- sendDelayedDestroySdDir(packageName);
+ if (deleteCodeAndResources) {
+ // Post a delayed destroy on the container since there might
+ // be active processes holding open file handles to package
+ // resources which will get killed by the process killer when
+ // destroying the container. This might even kill the current
+ // process and crash the system. Delay the destroy a bit so
+ // that the active processes get to handle the uninstall broadcasts.
+ sendDelayedDestroySdDir(packageName);
+ } else {
+ // Just unmount the directory
+ unMountSdDir(packageName);
+ }
}
return ret;
}
@@ -5866,7 +5871,9 @@
HashSet<String> loadedPermissions = new HashSet<String>();
GrantedPermissions(int pkgFlags) {
- this.pkgFlags = pkgFlags & ApplicationInfo.FLAG_SYSTEM;
+ this.pkgFlags = (pkgFlags & ApplicationInfo.FLAG_SYSTEM) |
+ (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) |
+ (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD);
}
}
@@ -6672,9 +6679,8 @@
if (!pkg.resourcePathString.equals(pkg.codePathString)) {
serializer.attribute(null, "resourcePath", pkg.resourcePathString);
}
- serializer.attribute(null, "system",
- (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
- ? "true" : "false");
+ serializer.attribute(null, "flags",
+ Integer.toString(pkg.pkgFlags));
serializer.attribute(null, "ts", pkg.getTimeStampStr());
serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
if (pkg.sharedUser == null) {
@@ -7065,16 +7071,24 @@
} catch (NumberFormatException e) {
}
}
- systemStr = parser.getAttributeValue(null, "system");
installerPackageName = parser.getAttributeValue(null, "installer");
+
+ systemStr = parser.getAttributeValue(null, "flags");
if (systemStr != null) {
- if ("true".equals(systemStr)) {
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ try {
+ pkgFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
}
} else {
- // Old settings that don't specify system... just treat
- // them as system, good enough.
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ // For backward compatibility
+ systemStr = parser.getAttributeValue(null, "system");
+ if (systemStr != null) {
+ pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM : 0;
+ } else {
+ // Old settings that don't specify system... just treat
+ // them as system, good enough.
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
}
timeStampStr = parser.getAttributeValue(null, "ts");
if (timeStampStr != null) {
@@ -7443,6 +7457,7 @@
static final boolean DEBUG_SD_INSTALL = false;
final private String mSdEncryptKey = "AppsOnSD";
final private String mSdEncryptAlg = "AES";
+ private boolean mMediaMounted = false;
private MountService getMountService() {
return (MountService) ServiceManager.getService("mount");
@@ -7518,6 +7533,11 @@
return null;
}
+ private boolean unMountSdDir(String pkgName) {
+ // STOPSHIP unmount directory
+ return true;
+ }
+
private String getSdDir(String pkgName) {
String cachePath = null;
try {
@@ -7553,6 +7573,15 @@
}
}
+ private String[] getSecureContainerList() {
+ try {
+ return getMountService().getSecureContainerList();
+ } catch (IllegalStateException e) {
+ Log.i(TAG, "Failed to getSecureContainerList");
+ }
+ return null;
+ }
+
private void sendDelayedDestroySdDir(String pkgName) {
if (mHandler.hasMessages(DESTROY_SD_CONTAINER, pkgName)) {
// Don't have to send message again
@@ -7562,7 +7591,63 @@
mHandler.sendMessageDelayed(msg, DESTROY_SD_CONTAINER_DELAY);
}
- public void updateExternalMediaStatus(boolean mediaStatus) {
- // TODO
+ public void updateExternalMediaStatus(final boolean mediaStatus) {
+ if (mediaStatus == mMediaMounted) {
+ return;
+ }
+ mMediaMounted = mediaStatus;
+ // Queue up an async operation since the package installation may take a little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ mHandler.removeCallbacks(this);
+ final String list[] = getSecureContainerList();
+ if (list == null || list.length == 0) {
+ return;
+ }
+ for (int i = 0; i < list.length; i++) {
+ String mountPkg = list[i];
+ // TODO compare with default package
+ synchronized (mPackages) {
+ PackageSetting ps = mSettings.mPackages.get(mountPkg);
+ if (ps != null && (ps.pkgFlags & ApplicationInfo.FLAG_ON_SDCARD) != 0) {
+ if (mediaStatus) {
+ String pkgPath = getSdDir(mountPkg);
+ if (pkgPath == null) {
+ continue;
+ }
+ pkgPath = ps.codePathString;
+ int parseFlags = PackageParser.PARSE_CHATTY |
+ PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
+ PackageParser pp = new PackageParser(pkgPath);
+ pp.setSeparateProcesses(mSeparateProcesses);
+ final PackageParser.Package pkg = pp.parsePackage(new File(pkgPath),
+ null, mMetrics, parseFlags);
+ if (pkg == null) {
+ Log.w(TAG, "Failed to install package : " + mountPkg + " from sd card");
+ continue;
+ }
+ int scanMode = SCAN_MONITOR;
+ // Scan the package
+ if (scanPackageLI(pkg, parseFlags, scanMode) != null) {
+ // Grant permissions
+ grantPermissionsLP(pkg, false);
+ // Persist settings
+ mSettings.writeLP();
+ } else {
+ Log.i(TAG, "Failed to install package: " + mountPkg + " from sdcard");
+ }
+ } else {
+ // Delete package
+ PackageRemovedInfo outInfo = new PackageRemovedInfo();
+ boolean res = deletePackageLI(mountPkg, false, PackageManager.DONT_DELETE_DATA, outInfo);
+ if (!res) {
+ Log.e(TAG, "Failed to delete pkg from sdcard : " + mountPkg);
+ }
+ }
+ }
+ }
+ }
+ }
+ });
}
}