Merge "Workaround for some hardware decoders not properly signaling end-of-output-stream properly."
diff --git a/api/current.xml b/api/current.xml
index 113b9e0..96e7fd6 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -23927,6 +23927,28 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_SELECT_QUERY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;select_query&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INTENT_ACTION_GLOBAL_SEARCH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.search.action.GLOBAL_SEARCH&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="INTENT_ACTION_SEARCHABLES_CHANGED"
  type="java.lang.String"
  transient="false"
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index dcae0c7..79bda74 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -218,14 +218,20 @@
 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 1679d14..35a173e 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 79eb310b..4953f5d 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 @@
                 }
             } 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 @@
         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 @@
         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/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 9112be4..981145b 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1332,20 +1332,11 @@
     public final static String EXTRA_DATA_KEY = "intent_extra_data_key";
 
     /**
-     * String extra data key for {@link #INTENT_ACTION_GLOBAL_SEARCH} intents. Contains the initial
-     * query to show in the global search activity.
-     *
-     * @hide Pending API council approval
+     * Boolean extra data key for {@link #INTENT_ACTION_GLOBAL_SEARCH} intents. If {@code true},
+     * the initial query should be selected when the global search activity is started, so
+     * that the user can easily replace it with another query.
      */
-    public final static String INITIAL_QUERY = "initial_query";
-
-    /**
-     * Boolean extra data key for {@link Intent#INTENT_ACTION_GLOBAL_SEARCH} intents. If {@code true},
-     * the initial query should be selected.
-     *
-     * @hide Pending API council approval
-     */
-    public final static String SELECT_INITIAL_QUERY = "select_initial_query";
+    public final static String EXTRA_SELECT_QUERY = "select_query";
 
     /**
      * Defines the constants used in the communication between {@link android.app.SearchDialog} and
@@ -1643,10 +1634,12 @@
             = "android.search.action.CHANGE_SEARCH_SOURCE";
 
     /**
-     * Intent action for finding the global search activity.
+     * Intent action for starting the global search activity.
      * The global search provider should handle this intent.
-     * 
-     * @hide Pending API council approval.
+     *
+     * Supported extra data keys: {@link #QUERY},
+     * {@link #EXTRA_SELECT_QUERY},
+     * {@link #APP_DATA}.
      */
     public final static String INTENT_ACTION_GLOBAL_SEARCH 
             = "android.search.action.GLOBAL_SEARCH";
@@ -1823,10 +1816,10 @@
             intent.putExtra(APP_DATA, appSearchData);
         }
         if (!TextUtils.isEmpty(initialQuery)) {
-            intent.putExtra(INITIAL_QUERY, initialQuery);
+            intent.putExtra(QUERY, initialQuery);
         }
         if (selectInitialQuery) {
-            intent.putExtra(SELECT_INITIAL_QUERY, selectInitialQuery);
+            intent.putExtra(EXTRA_SELECT_QUERY, selectInitialQuery);
         }
         try {
             if (DBG) Log.d(TAG, "Starting global search: " + intent.toUri(0));
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 3dea286..b27cd6c 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -218,6 +218,22 @@
     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},
      * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
@@ -227,6 +243,8 @@
      * {@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 fc6538f..54db5e0 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -296,4 +296,13 @@
      * 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 53a966d..bc59c94 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -252,6 +252,13 @@
     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
      * that you don't want to kill the app containing the component.  Be careful when you set this
@@ -411,6 +418,15 @@
      */
     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 ad99f54..8a5df32 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -327,16 +327,18 @@
         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 @@
         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 @@
             }
         }
 
+        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 @@
         // 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/core/java/android/view/View.java b/core/java/android/view/View.java
