Merge "Add connectivity manager automation test framework:  - Create a dummy activity - ConnectivityManagerTestActivity - to listen to broadcast from connectivity manager, to control wifi, and to verify that connectivity information for different network types. This framework will be used for funcitonal tests and stress tests."
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index cfc2e75..659d70f 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -92,11 +92,6 @@
             return;
         }
 
-        if ("mountsd".equals(op)) {
-            runMountSd();
-            return;
-        }
-
         if ("uninstall".equals(op)) {
             runUninstall();
             return;
@@ -646,37 +641,6 @@
         }
     }
 
-    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;
@@ -866,7 +830,6 @@
         System.err.println("       pm path PACKAGE");
         System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] 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("");
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6d5686a..596ca9d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -980,10 +980,11 @@
             return true;
         }
 
-        case KILL_PIDS_FOR_MEMORY_TRANSACTION: {
+        case KILL_PIDS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int[] pids = data.createIntArray();
-            boolean res = killPidsForMemory(pids);
+            String reason = data.readString();
+            boolean res = killPids(pids, reason);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -2393,12 +2394,13 @@
         mRemote.transact(NOTE_WAKEUP_ALARM_TRANSACTION, data, null, 0);
         data.recycle();
     }
-    public boolean killPidsForMemory(int[] pids) throws RemoteException {
+    public boolean killPids(int[] pids, String reason) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeIntArray(pids);
-        mRemote.transact(KILL_PIDS_FOR_MEMORY_TRANSACTION, data, reply, 0);
+        data.writeString(reason);
+        mRemote.transact(KILL_PIDS_TRANSACTION, data, reply, 0);
         boolean res = reply.readInt() != 0;
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 14571de..30feae1 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -241,7 +241,7 @@
     
     public void noteWakeupAlarm(IIntentSender sender) throws RemoteException;
     
-    public boolean killPidsForMemory(int[] pids) throws RemoteException;
+    public boolean killPids(int[] pids, String reason) throws RemoteException;
     
     public void reportPss(IApplicationThread caller, int pss) throws RemoteException;
     
@@ -476,7 +476,7 @@
     int GET_PROCESSES_IN_ERROR_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+76;
     int CLEAR_APP_DATA_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+77;
     int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
-    int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
+    int KILL_PIDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
     int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
     int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
     int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 399a87d..c638d04 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -309,7 +309,7 @@
      * MountService uses this to call into the package manager to update
      * status of sdcard.
      */
-    boolean updateExternalMediaStatus(boolean mounted);
+    void updateExternalMediaStatus(boolean mounted, boolean reportStatus);
 
     String nextPackageToClean(String lastPackage);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index bbf4ca1..0318b6c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -233,7 +233,7 @@
     /**
      * Flag parameter for {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} to
      * indicate that this package should be installed as forward locked, i.e. only the app itself
-     * should have access to it's code and non-resource assets.
+     * should have access to its code and non-resource assets.
      * @hide
      */
     public static final int INSTALL_FORWARD_LOCK = 0x00000001;
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index 75455ab..4862f80 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -84,7 +84,7 @@
     int[] getStorageUsers(String path);
 
     /**
-     * Gets the state of an volume via it's mountpoint.
+     * Gets the state of a volume via its mountpoint.
      */
     String getVolumeState(String mountPoint);
 
@@ -146,4 +146,10 @@
      * Invokes call back once the shutdown is complete.
      */
     void shutdown(IMountShutdownObserver observer);
+
+    /**
+     * Call into MountService by PackageManager to notify that its done
+     * processing the media status update request.
+     */
+    void finishMediaUpdate();
 }
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index dae9187..344b390 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -527,20 +527,12 @@
      */
     private int getFileSize(String uri) {
         int size = 0;
-        Cursor cursor = mContext.getContentResolver().query(Uri.parse(uri),
-                new String[] { OpenableColumns.SIZE },
-                null,
-                null,
-                null);
-        if (cursor != null) {
-            try {
-                if (cursor.moveToNext()) {
-                    size = cursor.getInt(0);
-                }
-            } finally {
-                cursor.close();
-            }
-        }
+        try {
+            InputStream stream = mContext.getContentResolver()
+                            .openInputStream(Uri.parse(uri));
+            size = stream.available();
+            stream.close();
+        } catch (Exception e) {}
         return size;
     }
 
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 1c59c10..4f680e5 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -733,11 +733,15 @@
             ret.contentdisposition = contentDisposition;
         }
 
