From fd3530f90562bb7e66edfee39d90fc8beda82f1d Mon Sep 17 00:00:00 2001 From: Suchi Amalapurapu Date: Mon, 18 Jan 2010 00:15:59 -0800 Subject: 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. --- cmds/pm/src/com/android/commands/pm/Pm.java | 40 +++++++ services/java/com/android/server/MountService.java | 10 ++ .../com/android/server/PackageManagerService.java | 123 +++++++++++++++++---- 3 files changed, 154 insertions(+), 19 deletions(-) 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 @@ public final class Pm { return; } + if ("mountsd".equals(op)) { + runMountSd(); + return; + } + if ("uninstall".equals(op)) { runUninstall(); return; @@ -637,6 +642,37 @@ public final class Pm { } } + 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 @@ public final class Pm { 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 @@ public final class Pm { 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.content.res.Resources; 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 @@ class MountService extends IMountService.Stub private String mLegacyState = Environment.MEDIA_REMOVED; + private PackageManagerService mPms; + /** * Constructs a new MountService instance * @@ -139,6 +142,7 @@ class MountService extends IMountService.Stub 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 @@ class MountService extends IMountService.Stub 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 @@ class MountService extends IMountService.Stub 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 @@ class MountService extends IMountService.Stub 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { HashSet loadedPermissions = new HashSet(); 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { } 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { } } + 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 @@ class PackageManagerService extends IPackageManager.Stub { 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); + } + } + } + } + } + } + }); } } -- cgit v1.1