index df4cab0..a3d3521 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6177,7 +6177,10 @@
      * @see #getDrawingCache()
      */
     public void setDrawingCacheBackgroundColor(int color) {
-        mDrawingCacheBackgroundColor = color;
+        if (color != mDrawingCacheBackgroundColor) {
+            mDrawingCacheBackgroundColor = color;
+            mPrivateFlags &= ~DRAWING_CACHE_VALID;
+        }
     }
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index c349606..09ed931 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2997,8 +2997,11 @@
 
     private void drawLayers(Canvas canvas) {
         if (mRootLayer != 0) {
-            float scrollY = Math.max(mScrollY - getTitleHeight(), 0);
+            int scrollY = computeVerticalScrollOffset();
+            int viewHeight = getHeight() - getVisibleTitleHeight();
+
             nativeDrawLayers(mRootLayer, mScrollX, scrollY,
+                             getWidth(), viewHeight,
                              mActualScale, canvas);
         }
     }
@@ -6354,7 +6357,8 @@
     private native boolean  nativeLayersHaveAnimations(int layer);
     private native void     nativeUpdateLayers(int layer, int updates);
     private native void     nativeDrawLayers(int layer,
-                                             float scrollX, float scrollY,
+                                             int scrollX, int scrollY,
+                                             int width, int height,
                                              float scale, Canvas canvas);
     private native void     nativeDrawMatches(Canvas canvas);
     private native void     nativeDrawSelectionPointer(Canvas content,
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 32199a0..b795080 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3250,7 +3250,14 @@
      * @param color The background color
      */
     public void setCacheColorHint(int color) {
-        mCacheColorHint = color;
+        if (color != mCacheColorHint) {
+            mCacheColorHint = color;
+            int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                getChildAt(i).setDrawingCacheBackgroundColor(color);
+            }
+            mRecycler.setCacheColorHint(color);
+        }
     }
 
     /**
@@ -3670,5 +3677,38 @@
                 }
             }
         }
+
+        /**
+         * Updates the cache color hint of all known views.
+         *
+         * @param color The new cache color hint.
+         */
+        void setCacheColorHint(int color) {
+            if (mViewTypeCount == 1) {
+                final ArrayList<View> scrap = mCurrentScrap;
+                final int scrapCount = scrap.size();
+                for (int i = 0; i < scrapCount; i++) {
+                    scrap.get(i).setDrawingCacheBackgroundColor(color);
+                }
+            } else {
+                final int typeCount = mViewTypeCount;
+                for (int i = 0; i < typeCount; i++) {
+                    final ArrayList<View> scrap = mScrapViews[i];
+                    final int scrapCount = scrap.size();
+                    for (int j = 0; j < scrapCount; j++) {
+                        scrap.get(i).setDrawingCacheBackgroundColor(color);
+                    }
+                }
+            }
+            // Just in case this is called during a layout pass
+            final View[] activeViews = mActiveViews;
+            final int count = activeViews.length;
+            for (int i = 0; i < count; ++i) {
+                final View victim = activeViews[i];
+                if (victim != null) {
+                    victim.setDrawingCacheBackgroundColor(color);
+                }
+            }
+        }
     }
 }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 2b12268..4b9b366 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -135,8 +135,8 @@
     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 @@
     final HashMap<String, ArrayList<String>> mPendingBroadcasts
             = new HashMap<String, ArrayList<String>>();
     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 @@
         }
         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 @@
                 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 @@
             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 @@
         int i;
         for (i=0; i<files.length; i++) {
             File file = new File(dir, files[i]);
-            File resFile = file;
-            // Pick up the resource path from settings for fwd locked apps
-            if ((scanMode & SCAN_FORWARD_LOCKED) != 0) {
-                resFile = null;
-            }
-            PackageParser.Package pkg = scanPackageLI(file, file, resFile,
+            PackageParser.Package pkg = scanPackageLI(file,
                     flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
         }
     }
@@ -2009,14 +2015,15 @@
      *  Returns null in case of errors and the error code is stored in mLastScanError
      */
     private PackageParser.Package scanPackageLI(File scanFile,
-            File destCodeFile, File destResourceFile, int parseFlags,
+            int parseFlags,
             int scanMode) {
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
         parseFlags |= mDefParseFlags;
         PackageParser pp = new PackageParser(scanFile.getPath());
         pp.setSeparateProcesses(mSeparateProcesses);
         final PackageParser.Package pkg = pp.parsePackage(scanFile,
-                destCodeFile.getAbsolutePath(), mMetrics, parseFlags);
+                scanFile.getPath(),
+                mMetrics, parseFlags);
         if (pkg == null) {
             mLastScanError = pp.getParseError();
             return null;
@@ -2062,16 +2069,12 @@
         }
         // The apk is forward locked (not public) if its code and resources
         // are kept in different files.
+        // TODO grab this value from PackageSettings
         if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
-            scanMode |= SCAN_FORWARD_LOCKED;
-        }
-        File resFile = destResourceFile;
-        if (ps != null && ((scanMode & SCAN_FORWARD_LOCKED) != 0)) {
-            resFile = getFwdLockedResource(ps.name);
+            parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
         }
         // Note that we invoke the following method only if we are about to unpack an application