+        // lastModified and etag may be set back to http header. So they can't
+        // be empty string.
         String lastModified = headers.getLastModified();
-        if (lastModified != null) ret.lastModified = lastModified;
+        if (lastModified != null && lastModified.length() > 0) {
+            ret.lastModified = lastModified;
+        }
 
         String etag = headers.getEtag();
-        if (etag != null) ret.etag = etag;
+        if (etag != null && etag.length() > 0) ret.etag = etag;
 
         String cacheControl = headers.getCacheControl();
         if (cacheControl != null) {
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 4f2830b..1eb3fa4 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -397,6 +397,7 @@
                             notify();
                         }
                     }
+                    mWebView.dismissZoomControl();
                 }
                 break;
 
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 9314d7b..5345879 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -340,6 +340,15 @@
     }
 
     /**
+     * Sets the maximum size of the ApplicationCache.
+     * This should only ever be called on the WebKit thread.
+     * @hide Pending API council approval
+     */
+    public void setAppCacheMaximumSize(long size) {
+        nativeSetAppCacheMaximumSize(size);
+    }
+
+    /**
      * Utility function to send a message to our handler
      */
     private synchronized void postMessage(Message msg) {
@@ -402,4 +411,5 @@
     private static native void nativeSetQuotaForOrigin(String origin, long quota);
     private static native void nativeDeleteOrigin(String origin);
     private static native void nativeDeleteAllData();
+    private static native void nativeSetAppCacheMaximumSize(long size);
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8ce6276..cabda85 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2297,20 +2297,13 @@
         scrollBar.draw(canvas);
     }
 
-    private boolean canOverscrollHorizontally() {
-        return (Math.abs(mMinZoomScale - mMaxZoomScale) >= MINIMUM_SCALE_INCREMENT)
-                && getSettings().supportZoom()
-                && getSettings().getUseWideViewPort();
-    }
-
     @Override
     protected void onOverscrolled(int scrollX, int scrollY, boolean clampedX,
             boolean clampedY) {
         mInOverScrollMode = false;
         int maxX = computeMaxScrollX();
-        if (maxX == 0 && !canOverscrollHorizontally()) {
-            // do not over scroll x if the page just fits the screen and it
-            // can't zoom or the view doesn't use wide viewport
+        if (maxX == 0) {
+            // do not over scroll x if the page just fits the screen
             scrollX = pinLocX(scrollX);
         } else if (scrollX < 0 || scrollX > maxX) {
             mInOverScrollMode = true;
@@ -3986,8 +3979,7 @@
     protected void onDetachedFromWindow() {
         clearTextEntry(false);
         super.onDetachedFromWindow();
-        // Clean up the zoom controller
-        mZoomButtonsController.setVisible(false);
+        dismissZoomControl();
     }
 
     /**
@@ -4186,6 +4178,8 @@
             }
         }
 
+        dismissZoomControl();
+
         // onSizeChanged() is called during WebView layout. And any
         // requestLayout() is blocked during layout. As setNewZoomScale() will
         // call its child View to reposition itself through ViewManager's
@@ -4447,9 +4441,7 @@
         public boolean onScaleBegin(ScaleGestureDetector detector) {
             // cancel the single touch handling
             cancelTouch();
-            if (mZoomButtonsController.isVisible()) {
-                mZoomButtonsController.setVisible(false);
-            }
+            dismissZoomControl();
             // reset the zoom overview mode so that the page won't auto grow
             mInZoomOverview = false;
             // If it is in password mode, turn it off so it does not draw
@@ -5388,9 +5380,6 @@
                 vx = 0;
             }
         }
-        if (maxX == 0 && !canOverscrollHorizontally()) {
-            vx = 0;
-        }
         if (true /* EMG release: make our fling more like Maps' */) {
             // maps cuts their velocity in half
             vx = vx * 3 / 4;
@@ -5429,8 +5418,9 @@
         mLastVelY = vy;
         mLastVelocity = (float) Math.hypot(vx, vy);
 
+        // no horizontal overscroll if the content just fits
         mScroller.fling(mScrollX, mScrollY, -vx, -vy, 0, maxX, 0, maxY,
-                getViewWidth() / 3, getViewHeight() / 3);
+                maxX == 0 ? 0 : getViewWidth() / 3, getViewHeight() / 3);
         // TODO: duration is calculated based on velocity, if the range is
         // small, the animation will stop before duration is up. We may
         // want to calculate how long the animation is going to run to precisely
@@ -5782,6 +5772,31 @@
         }
     }
 
