diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index dcae0c7dd8a11..79bda74e84c34 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -218,14 +218,20 @@ int free_cache(int free_size) static int is_valid_apk_path(const char *path) { int len = strlen(APK_DIR_PREFIX); +int nosubdircheck = 0; if (strncmp(path, APK_DIR_PREFIX, len)) { len = strlen(PROTECTED_DIR_PREFIX); if (strncmp(path, PROTECTED_DIR_PREFIX, len)) { - LOGE("invalid apk path '%s' (bad prefix)\n", path); - return 0; + len = strlen(SDCARD_DIR_PREFIX); + if (strncmp(path, SDCARD_DIR_PREFIX, len)) { + LOGE("invalid apk path '%s' (bad prefix)\n", path); + return 0; + } else { + nosubdircheck = 1; + } } } - if (strchr(path + len, '/')) { + if ((nosubdircheck != 1) && strchr(path + len, '/')) { LOGE("invalid apk path '%s' (subdir?)\n", path); return 0; } diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index 1679d148f4ec0..35a173ea860d0 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -68,6 +68,7 @@ /* other handy constants */ #define PROTECTED_DIR_PREFIX "/data/app-private/" +#define SDCARD_DIR_PREFIX "/asec/" #define DALVIK_CACHE_PREFIX "/data/dalvik-cache/" #define DALVIK_CACHE_POSTFIX "/classes.dex" diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 79eb310bb0e54..4953f5deaf8d9 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -594,6 +594,8 @@ public final class Pm { } } else if (opt.equals("-t")) { installFlags |= PackageManager.INSTALL_ALLOW_TEST; + } else if (opt.equals("-s")) { + installFlags |= PackageManager.INSTALL_ON_SDCARD; } else { System.err.println("Error: Unknown option: " + opt); showUsage(); @@ -822,7 +824,7 @@ public final class Pm { System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); System.err.println(" pm list features"); System.err.println(" pm path PACKAGE"); - System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] PATH"); + 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 enable PACKAGE_OR_COMPONENT"); System.err.println(" pm disable PACKAGE_OR_COMPONENT"); @@ -854,6 +856,7 @@ public final class Pm { System.err.println(" -r: reinstall an exisiting app, keeping its data."); System.err.println(" -t: allow test .apks to be installed."); System.err.println(" -i: specify the installer package name."); + System.err.println(" -s: install package on sdcard."); System.err.println(""); System.err.println("The uninstall command removes a package from the system. Options:"); System.err.println(" -k: keep the data and cache directories around."); diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 3dea28630ad02..b27cd6cda1533 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -217,6 +217,22 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int FLAG_NEVER_ENCRYPT = 1<<17; + /** + * Value for {@link #flags}: Set to true if the application has been + * installed using the forward lock option. + * + * {@hide} + */ + public static final int FLAG_FORWARD_LOCK = 1<<18; + + /** + * Value for {@link #flags}: Set to true if the application is + * currently installed on the sdcard. + * + * {@hide} + */ + public static final int FLAG_ON_SDCARD = 1<<19; + /** * Flags associated with the application. Any combination of * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE}, @@ -227,6 +243,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * {@link #FLAG_SUPPORTS_NORMAL_SCREENS}, * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_RESIZEABLE_FOR_SCREENS}, * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}. + * {@link #FLAG_FWD_LOCKED}, + * {@link #FLAG_ON_SDCARD} */ public int flags = 0; diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index fc6538fbe05d5..54db5e04c7d29 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -296,4 +296,13 @@ interface IPackageManager { * in the special development "no pre-dexopt" mode. */ boolean performDexOpt(String packageName); + + /** + * Update status of external media on the package manager to scan and + * install packages installed on the external media. Like say the + * MountService uses this to call into the package manager to update + * status of sdcard. + */ + void updateExternalMediaStatus(boolean mounted); + } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 53a966d3db126..bc59c94526d62 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -251,6 +251,13 @@ public abstract class PackageManager { */ public static final int INSTALL_ALLOW_TEST = 0x00000004; + /** + * Flag parameter for {@link #installPackage} to indicate that this + * package has to be installed on the sdcard. + * @hide + */ + public static final int INSTALL_ON_SDCARD = 0x00000008; + /** * Flag parameter for * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate @@ -411,6 +418,15 @@ public abstract class PackageManager { */ public static final int INSTALL_FAILED_MISSING_FEATURE = -17; + // ------ Errors related to sdcard + /** + * Installation return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if + * a secure container mount point couldn't be accessed on external media. + * @hide + */ + public static final int INSTALL_FAILED_CONTAINER_ERROR = -18; + /** * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index ad99f54aeac52..8a5df324e60de 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -327,16 +327,18 @@ public class PackageParser { return null; } - public final static int PARSE_IS_SYSTEM = 0x0001; - public final static int PARSE_CHATTY = 0x0002; - public final static int PARSE_MUST_BE_APK = 0x0004; - public final static int PARSE_IGNORE_PROCESSES = 0x0008; + public final static int PARSE_IS_SYSTEM = 1<<0; + public final static int PARSE_CHATTY = 1<<1; + public final static int PARSE_MUST_BE_APK = 1<<2; + public final static int PARSE_IGNORE_PROCESSES = 1<<3; + public final static int PARSE_FORWARD_LOCK = 1<<4; + public final static int PARSE_ON_SDCARD = 1<<5; public int getParseError() { return mParseError; } - public Package parsePackage(File sourceFile, String destFileName, + public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags) { mParseError = PackageManager.INSTALL_SUCCEEDED; @@ -413,8 +415,11 @@ public class PackageParser { parser.close(); assmgr.close(); - pkg.applicationInfo.sourceDir = destFileName; - pkg.applicationInfo.publicSourceDir = destFileName; + // Set code and resource paths + pkg.mPath = destCodePath; + pkg.mScanPath = mArchiveSourcePath; + //pkg.applicationInfo.sourceDir = destCodePath; + //pkg.applicationInfo.publicSourceDir = destRes; pkg.mSignatures = null; return pkg; @@ -1369,6 +1374,14 @@ public class PackageParser { } } + if ((flags & PARSE_FORWARD_LOCK) != 0) { + ai.flags |= ApplicationInfo.FLAG_FORWARD_LOCK; + } + + if ((flags & PARSE_ON_SDCARD) != 0) { + ai.flags |= ApplicationInfo.FLAG_ON_SDCARD; + } + if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_debuggable, false)) { @@ -2530,10 +2543,6 @@ public class PackageParser { // preferred up order. public int mPreferredOrder = 0; - // For use by package manager service to keep track of which apps - // have been installed with forward locking. - public boolean mForwardLocked; - // For use by the package manager to keep track of the path to the // file an app came from. public String mScanPath; diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 2b12268babbd6..4b9b36637dae5 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -135,8 +135,8 @@ class PackageManagerService extends IPackageManager.Stub { static final int SCAN_NO_DEX = 1<<1; static final int SCAN_FORCE_DEX = 1<<2; static final int SCAN_UPDATE_SIGNATURE = 1<<3; - static final int SCAN_FORWARD_LOCKED = 1<<4; - static final int SCAN_NEW_INSTALL = 1<<5; + static final int SCAN_NEW_INSTALL = 1<<4; + static final int SCAN_NO_PATHS = 1<<5; final HandlerThread mHandlerThread = new HandlerThread("PackageManager", Process.THREAD_PRIORITY_BACKGROUND); @@ -281,8 +281,10 @@ class PackageManagerService extends IPackageManager.Stub { final HashMap> mPendingBroadcasts = new HashMap>(); static final int SEND_PENDING_BROADCAST = 1; + static final int DESTROY_SD_CONTAINER = 2; // Delay time in millisecs static final int BROADCAST_DELAY = 10 * 1000; + static final int DESTROY_SD_CONTAINER_DELAY = 30 * 1000; class PackageHandler extends Handler { PackageHandler(Looper looper) { @@ -290,6 +292,15 @@ class PackageManagerService extends IPackageManager.Stub { } public void handleMessage(Message msg) { switch (msg.what) { + case DESTROY_SD_CONTAINER: + String pkgName = (String) msg.obj; + if (pkgName != null) { + // Too bad we cannot handle the errors from destroying the containers. + if (!destroySdDir(pkgName)) { + Log.e(TAG, "Failed to destroy container for pkg : " + pkgName); + } + } + break; case SEND_PENDING_BROADCAST : { String packages[]; ArrayList components[]; @@ -562,12 +573,12 @@ class PackageManagerService extends IPackageManager.Stub { mFrameworkDir.getPath(), OBSERVER_EVENTS, true); mFrameworkInstallObserver.startWatching(); scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM, - scanMode | SCAN_NO_DEX); + scanMode | SCAN_NO_DEX | SCAN_NO_PATHS); mSystemAppDir = new File(Environment.getRootDirectory(), "app"); mSystemInstallObserver = new AppDirObserver( mSystemAppDir.getPath(), OBSERVER_EVENTS, true); mSystemInstallObserver.startWatching(); - scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode); + scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode | SCAN_NO_PATHS); mAppInstallDir = new File(dataDir, "app"); if (mInstaller == null) { // Make sure these dirs exist, when we are running in @@ -594,7 +605,7 @@ class PackageManagerService extends IPackageManager.Stub { mDrmAppInstallObserver = new AppDirObserver( mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false); mDrmAppInstallObserver.startWatching(); - scanDirLI(mDrmAppPrivateInstallDir, 0, scanMode | SCAN_FORWARD_LOCKED); + scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); @@ -1961,12 +1972,7 @@ class PackageManagerService extends IPackageManager.Stub { int i; for (i=0; i 0) { + mbLen++; + } + if (DEBUG_SD_INSTALL) Log.i(TAG, "mbLen="+mbLen); + String cachePath = null; + // Remove any pending destroy messages + mHandler.removeMessages(DESTROY_SD_CONTAINER, pkgName); + try { + cachePath = mountService.createSecureContainer(pkgName, + mbLen, + "vfat", mSdEncryptKey, Process.SYSTEM_UID); + if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install " + pkgName + ", cachePath =" + cachePath); + return cachePath; + } catch(IllegalStateException e) { + Log.e(TAG, "Failed to create storage on sdcard with exception: " + e); + } + // TODO just fail here and let the user delete later on. + try { + mountService.destroySecureContainer(pkgName); + if (DEBUG_SD_INSTALL) Log.i(TAG, "Destroying cache for " + pkgName + ", cachePath =" + cachePath); + } catch(IllegalStateException e) { + Log.e(TAG, "Failed to destroy existing cache: " + e); + return null; + } + try { + cachePath = mountService.createSecureContainer(pkgName, + mbLen, + "vfat", mSdEncryptKey, Process.SYSTEM_UID); + if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install again " + pkgName + ", cachePath =" + cachePath); + return cachePath; + } catch(IllegalStateException e) { + Log.e(TAG, "Failed to create storage on sdcard with exception: " + e); + return null; + } + } + + private String mountSdDir(String pkgName, int ownerUid) { + try { + return getMountService().mountSecureContainer(pkgName, mSdEncryptKey, ownerUid); + } catch (IllegalStateException e) { + Log.i(TAG, "Failed to mount container for pkg : " + pkgName + " exception : " + e); + } + return null; + } + + private String getSdDir(String pkgName) { + String cachePath = null; + try { + cachePath = getMountService().getSecureContainerPath(pkgName); + } catch (IllegalStateException e) { + Log.e(TAG, "Failed to retrieve secure container path for pkg : " + pkgName + " with exception " + e); + } + return cachePath; + } + + private boolean finalizeSdDir(String pkgName) { + try { + getMountService().finalizeSecureContainer(pkgName); + return true; + } catch (IllegalStateException e) { + Log.i(TAG, "Failed to destroy container for pkg : " + pkgName); + return false; + } + } + + private boolean destroySdDir(String pkgName) { + try { + if (mHandler.hasMessages(DESTROY_SD_CONTAINER, pkgName)) { + // Don't have to send message again + mHandler.removeMessages(DESTROY_SD_CONTAINER, pkgName); + } + // We need to destroy right away + getMountService().destroySecureContainer(pkgName); + return true; + } catch (IllegalStateException e) { + Log.i(TAG, "Failed to destroy container for pkg : " + pkgName); + return false; + } + } + + private void sendDelayedDestroySdDir(String pkgName) { + if (mHandler.hasMessages(DESTROY_SD_CONTAINER, pkgName)) { + // Don't have to send message again + return; + } + Message msg = mHandler.obtainMessage(DESTROY_SD_CONTAINER, pkgName); + mHandler.sendMessageDelayed(msg, DESTROY_SD_CONTAINER_DELAY); + } + + public void updateExternalMediaStatus(boolean mediaStatus) { + // TODO + } }