-        return scanPackageLI(scanFile, destCodeFile, resFile,
-                pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
+        return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
     }
 
     private static String fixProcessName(String defProcessName,
@@ -2138,7 +2141,7 @@
             try {
                 if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
                     ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
-                            !pkg.mForwardLocked);
+                            !isForwardLocked(pkg));
                     pkg.mDidDexOpt = true;
                     performed = true;
                 }
@@ -2164,9 +2167,8 @@
     }
     
     private PackageParser.Package scanPackageLI(
-        File scanFile, File destCodeFile, File destResourceFile,
         PackageParser.Package pkg, int parseFlags, int scanMode) {
-
+        File scanFile = new File(pkg.mScanPath);
         mScanningPath = scanFile;
         if (pkg == null) {
             mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
@@ -2223,6 +2225,43 @@
             return null;
         }
 
+        // Initialize package source and resource directories
+        File destResourceFile = null;
+        File destCodeFile = null;
+        if ((scanMode & SCAN_NO_PATHS) == 0) {
+            boolean fwdLocked = (parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0;
+            final String pkgFileName = pkgName + ".apk";
+            File destDir = null;
+
+            if (fwdLocked) {
+                destDir = mDrmAppPrivateInstallDir;
+                destResourceFile = new File(mAppInstallDir, pkgName + ".zip");
+            } else {
+                boolean onSd = (parseFlags & PackageParser.PARSE_ON_SDCARD) != 0;
+                if (!onSd) {
+                    destDir = mAppInstallDir;
+                } else {
+                    String cachePath = getSdDir(pkgName);
+                    if (cachePath == null) {
+                        Log.e(TAG, "Secure container path for pkg: " + pkgName + " at location: " + cachePath +
+                                " not found");
+                        mLastScanError = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+                        return null;
+                    }
+                    destDir = new File(cachePath);
+                }
+                destResourceFile = new File(destDir, pkgFileName);
+            }
+            destCodeFile = new File(destDir, pkgFileName);
+            pkg.mPath = destCodeFile.getAbsolutePath();
+        } else {
+            pkg.mPath = pkg.mScanPath;
+            destCodeFile = new File(pkg.mScanPath);
+            destResourceFile = new File(pkg.mScanPath);
+        }
+        pkg.applicationInfo.sourceDir = destCodeFile.getAbsolutePath();
+        pkg.applicationInfo.publicSourceDir = destResourceFile.getAbsolutePath();
+
         SharedUserSetting suid = null;
         PackageSetting pkgSetting = null;
 
@@ -2394,7 +2433,6 @@
                 pkg.applicationInfo.packageName,
                 pkg.applicationInfo.processName,
                 pkg.applicationInfo.uid);
-        pkg.applicationInfo.publicSourceDir = destResourceFile.toString();
 
         File dataPath;
         if (mPlatformPackage == pkg) {
@@ -2509,8 +2547,6 @@
                     return null;
                 }
             }