+    void dismissZoomControl() {
+        if (mWebViewCore == null) {
+            // maybe called after WebView's destroy(). As we can't get settings,
+            // just hide zoom control for both styles.
+            mZoomButtonsController.setVisible(false);
+            if (mZoomControls != null) {
+                mZoomControls.hide();
+            }
+            return;
+        }
+        WebSettings settings = getSettings();
+        if (settings.getBuiltInZoomControls()) {
+            if (mZoomButtonsController.isVisible()) {
+                mZoomButtonsController.setVisible(false);
+            }
+        } else {
+            if (mZoomControlRunnable != null) {
+                mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+            }
+            if (mZoomControls != null) {
+                mZoomControls.hide();
+            }
+        }
+    }
+
     // Rule for double tap:
     // 1. if the current scale is not same as the text wrap scale and layout
     //    algorithm is NARROW_COLUMNS, fit to column;
@@ -5796,20 +5811,9 @@
         mAnchorX = viewToContentX((int) mZoomCenterX + mScrollX);
         mAnchorY = viewToContentY((int) mZoomCenterY + mScrollY);
         WebSettings settings = getSettings();
-        // remove the zoom control after double tap
-        if (settings.getBuiltInZoomControls()) {
-            if (mZoomButtonsController.isVisible()) {
-                mZoomButtonsController.setVisible(false);
-            }
-        } else {
-            if (mZoomControlRunnable != null) {
-                mPrivateHandler.removeCallbacks(mZoomControlRunnable);
-            }
-            if (mZoomControls != null) {
-                mZoomControls.hide();
-            }
-        }
         settings.setDoubleTapToastCount(0);