-
-            pkg.mForwardLocked = (scanMode&SCAN_FORWARD_LOCKED) != 0;
             pkg.mScanPath = path;
 
             if ((scanMode&SCAN_NO_DEX) == 0) {
@@ -2545,7 +2581,7 @@
         }
         synchronized (mPackages) {
             // Add the new setting to mSettings
-            mSettings.insertPackageSettingLP(pkgSetting, pkg, destCodeFile, destResourceFile);
+            mSettings.insertPackageSettingLP(pkgSetting, pkg);
             // Add the new setting to mPackages
             mPackages.put(pkg.applicationInfo.packageName, pkg);
             int N = pkg.providers.size();
@@ -3714,7 +3750,7 @@
                 if ((event&ADD_EVENTS) != 0) {
                     PackageParser.Package p = mAppDirs.get(fullPathStr);
                     if (p == null) {
-                        p = scanPackageLI(fullPath, fullPath, fullPath,
+                        p = scanPackageLI(fullPath,
                                 (mIsRom ? PackageParser.PARSE_IS_SYSTEM : 0) |
                                 PackageParser.PARSE_CHATTY |
                                 PackageParser.PARSE_MUST_BE_APK,
@@ -3823,13 +3859,14 @@
     /*
      * Install a non-existing package.
      */
-    private void installNewPackageLI(String pkgName,
-            File tmpPackageFile,
-            String destFilePath, File destPackageFile, File destResourceFile,
-            PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
+    private void installNewPackageLI(PackageParser.Package pkg,
+            int parseFlags,
+            int scanMode,
             String installerPackageName, PackageInstalledInfo res) {
         // Remember this for later, in case we need to rollback this install
         boolean dataDirExists;
+        String pkgName = pkg.packageName;
+        boolean onSd = (parseFlags & PackageParser.PARSE_ON_SDCARD) != 0;
 
         if (useEncryptedFilesystemForPackage(pkg)) {
             dataDirExists = (new File(mSecureAppDataDir, pkgName)).exists();
@@ -3838,7 +3875,7 @@
         }
         res.name = pkgName;
         synchronized(mPackages) {
-            if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) {
+            if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
                 // Don't allow installation over an existing package with the same name.
                 Log.w(TAG, "Attempt to re-install " + pkgName
                         + " without first uninstalling.");
@@ -3846,32 +3883,37 @@
                 return;
             }
         }
-        if (destPackageFile.exists()) {
-            // It's safe to do this because we know (from the above check) that the file
-            // isn't currently used for an installed package.
-            destPackageFile.delete();
-        }
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
-        PackageParser.Package newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
-                destResourceFile, pkg, 0,
-                SCAN_MONITOR | SCAN_FORCE_DEX
-                | SCAN_UPDATE_SIGNATURE
-                | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
-                | (newInstall ? SCAN_NEW_INSTALL : 0));
+        if (onSd) {
+            // Create secure container mount point for package
+            String cPath = createSdDir(new File(pkg.mScanPath), pkgName);
+            if (cPath == null) {
+                mLastScanError = res.returnCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+                return;
+            }
+        }
+        PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode);
         if (newPackage == null) {
-            Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
+            Log.w(TAG, "Package couldn't be installed in " + pkg.mPath);
             if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
                 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
             }
         } else {
-            updateSettingsLI(pkgName, tmpPackageFile,
-                    destFilePath, destPackageFile,
-                    destResourceFile, pkg,
-                    newPackage,
-                    true,
-                    forwardLocked,
+            File destPackageFile = new File(pkg.mPath);
+            if (destPackageFile.exists()) {
+                // It's safe to do this because we know (from the above check) that the file
+                // isn't currently used for an installed package.
+                destPackageFile.delete();
+            }
+            updateSettingsLI(newPackage,
                     installerPackageName,
                     res);
+            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+                // Check if container can be finalized
+                if(onSd && !finalizeSdDir(pkgName)) {
+                    res.returnCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+                }
+            }
             // delete the partially installed application. the data directory will have to be
             // restored if it was already existing
             if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -3885,15 +3927,19 @@
                                 res.removedInfo);
             }
         }
+        if (onSd && res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+            // Destroy cache
+            destroySdDir(pkgName);
+        }
     }
 
-    private void replacePackageLI(String pkgName,
-            File tmpPackageFile,
-            String destFilePath, File destPackageFile, File destResourceFile,
-            PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
+    private void replacePackageLI(PackageParser.Package pkg,
+            int parseFlags,
+            int scanMode,
             String installerPackageName, PackageInstalledInfo res) {
 
         PackageParser.Package oldPackage;
+        String pkgName = pkg.packageName;
         // First find the old package info and check signatures
         synchronized(mPackages) {
             oldPackage = mPackages.get(pkgName);
@@ -3905,21 +3951,15 @@
         }
         boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
         if(sysPkg) {
-            replaceSystemPackageLI(oldPackage,
-                    tmpPackageFile, destFilePath,
-                    destPackageFile, destResourceFile, pkg, forwardLocked,
-                    newInstall, installerPackageName, res);
+            replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
         } else {
-            replaceNonSystemPackageLI(oldPackage, tmpPackageFile, destFilePath,
-                    destPackageFile, destResourceFile, pkg, forwardLocked,
-                    newInstall, installerPackageName, res);
+            replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
         }
     }
 
     private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
-            File tmpPackageFile,
-            String destFilePath, File destPackageFile, File destResourceFile,
-            PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
+            PackageParser.Package pkg,
+            int parseFlags, int scanMode,
             String installerPackageName, PackageInstalledInfo res) {
         PackageParser.Package newPackage = null;
         String pkgName = deletedPackage.packageName;
@@ -3931,7 +3971,7 @@
             oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
         }
 
-        int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING;
+        parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
         // First delete the existing package while retaining the data directory
         if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
                 res.removedInfo)) {
@@ -3941,24 +3981,13 @@
         } else {
             // Successfully deleted the old package. Now proceed with re-installation
             mLastScanError = PackageManager.INSTALL_SUCCEEDED;
-            newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
-                    destResourceFile, pkg, parseFlags,
-                    SCAN_MONITOR | SCAN_FORCE_DEX
-                    | SCAN_UPDATE_SIGNATURE
-                    | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
-                    | (newInstall ? SCAN_NEW_INSTALL : 0));
+            newPackage = scanPackageLI(pkg, parseFlags, scanMode);
             if (newPackage == null) {
-                    Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
+                Log.w(TAG, "Package couldn't be installed in " + pkg.mPath);
                 if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
                     res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
-                }
-            } else {
-                updateSettingsLI(pkgName, tmpPackageFile,
-                        destFilePath, destPackageFile,
-                        destResourceFile, pkg,
-                        newPackage,
-                        true,
-                        forwardLocked,
+                }      
+                updateSettingsLI(newPackage,
                         installerPackageName,
                         res);
                 updatedSettings = true;
@@ -4028,13 +4057,12 @@
     }
 
     private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
-            File tmpPackageFile,
-            String destFilePath, File destPackageFile, File destResourceFile,
-            PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
+            PackageParser.Package pkg,
+            int parseFlags, int scanMode,
             String installerPackageName, PackageInstalledInfo res) {
         PackageParser.Package newPackage = null;
         boolean updatedSettings = false;
-        int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING |
+        parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING |
                 PackageParser.PARSE_IS_SYSTEM;
         String packageName = deletedPackage.packageName;
         res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
@@ -4064,26 +4092,14 @@
         // Successfully disabled the old package. Now proceed with re-installation
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
         pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-        newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
-                destResourceFile, pkg, parseFlags,
-                SCAN_MONITOR | SCAN_FORCE_DEX
-                | SCAN_UPDATE_SIGNATURE
-                | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
-                | (newInstall ? SCAN_NEW_INSTALL : 0));
+        newPackage = scanPackageLI(pkg, parseFlags, scanMode);
         if (newPackage == null) {
-            Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
+            Log.w(TAG, "Package couldn't be installed in " + pkg.mPath);
             if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
                 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
             }
         } else {
-            updateSettingsLI(packageName, tmpPackageFile,
-                    destFilePath, destPackageFile,
-                    destResourceFile, pkg,
-                    newPackage,
-                    true,
-                    forwardLocked,
-                    installerPackageName,
-                    res);
+            updateSettingsLI(newPackage, installerPackageName, res);
             updatedSettings = true;
         }
 