+        // remove the zoom control after double tap
+        dismissZoomControl();
         ViewManager.ChildView plugin = mViewManager.hitTest(mAnchorX, mAnchorY);
         if (plugin != null) {
             if (isPluginFitOnScreen(plugin)) {
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 3328c13..ea99f03 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -216,9 +216,9 @@
     }
 
     /**
-     * Sets the drawable to use as the left part of the strip below the
+     * Sets the drawable to use as the right part of the strip below the
      * tab indicators.
-     * @param drawable the left strip drawable
+     * @param drawable the right strip drawable
      */
     public void setRightStripDrawable(Drawable drawable) {
         mBottomLeftStrip = drawable;
@@ -226,10 +226,10 @@
         invalidate();    }
 
     /**
-     * Sets the drawable to use as the left part of the strip below the
+     * Sets the drawable to use as the right part of the strip below the
      * tab indicators.
      * @param resId the resource identifier of the drawable to use as the
-     * left strip drawable
+     * right strip drawable
      */
     public void setRightStripDrawable(int resId) {
         mBottomLeftStrip = mContext.getResources().getDrawable(resId);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4e2caa0..a3c73d8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -732,7 +732,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_ACCESS"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_access"
         android:description="@string/permdesc_asec_access" />
 
@@ -740,7 +740,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_CREATE"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_create"
         android:description="@string/permdesc_asec_create" />
 
@@ -748,7 +748,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_DESTROY"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_destroy"
         android:description="@string/permdesc_asec_destroy" />
 
@@ -756,7 +756,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_mount_unmount"
         android:description="@string/permdesc_asec_mount_unmount" />
 
@@ -764,7 +764,7 @@
          @hide  -->
     <permission android:name="android.permission.ASEC_RENAME"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_asec_rename"
         android:description="@string/permdesc_asec_rename" />
 
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 2c5cbf6..5988d34 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -52,6 +52,7 @@
  *
  * <p>See the <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a>
  * documentation for additional help with using MediaRecorder.
+ * <p>Note: Currently, MediaRecorder does not work on the emulator.
  */
 public class MediaRecorder
 {
diff --git a/services/java/com/android/server/EntropyService.java b/services/java/com/android/server/EntropyService.java
index 0a53e9c..81ae26f 100644
--- a/services/java/com/android/server/EntropyService.java
+++ b/services/java/com/android/server/EntropyService.java
@@ -48,14 +48,15 @@
  * instead of periodically.
  */
 public class EntropyService extends Binder {
-    private static final String ENTROPY_FILENAME = getSystemDir() + "/entropy.dat";
     private static final String TAG = "EntropyService";
     private static final int ENTROPY_WHAT = 1;
     private static final int ENTROPY_WRITE_PERIOD = 3 * 60 * 60 * 1000;  // 3 hrs
-    private static final String RANDOM_DEV = "/dev/urandom";
     private static final long START_TIME = System.currentTimeMillis();
     private static final long START_NANOTIME = System.nanoTime();
 
+    private final String randomDevice;
+    private final String entropyFile;
+
     /**
      * Handler that periodically updates the entropy on disk.
      */
@@ -72,6 +73,16 @@
     };
 
     public EntropyService() {
+        this(getSystemDir() + "/entropy.dat", "/dev/urandom");
+    }
+
+    /** Test only interface, not for public use */
+    public EntropyService(String entropyFile, String randomDevice) {
+        if (randomDevice == null) { throw new NullPointerException("randomDevice"); }
+        if (entropyFile == null) { throw new NullPointerException("entropyFile"); }
+
+        this.randomDevice = randomDevice;
+        this.entropyFile = entropyFile;
         loadInitialEntropy();
         addDeviceSpecificEntropy();
         writeEntropy();
@@ -85,7 +96,7 @@
 
     private void loadInitialEntropy() {
         try {
-            RandomBlock.fromFile(ENTROPY_FILENAME).toFile(RANDOM_DEV);
+            RandomBlock.fromFile(entropyFile).toFile(randomDevice);
         } catch (IOException e) {
             Slog.w(TAG, "unable to load initial entropy (first boot?)", e);
         }
@@ -93,7 +104,7 @@
 
     private void writeEntropy() {
         try {
-            RandomBlock.fromFile(RANDOM_DEV).toFile(ENTROPY_FILENAME);
+            RandomBlock.fromFile(randomDevice).toFile(entropyFile);
         } catch (IOException e) {
             Slog.w(TAG, "unable to write entropy", e);
         }
@@ -116,7 +127,7 @@
     private void addDeviceSpecificEntropy() {
         PrintWriter out = null;
         try {
-            out = new PrintWriter(new FileOutputStream(RANDOM_DEV));
+            out = new PrintWriter(new FileOutputStream(randomDevice));
             out.println("Copyright (C) 2009 The Android Open Source Project");
             out.println("All Your Randomness Are Belong To Us");
             out.println(START_TIME);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index d50f591..d3ac026 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -135,17 +135,6 @@
     private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
     private static final int MAX_UNMOUNT_RETRIES = 4;
 
-    private IntentFilter mPmFilter = new IntentFilter(
-            Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-    private BroadcastReceiver mPmReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
-                mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
-            }
-        }
-    };
-
     class UnmountCallBack {
         String path;
         int retries;
@@ -200,49 +189,35 @@
 
     class MountServiceHandler extends Handler {
         ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
-        boolean mRegistered = false;
+        boolean mUpdatingStatus = false;
 
         MountServiceHandler(Looper l) {
             super(l);
         }
 
-        void registerReceiver() {
-            mRegistered = true;
-            if (DEBUG_UNMOUNT) Log.i(TAG, "Registering receiver");
-            mContext.registerReceiver(mPmReceiver, mPmFilter);
-        }
-
-        void unregisterReceiver() {
-            mRegistered = false;
-            if (DEBUG_UNMOUNT) Log.i(TAG, "Unregistering receiver");
-            mContext.unregisterReceiver(mPmReceiver);
-        }
-
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case H_UNMOUNT_PM_UPDATE: {
                     if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_UPDATE");
                     UnmountCallBack ucb = (UnmountCallBack) msg.obj;
                     mForceUnmounts.add(ucb);
-                    if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mRegistered);
+                    if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mUpdatingStatus);
                     // Register only if needed.
-                    if (!mRegistered) {
-                        registerReceiver();
-                        if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status");
-                        boolean hasExtPkgs = mPms.updateExternalMediaStatus(false);
-                        if (!hasExtPkgs) {
-                            // Unregister right away
-                            mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
-                        }
+                    if (!mUpdatingStatus) {
+                        if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status on PackageManager");
+                        mUpdatingStatus = true;
+                        mPms.updateExternalMediaStatus(false, true);
                     }
                     break;
                 }
                 case H_UNMOUNT_PM_DONE: {
                     if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_DONE");
-                    // Unregister now.
-                    if (mRegistered) {
-                        unregisterReceiver();
+                    if (!mUpdatingStatus) {
+                        // Does not correspond to unmount's status update.
+                        return;
                     }
+                    if (DEBUG_UNMOUNT) Log.i(TAG, "Updated status. Processing requests");
+                    mUpdatingStatus = false;
                     int size = mForceUnmounts.size();
                     int sizeArr[] = new int[size];
                     int sizeArrN = 0;
@@ -261,7 +236,7 @@
                                 ActivityManagerService ams = (ActivityManagerService)
                                 ServiceManager.getService("activity");
                                 // Eliminate system process here?
-                                boolean ret = ams.killPidsForMemory(pids);
+                                boolean ret = ams.killPids(pids, "Unmount media");
                                 if (ret) {
                                     // Confirm if file references have been freed.
                                     pids = getStorageUsers(path);
@@ -277,8 +252,8 @@
                                     ucb));
                         } else {
                             if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
-                                Log.i(TAG, "Cannot unmount inspite of " +
-                                        MAX_UNMOUNT_RETRIES + " to unmount media");
+                                Log.i(TAG, "Cannot unmount media inspite of " +
+                                        MAX_UNMOUNT_RETRIES + " retries");
                                 // Send final broadcast indicating failure to unmount.                 
                             } else {
                                 mHandler.sendMessageDelayed(
@@ -337,16 +312,23 @@
                     public void run() {
                         try {
                             String path = Environment.getExternalStorageDirectory().getPath();
-                            if (getVolumeState(
-                                    Environment.getExternalStorageDirectory().getPath()).equals(
-                                            Environment.MEDIA_UNMOUNTED)) {
+                            String state = getVolumeState(path);
+
+                            if (state.equals(Environment.MEDIA_UNMOUNTED)) {
                                 int rc = doMountVolume(path);
                                 if (rc != StorageResultCode.OperationSucceeded) {
                                     Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
                                 }
+                            } else if (state.equals(Environment.MEDIA_SHARED)) {
+                                /*
+                                 * Bootstrap UMS enabled state since vold indicates
+                                 * the volume is shared (runtime restart while ums enabled)
+                                 */
+                                notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Shared);
                             }
+
                             /*
-                             * If UMS is connected in boot, send the connected event
+                             * If UMS was connected on boot, send the connected event
                              * now that we're up.
                              */
                             if (mSendUmsConnectedOnBoot) {
@@ -405,9 +387,9 @@
         }
         // Update state on PackageManager
         if (Environment.MEDIA_UNMOUNTED.equals(state)) {
-            mPms.updateExternalMediaStatus(false);
+            mPms.updateExternalMediaStatus(false, false);
         } else if (Environment.MEDIA_MOUNTED.equals(state)) {
-            mPms.updateExternalMediaStatus(true);
+            mPms.updateExternalMediaStatus(true, false);
         }
         String oldState = mLegacyState;
         mLegacyState = state;
@@ -750,19 +732,15 @@
         if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
             return VoldResponseCode.OpFailedVolNotMounted;
         }
-
-        // We unmounted the volume. No of the asec containers are available now.
-        synchronized (mAsecMountSet) {
-            mAsecMountSet.clear();
-        }
-        // Notify PackageManager of potential media removal and deal with
-        // return code later on. The caller of this api should be aware or have been
-        // notified that the applications installed on the media will be killed.
         // Redundant probably. But no harm in updating state again.
-        mPms.updateExternalMediaStatus(false);
+        mPms.updateExternalMediaStatus(false, false);
         try {
             mConnector.doCommand(String.format(
                     "volume unmount %s%s", path, (force ? " force" : "")));
+            // We unmounted the volume. None of the asec containers are available now.
+            synchronized (mAsecMountSet) {
+                mAsecMountSet.clear();
+            }
             return StorageResultCode.OperationSucceeded;
         } catch (NativeDaemonConnectorException e) {
             // Don't worry about mismatch in PackageManager since the
@@ -1325,5 +1303,9 @@
         Log.e(TAG, "Got an empty response");
         return "";
     }
+
+    public void finishMediaUpdate() {
+        mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
+    }
 }
 
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 48b3fbb..9eb63a6 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -343,6 +343,7 @@
     static final int POST_INSTALL = 9;
     static final int MCS_RECONNECT = 10;
     static final int MCS_GIVE_UP = 11;
+    static final int UPDATED_MEDIA_STATUS = 12;
 
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
@@ -596,6 +597,13 @@
                         Slog.e(TAG, "Bogus post-install token " + msg.arg1);
                     }
                 } break;
+                case UPDATED_MEDIA_STATUS: {
+                    try {
+                        PackageHelper.getMountService().finishMediaUpdate();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "MountService not running?");
+                    }
+                } break;
             }
         }
     }
@@ -9373,10 +9381,12 @@
    }
 
    /*
-    * Return true if PackageManager does have packages to be updated.
+    * Update media status on PackageManager.
     */
-   public boolean updateExternalMediaStatus(final boolean mediaStatus) {
-       final boolean ret;
+   public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
+       if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+           throw new SecurityException("Media status can only be updated by the system");
+       }
        synchronized (mPackages) {
            Log.i(TAG, "Updating external media status from " +
                    (mMediaMounted ? "mounted" : "unmounted") + " to " +
@@ -9384,32 +9394,29 @@
            if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
                    mediaStatus+", mMediaMounted=" + mMediaMounted);
            if (mediaStatus == mMediaMounted) {
-               return false;
+               if (reportStatus) {
+                   mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
+               }
+               return;
            }
            mMediaMounted = mediaStatus;
-           Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_EXTERNAL_STORAGE);
-           ret = appList != null && appList.size() > 0;
-           if (DEBUG_SD_INSTALL) {
-               if (appList != null) {
-                   for (String app : appList) {
-                       Log.i(TAG, "Should enable " + app + " on sdcard");
-                   }
-               }
-           }
-           if (DEBUG_SD_INSTALL)  Log.i(TAG, "updateExternalMediaStatus returning " + ret);
        }
        // Queue up an async operation since the package installation may take a little while.
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
-               updateExternalMediaStatusInner(mediaStatus, ret);
+               try {
+                   updateExternalMediaStatusInner(mediaStatus);
+               } finally {
+                   if (reportStatus) {
+                       mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
+                   }
+               }
            }
        });