@@ -4102,9 +4118,7 @@
                 removePackageLI(newPackage, true);
             }
             // Add back the old system package
-            scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath,
-                    oldPkgSetting.resourcePath,
-                    oldPkg, parseFlags,
+            scanPackageLI(oldPkg, parseFlags,
                     SCAN_MONITOR
                     | SCAN_UPDATE_SIGNATURE);
             // Restore the old system information in Settings
@@ -4119,14 +4133,9 @@
         }
     }
 
-    private void updateSettingsLI(String pkgName, File tmpPackageFile,
-            String destFilePath, File destPackageFile,
-            File destResourceFile,
-            PackageParser.Package pkg,
-            PackageParser.Package newPackage,
-            boolean replacingExistingPackage,
-            boolean forwardLocked,
+    private void updateSettingsLI(PackageParser.Package newPackage,
             String installerPackageName, PackageInstalledInfo res) {
+        String pkgName = newPackage.packageName;
         synchronized (mPackages) {
             //write settings. the installStatus will be incomplete at this stage.
             //note that the new package setting would have already been
@@ -4136,11 +4145,10 @@
         }
 
         int retCode = 0;
-        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
-            retCode = mInstaller.movedex(tmpPackageFile.toString(),
-                    destPackageFile.toString());
+        if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+            retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath);
             if (retCode != 0) {
-                Log.e(TAG, "Couldn't rename dex file: " + destPackageFile);
+                Log.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
                 res.returnCode =  PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                 return;
             }
@@ -4148,22 +4156,25 @@
         // XXX There are probably some big issues here: upon doing
         // the rename, we have reached the point of no return (the
         // original .apk is gone!), so we can't fail.  Yet... we can.
-        if (!tmpPackageFile.renameTo(destPackageFile)) {
-            Log.e(TAG, "Couldn't move package file to: " + destPackageFile);
-            res.returnCode =  PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+        File scanFile = new File(newPackage.mScanPath);
+        if (!scanFile.renameTo(new File(newPackage.mPath))) {
+            Log.e(TAG, "Couldn't move package file: " + newPackage.mScanPath + " to: " + newPackage.mPath);
+            // TODO rename should work. Workaround
+            if (!FileUtils.copyFile(scanFile, new File(newPackage.mPath))) {
+                Log.e(TAG, "Couldn't move package file to: " + newPackage.mPath);
+                res.returnCode =  PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+            }
         } else {
-            res.returnCode = setPermissionsLI(pkgName, newPackage, destFilePath,
-                    destResourceFile,
-                    forwardLocked);
+            res.returnCode = setPermissionsLI(newPackage);
             if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
                 return;
             } else {
-                Log.d(TAG, "New package installed in " + destPackageFile);
+                Log.d(TAG, "New package installed in " + newPackage.mPath);
             }
         }
         if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
             if (mInstaller != null) {
-                mInstaller.rmdex(tmpPackageFile.getPath());
+                mInstaller.rmdex(newPackage.mScanPath);
             }
         }
 
@@ -4180,11 +4191,6 @@
         }
     }
 
-    private File getFwdLockedResource(String pkgName) {
-        final String publicZipFileName = pkgName + ".zip";
-        return new File(mAppInstallDir, publicZipFileName);
-    }
-
     private File copyTempInstallFile(Uri pPackageURI,
             PackageInstalledInfo res) {
         File tmpPackageFile = createTempPackageFile();
@@ -4246,46 +4252,29 @@
     private void installPackageLI(Uri pPackageURI,
             int pFlags, boolean newInstall, String installerPackageName,
             File tmpPackageFile, PackageInstalledInfo res) {
-        String pkgName = null;
-        boolean forwardLocked = false;
+        boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
+        boolean onSd = ((pFlags & PackageManager.INSTALL_ON_SDCARD) != 0);
         boolean replacingExistingPackage = false;
+        int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
+                | (newInstall ? SCAN_NEW_INSTALL : 0);
         // Result object to be returned
         res.returnCode = PackageManager.INSTALL_SUCCEEDED;
 
         main_flow: try {
-            pkgName = PackageParser.parsePackageName(
-                    tmpPackageFile.getAbsolutePath(), 0);
-            if (pkgName == null) {
-                Log.e(TAG, "Couldn't find a package name in : " + tmpPackageFile);
-                res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
-                break main_flow;
-            }
-            res.name = pkgName;
-            //initialize some variables before installing pkg
-            final String pkgFileName = pkgName + ".apk";
-            final File destDir = ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0)
-                                 ?  mDrmAppPrivateInstallDir
-                                 : mAppInstallDir;
-            final File destPackageFile = new File(destDir, pkgFileName);
-            final String destFilePath = destPackageFile.getAbsolutePath();
-            File destResourceFile;
-            if ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0) {
-                destResourceFile = getFwdLockedResource(pkgName);
-                forwardLocked = true;
-            } else {
-                destResourceFile = destPackageFile;
-            }
             // Retrieve PackageSettings and parse package
-            int parseFlags = PackageParser.PARSE_CHATTY;
+            int parseFlags = PackageParser.PARSE_CHATTY |
+                    (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+                    (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
             parseFlags |= mDefParseFlags;
             PackageParser pp = new PackageParser(tmpPackageFile.getPath());
             pp.setSeparateProcesses(mSeparateProcesses);
             final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
-                    destPackageFile.getAbsolutePath(), mMetrics, parseFlags);
+                    null, mMetrics, parseFlags);
             if (pkg == null) {
                 res.returnCode = pp.getParseError();
                 break main_flow;
             }
+            String pkgName = res.name = pkg.packageName;
             if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
                 if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
                     res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
@@ -4306,17 +4295,11 @@
             }
 
             if(replacingExistingPackage) {
-                replacePackageLI(pkgName,
-                        tmpPackageFile,
-                        destFilePath, destPackageFile, destResourceFile,
-                        pkg, forwardLocked, newInstall, installerPackageName,
-                        res);
+                replacePackageLI(pkg, parseFlags, scanMode,
+                        installerPackageName, res);
             } else {
-                installNewPackageLI(pkgName,
-                        tmpPackageFile,
-                        destFilePath, destPackageFile, destResourceFile,
-                        pkg, forwardLocked, newInstall, installerPackageName,
-                        res);
+                installNewPackageLI(pkg, parseFlags, scanMode,
+                        installerPackageName,res);
             }
         } finally {
             if (tmpPackageFile != null && tmpPackageFile.exists()) {
@@ -4325,13 +4308,12 @@
         }
     }
 