-       return ret;
    }
 
-   private void updateExternalMediaStatusInner(boolean mediaStatus,
-           boolean sendUpdateBroadcast) {
+   private void updateExternalMediaStatusInner(boolean mediaStatus) {
        // If we are up here that means there are packages to be
        // enabled or disabled.
        final String list[] = PackageHelper.getSecureContainerList();
@@ -9474,11 +9481,11 @@
        // Process packages with valid entries.
        if (mediaStatus) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
-           loadMediaPackages(processCids, uidArr, sendUpdateBroadcast, removeCids);
+           loadMediaPackages(processCids, uidArr, removeCids);
            startCleaningPackages();
        } else {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
-           unloadMediaPackages(processCids, uidArr, sendUpdateBroadcast);
+           unloadMediaPackages(processCids, uidArr);
        }
    }
 
@@ -9509,8 +9516,7 @@
     * to avoid unnecessary crashes.
     */
    private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
-           int uidArr[], boolean sendUpdateBroadcast,
-           HashSet<String> removeCids) {
+           int uidArr[], HashSet<String> removeCids) {
        ArrayList<String> pkgList = new ArrayList<String>();
        Set<SdInstallArgs> keys = processCids.keySet();
        boolean doGc = false;
@@ -9578,7 +9584,7 @@
            mSettings.writeLP();
        }
        // Send a broadcast to let everyone know we are done processing