-    private int setPermissionsLI(String pkgName,
-            PackageParser.Package newPackage,
-            String destFilePath,
-            File destResourceFile,
-            boolean forwardLocked) {
+    private int setPermissionsLI(PackageParser.Package newPackage) {
+        String pkgName = newPackage.packageName;
         int retCode;
-        if (forwardLocked) {
+        if ((newPackage.applicationInfo.flags
+                & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) {
+            File destResourceFile = new File(newPackage.applicationInfo.publicSourceDir);
             try {
                 extractPublicFiles(newPackage, destResourceFile);
             } catch (IOException e) {
@@ -4347,25 +4329,25 @@
             } else {
                 final int filePermissions =
                         FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
-                retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1,
+                retCode = FileUtils.setPermissions(newPackage.mPath, filePermissions, -1,
                                                    newPackage.applicationInfo.uid);
             }
         } else {
             final int filePermissions =
                     FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
                     |FileUtils.S_IROTH;
-            retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1);
+            retCode = FileUtils.setPermissions(newPackage.mPath, filePermissions, -1, -1);
         }
         if (retCode != 0) {
-            Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath
+            Log.e(TAG, "Couldn't set new package file permissions for " +
+                    newPackage.mPath
                        + ". The return code was: " + retCode);
         }
         return PackageManager.INSTALL_SUCCEEDED;
     }
 
-    private boolean isForwardLocked(PackageParser.Package deletedPackage) {
-        final ApplicationInfo applicationInfo = deletedPackage.applicationInfo;
-        return applicationInfo.sourceDir.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath());
+    private boolean isForwardLocked(PackageParser.Package pkg) {
+        return  ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
     }
 
     private void extractPublicFiles(PackageParser.Package newPackage,
@@ -4643,9 +4625,9 @@
             mSettings.enableSystemPackageLP(p.packageName);
         }
         // Install the system package
-        PackageParser.Package newPkg = scanPackageLI(ps.codePath, ps.codePath, ps.resourcePath,
+        PackageParser.Package newPkg = scanPackageLI(ps.codePath,
                 PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
-                SCAN_MONITOR);
+                SCAN_MONITOR | SCAN_NO_PATHS);
 
         if (newPkg == null) {
             Log.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
@@ -4749,14 +4731,32 @@
             Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
             return false;
         }
+        boolean onSd = (p.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0;
+        // Mount sd container if needed
+        if (onSd) {
+            // TODO Better error handling from MountService api later
+            mountSdDir(p.packageName, Process.SYSTEM_UID) ;
+        }
+        boolean ret = false;
         if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
             Log.i(TAG, "Removing system package:"+p.packageName);
             // When an updated system application is deleted we delete the existing resources as well and
             // fall back to existing code in system partition
-            return deleteSystemPackageLI(p, flags, outInfo);
+            ret = deleteSystemPackageLI(p, flags, outInfo);
+        } else {
+            Log.i(TAG, "Removing non-system package:"+p.packageName);
+            ret = deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
         }
-        Log.i(TAG, "Removing non-system package:"+p.packageName);
-        return 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);
+        }
+        return ret;
     }
 
     public void clearApplicationUserData(final String packageName,
@@ -6343,22 +6343,23 @@
             return p;
         }
 
-        private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg,
-                File codePath, File resourcePath) {
+        private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) {
             p.pkg = pkg;
+            String codePath = pkg.applicationInfo.sourceDir;
+            String resourcePath = pkg.applicationInfo.publicSourceDir;
             // Update code path if needed
-            if (!codePath.toString().equalsIgnoreCase(p.codePathString)) {
+            if (!codePath.equalsIgnoreCase(p.codePathString)) {
                 Log.w(TAG, "Code path for pkg : " + p.pkg.packageName +
                         " changing from " + p.codePathString + " to " + codePath);
-                p.codePath = codePath;
-                p.codePathString = codePath.toString();
+                p.codePath = new File(codePath);
+                p.codePathString = codePath;
             }
             //Update resource path if needed
-            if (!resourcePath.toString().equalsIgnoreCase(p.resourcePathString)) {
+            if (!resourcePath.equalsIgnoreCase(p.resourcePathString)) {
                 Log.w(TAG, "Resource path for pkg : " + p.pkg.packageName +
                         " changing from " + p.resourcePathString + " to " + resourcePath);
-                p.resourcePath = resourcePath;
-                p.resourcePathString = resourcePath.toString();
+                p.resourcePath = new File(resourcePath);
+                p.resourcePathString = resourcePath;
             }
             // Update version code if needed
              if (pkg.mVersionCode != p.versionCode) {
@@ -7432,4 +7433,110 @@
                        || packageSettings.enabledComponents.contains(componentInfo.name));
         }
     }
+
+    // ------- apps on sdcard specific code -------
+    static final boolean DEBUG_SD_INSTALL = false;
+    final private String mSdEncryptKey = "none";
+
+    private MountService getMountService() {
+        return (MountService) ServiceManager.getService("mount");
+    }
+
+   private String createSdDir(File tmpPackageFile, String pkgName) {
+        // Create mount point via MountService
+        MountService mountService = getMountService();
+        long len = tmpPackageFile.length();
+        int mbLen = (int) (len/(1024*1024));
+        if ((len - (mbLen * 1024 * 1024)) > 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
+   }
 }