-       if (sendUpdateBroadcast) {
+       if (pkgList.size() > 0) {
            sendResourcesChangedBroadcast(true, pkgList, uidArr);
        }
        if (doGc) {
@@ -9594,7 +9600,7 @@
    }
 
    private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
-           int uidArr[], boolean sendUpdateBroadcast) {
+           int uidArr[]) {
        if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
        ArrayList<String> pkgList = new ArrayList<String>();
        ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
@@ -9617,7 +9623,7 @@
            }
        }
        // Send broadcasts
-       if (sendUpdateBroadcast) {
+       if (pkgList.size() > 0) {
            sendResourcesChangedBroadcast(false, pkgList, uidArr);
        }
        // Force gc
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 93e45fc..fdb67f8 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -10755,7 +10755,7 @@
                         pids[i] = pidCandidates.keyAt(i);
                     }
                     try {
-                        if (mActivityManager.killPidsForMemory(pids)) {
+                        if (mActivityManager.killPids(pids, "Free memory")) {
                             killedApps = true;
                         }
                     } catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2ecebed..7034c88 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8359,11 +8359,11 @@
         }
     }
 
-    public boolean killPidsForMemory(int[] pids) {
+    public boolean killPids(int[] pids, String pReason) {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-            throw new SecurityException("killPidsForMemory only available to the system");
+            throw new SecurityException("killPids only available to the system");
         }
-        
+        String reason = (pReason == null) ? "Unknown" : pReason;
         // XXX Note: don't acquire main activity lock here, because the window
         // manager calls in with its locks held.
         
@@ -8387,7 +8387,7 @@
             if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
                 worstType = HIDDEN_APP_MIN_ADJ;
             }
-            Slog.w(TAG, "Killing processes for memory at adjustment " + worstType);
+            Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType);
             for (int i=0; i<pids.length; i++) {
                 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
                 if (proc == null) {
@@ -8395,10 +8395,10 @@
                 }
                 int adj = proc.setAdj;
                 if (adj >= worstType) {
-                    Slog.w(TAG, "Killing for memory: " + proc + " (adj "
+                    Slog.w(TAG, "Killing " + reason + " : " + proc + " (adj "
                             + adj + ")");
-                    EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
-                            proc.processName, adj);
+                    EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
+                            proc.processName, adj, reason);
                     killed = true;
                     Process.killProcess(pids[i]);
                 }
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags
index 0ddcc247..aadd37d 100644
--- a/services/java/com/android/server/am/EventLogTags.logtags
+++ b/services/java/com/android/server/am/EventLogTags.logtags
@@ -58,7 +58,7 @@
 # The activity's onResume has been called.
 30022 am_on_resume_called (Component Name|3)
 # Kill a process to reclaim memory.
-30023 am_kill_for_memory (PID|1|5),(Process Name|3),(OomAdj|1|5)
+30023 am_kill (PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
 # Discard an undelivered serialized broadcast (timeout/ANR/crash)
 30024 am_broadcast_discard_filter (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
 30025 am_broadcast_discard_app (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
diff --git a/services/tests/servicestests/src/com/android/server/EntropyServiceTest.java b/services/tests/servicestests/src/com/android/server/EntropyServiceTest.java
new file mode 100644
index 0000000..636ba21
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/EntropyServiceTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.os.FileUtils;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+
+/**
+ * Tests for {@link com.android.server.EntropyService}
+ */
+public class EntropyServiceTest extends AndroidTestCase {
+
+    public void testInitialWrite() throws Exception {
+        File dir = getContext().getDir("testInitialWrite", Context.MODE_PRIVATE);
+        File file = File.createTempFile("testInitialWrite", "dat", dir);
+        file.deleteOnExit();
+        assertEquals(0, FileUtils.readTextFile(file, 0, null).length());
+
+        // The constructor has the side effect of writing to file
+        new EntropyService("/dev/null", file.getCanonicalPath());
+
+        assertTrue(FileUtils.readTextFile(file, 0, null).length() > 0);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 6eea46e..d3a34ec 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -202,7 +202,7 @@
     /**
      * Supply the ICC PIN to the ICC
      *
-     * When the operation is complete, onComplete will be sent to it's
+     * When the operation is complete, onComplete will be sent to its
      * Handler.
      *
      * onComplete.obj will be an AsyncResult
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index dd7a169..6975c70 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -93,6 +93,9 @@
     protected void setUp() throws Exception {
         super.setUp();
         mOrigState = getMediaState();
+        if (!mountMedia()) {
+            Log.i(TAG, "sdcard not mounted? Some of these tests might fail");
+        }
     }
 
     @Override
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
index ce1bf8d..5780c43 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -73,6 +73,7 @@
     private static final int LAYOUT_DUMP_DATABASE_CALLBACKS = 41;
     private static final int LAYOUT_SET_CAN_OPEN_WINDOWS = 42;
     private static final int SET_GEOLOCATION_PERMISSION = 43;
+    private static final int OVERRIDE_PREFERENCE = 44;
     
     CallbackProxy(EventSender eventSender, 
             LayoutTestController layoutTestController) {
@@ -266,6 +267,12 @@
             mLayoutTestController.setGeolocationPermission(
                     msg.arg1 == 1 ? true : false);
             break;
+
+        case OVERRIDE_PREFERENCE:
+            String key = msg.getData().getString("key");
+            boolean value = msg.getData().getBoolean("value");
+            mLayoutTestController.overridePreference(key, value);
+            break;
         }
     }
 
@@ -461,6 +468,10 @@
         WebStorage.getInstance().setQuotaForOrigin("file://", quota);
     }
 
+    public void setAppCacheMaximumSize(long size) {
+        WebStorage.getInstance().setAppCacheMaximumSize(size);
+    }
+
     public void setCanOpenWindows() {
         obtainMessage(LAYOUT_SET_CAN_OPEN_WINDOWS).sendToTarget();
     }
@@ -480,4 +491,11 @@
     public void setGeolocationPermission(boolean allow) {
         obtainMessage(SET_GEOLOCATION_PERMISSION, allow ? 1 : 0, 0).sendToTarget();
     }
+
+    public void overridePreference(String key, boolean value) {
+        Message message = obtainMessage(OVERRIDE_PREFERENCE);
+        message.getData().putString("key", key);
+        message.getData().putBoolean("value", value);
+        message.sendToTarget();
+    }
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index d51d17a..d10e382 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -82,18 +82,10 @@
         // This first block of tests are for HTML5 features, for which Android
         // should pass all tests. They are skipped only temporarily.
         // TODO: Fix these failing tests and remove them from this list.
-        ignoreResultList.add("http/tests/appcache/auth.html"); // file not found
-        ignoreResultList.add("http/tests/appcache/deferred-events.html"); // file not found
-        ignoreResultList.add("http/tests/appcache/deferred-events-delete-while-raising.html"); // file not found
-        ignoreResultList.add("http/tests/appcache/destroyed-frame.html"); // file not found
-        ignoreResultList.add("http/tests/appcache/detached-iframe.html"); // file not found
-        ignoreResultList.add("http/tests/appcache/different-scheme.html"); // file not found
-        ignoreResultList.add("http/tests/appcache/disabled.html"); // not found
+        ignoreResultList.add("http/tests/appcache/auth.html"); // DumpRenderTree throws exception when authentication fails
         ignoreResultList.add("http/tests/appcache/empty-manifest.html"); // flaky
         ignoreResultList.add("http/tests/appcache/foreign-iframe-main.html"); // flaky - skips states
-        ignoreResultList.add("http/tests/appcache/max-size.html"); // no layoutTestController.setAppCacheMaximumSize
         ignoreResultList.add("http/tests/appcache/manifest-with-empty-file.html"); // flaky
-        ignoreResultList.add("http/tests/appcache/whitelist-wildcard.html"); // file not found
         ignoreResultList.add("storage/database-lock-after-reload.html"); // Succeeds but DumpRenderTree does not read result correctly
         ignoreResultList.add("storage/hash-change-with-xhr.html"); // Succeeds but DumpRenderTree does not read result correctly
 
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
index f535ed7..9236345 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
@@ -65,4 +65,6 @@
 
     // For Geolocation tests
     public void setGeolocationPermission(boolean allow);
+
+    public void overridePreference(String key, boolean value);
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 02a7046..24f58b2 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -61,6 +61,9 @@
 
     static enum DumpDataType {DUMP_AS_TEXT, EXT_REPR, NO_OP}
 
+    // String constants for use with layoutTestController.overridePreferences
+    private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED = "WebKitOfflineWebApplicationCacheEnabled";
+
     public class AsyncHandler extends Handler {
         @Override
         public void handleMessage(Message msg) {
@@ -459,6 +462,16 @@
         mGeolocationPermission = allow;
     }
 
+    public void overridePreference(String key, boolean value) {
+        // TODO: We should look up the correct WebView for the frame which
+        // called the layoutTestController method. Currently, we just use the
+        // WebView for the main frame. EventSender suffers from the same
+        // problem.
+        if (key.equals(WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED)) {
+            mWebView.getSettings().setAppCacheEnabled(value);
+        }
+    }
+
     private final WebViewClient mViewClient = new WebViewClient(){
         @Override
         public void onPageFinished(WebView view, String url) {