Merge "Re-enabling unit tests for PackageManager/Apps on SD." into froyo
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index 550cc24..f607ee9 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -79,7 +79,7 @@
             byte[] buffer = new byte[NTP_PACKET_SIZE];
             DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);
 
-            // set mode = 3 (client) and version = 3                                                                          
+            // set mode = 3 (client) and version = 3
             // mode is in low 3 bits of first byte
             // version is in bits 3-5 of first byte
             buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
@@ -90,7 +90,7 @@
             writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);
 
             socket.send(request);
-            
+
             // read the response
             DatagramPacket response = new DatagramPacket(buffer, buffer.length);
             socket.receive(response);
@@ -112,8 +112,8 @@
             //             = (transit + skew - transit + skew)/2
             //             = (2 * skew)/2 = skew
             long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2;
-            if (Config.LOGD) Log.d(TAG, "round trip: " + roundTripTime + " ms");
-            if (Config.LOGD) Log.d(TAG, "clock offset: " + clockOffset + " ms");
+            // if (Config.LOGD) Log.d(TAG, "round trip: " + roundTripTime + " ms");
+            // if (Config.LOGD) Log.d(TAG, "clock offset: " + clockOffset + " ms");
 
             // save our results - use the times on this side of the network latency
             // (response rather than request time)
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
index 6dbf325..f1ebb47 100644
--- a/core/java/android/net/http/Request.java
+++ b/core/java/android/net/http/Request.java
@@ -34,6 +34,7 @@
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
 import org.apache.http.ParseException;
 import org.apache.http.ProtocolVersion;
 
@@ -72,6 +73,10 @@
 
     int mFailCount = 0;
 
+    // This will be used to set the Range field if we retry a connection. This
+    // is http/1.1 feature.
+    private int mReceivedBytes = 0;
+
     private InputStream mBodyProvider;
     private int mBodyLength;
 
@@ -241,7 +246,6 @@
 
         StatusLine statusLine = null;
         boolean hasBody = false;
-        boolean reuse = false;
         httpClientConnection.flush();
         int statusCode = 0;
 
@@ -264,6 +268,8 @@
         if (hasBody)
             entity = httpClientConnection.receiveResponseEntity(header);
 
+        boolean supportPartialContent = v.greaterEquals(HttpVersion.HTTP_1_1);
+
         if (entity != null) {
             InputStream is = entity.getContent();
 
@@ -306,6 +312,7 @@
 
                     if (len != -1) {
                         count += len;
+                        if (supportPartialContent) mReceivedBytes += len;
                     }
                     if (len == -1 || count >= lowWater) {
                         if (HttpLog.LOGV) HttpLog.v("Request.readResponse() " + count);
@@ -324,7 +331,13 @@
                 if (HttpLog.LOGV) HttpLog.v( "readResponse() handling " + e);
             } catch(IOException e) {
                 // don't throw if we have a non-OK status code
-                if (statusCode == HttpStatus.SC_OK) {
+                if (statusCode == HttpStatus.SC_OK
+                        || statusCode == HttpStatus.SC_PARTIAL_CONTENT) {
+                    if (supportPartialContent && count > 0) {
+                        // if there is uncommited content, we should commit them
+                        // as we will continue the request
+                        mEventHandler.data(buf, count);
+                    }
                     throw e;
                 }
             } finally {
@@ -411,6 +424,15 @@
             }
             setBodyProvider(mBodyProvider, mBodyLength);
         }
+
+        if (mReceivedBytes > 0) {
+            // reset the fail count as we continue the request
+            mFailCount = 0;
+            // set the "Range" header to indicate that the retry will continue
+            // instead of restarting the request
+            HttpLog.v("*** Request.reset() to range:" + mReceivedBytes);
+            mHttpRequest.setHeader("Range", "bytes=" + mReceivedBytes + "-");
+        }
     }
 
     /**
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index f47a8d0..7f202a7 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -715,6 +715,8 @@
             
             if (mCreated) {
                 try {
+                    if (DEBUG) Log.v(TAG, "Removing window and destroying surface "
+                            + mSurfaceHolder.getSurface() + " of: " + this);
                     mSession.remove(mWindow);
                 } catch (RemoteException e) {
                 }
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 255e317..6a9218a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -386,7 +386,7 @@
 
     @Override
     public String toString() {
-        return "Surface(native-token=" + mSurfaceControl + ")";
+        return "Surface(native-token=" + mSurface + ")";
     }
 
     private Surface(Parcel source) throws OutOfResourcesException {
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index e0f8bc0..e6fa405 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -64,6 +64,7 @@
 
     // Standard HTTP status codes in a more representative format
     private static final int HTTP_OK = 200;
+    private static final int HTTP_PARTIAL_CONTENT = 206;
     private static final int HTTP_MOVED_PERMANENTLY = 301;
     private static final int HTTP_FOUND = 302;
     private static final int HTTP_SEE_OTHER = 303;
@@ -328,6 +329,17 @@
     // Does the header parsing work on the WebCore thread.
     private void handleHeaders(Headers headers) {
         if (mCancelled) return;
+
+        // Note: the headers we care in LoadListeners, like
+        // content-type/content-length, should not be updated for partial
+        // content. Just skip here and go ahead with adding data.
+        if (mStatusCode == HTTP_PARTIAL_CONTENT) {
+            // we don't support cache for partial content yet
+            WebViewWorker.getHandler().obtainMessage(
+                    WebViewWorker.MSG_REMOVE_CACHE, this).sendToTarget();
+            return;
+        }
+
         mHeaders = headers;
 
         long contentLength = headers.getContentLength();
diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java
index ece33ab..153c1c2 100644
--- a/core/java/android/webkit/ViewManager.java
+++ b/core/java/android/webkit/ViewManager.java
@@ -205,7 +205,14 @@
                 if (sView.getVisibility() == View.VISIBLE) {
                     sView.setVisibility(View.INVISIBLE);
                     sView.getHolder().setSizeFromLayout();
-                    sView.setVisibility(View.VISIBLE);
+                    // setLayoutParams() only requests the layout. If we set it
+                    // to VISIBLE now, it will use the old dimension to set the
+                    // size. Post a message to ensure that it shows the new size.
+                    mWebView.mPrivateHandler.post(new Runnable() {
+                        public void run() {
+                            sView.setVisibility(View.VISIBLE);
+                        }
+                    });
                 } else {
                     sView.getHolder().setSizeFromLayout();
                 }
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index dc952e6..19abec1 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -301,6 +301,23 @@
     }
 
     @Override
+    protected void onDraw(Canvas canvas) {
+        // onDraw should only be called for password fields.  If WebTextView is
+        // still drawing, but is no longer corresponding to a password field,
+        // remove it.
+        if (mWebView == null || !mWebView.nativeFocusCandidateIsPassword()
+                || !isSameTextField(mWebView.nativeFocusCandidatePointer())) {
+            // Although calling remove() would seem to make more sense here,
+            // changing it to not be a password field will make it not draw.
+            // Other code will make sure that it is removed completely, but this
+            // way the user will not see it.
+            setInPassword(false);
+        } else {
+            super.onDraw(canvas);
+        }
+    }
+
+    @Override
     public void onEditorAction(int actionCode) {
         switch (actionCode) {
         case EditorInfo.IME_ACTION_NEXT:
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index e2f5de4..66dad0b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -7256,13 +7256,13 @@
     private native void     nativeFindNext(boolean forward);
     /* package */ native int      nativeFocusCandidateFramePointer();
     /* package */ native boolean  nativeFocusCandidateHasNextTextfield();
-    private native boolean  nativeFocusCandidateIsPassword();
+    /* package */ native boolean  nativeFocusCandidateIsPassword();
     private native boolean  nativeFocusCandidateIsRtlText();
     private native boolean  nativeFocusCandidateIsTextInput();
     /* package */ native int      nativeFocusCandidateMaxLength();
     /* package */ native String   nativeFocusCandidateName();
     private native Rect     nativeFocusCandidateNodeBounds();
-    private native int      nativeFocusCandidatePointer();
+    /* package */ native int      nativeFocusCandidatePointer();
     private native String   nativeFocusCandidateText();
     private native int      nativeFocusCandidateTextSize();
     /**
diff --git a/docs/html/guide/developing/tools/bmgr.jd b/docs/html/guide/developing/tools/bmgr.jd
new file mode 100644
index 0000000..0353b77
--- /dev/null
+++ b/docs/html/guide/developing/tools/bmgr.jd
@@ -0,0 +1,165 @@
+page.title=bmgr
+@jd:body
+
+<!-- quickview box content here -->
+
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>bmgr quickview</h2>
+<p><code>bmgr</code> lets you inspect and control the backup/restore system on an Android device.
+
+  <h2>In this document</h2>
+  <ol>
+<li><a href="#transports">About backup transports</a></li>
+<li><a href="#restoresets">About restore sets</a></li>
+<li><a href="#backup">Forcing a backup operation</a></li>
+<li><a href="#restore">Forcing a restore operation</a></li>
+<li><a href="#other">Other commands</a></li>
+  </ol>
+
+</div>
+</div>
+
+<!-- normal page content here -->
+
+<p><code>bmgr</code> is a shell tool that developers can use to interact with the Backup Manager
+on Android devices supporting API version 8 or later.  It provides commands for inducing backup
+and restore operations on demand so that you do not need to repeatedly wipe data or take similar
+intrusive steps to test the operation of an application's backup agent.  These commands are
+accessed via the <a href="{@docRoot}guide/developing/tools/adb.html">adb</a> shell.
+
+<p>There are a couple of basic concepts used by the Backup Manager that are built into the way
+that <code>bmgr</code> operates.  These are <a href="#transports">backup transports</a> and
+<a href="#restoresets">restore sets</a>.
+
+
+<a name="transports"></a>
+<h2>About backup transports</h2>
+
+<p>A <em>backup transport</em> is the code module responsible for moving backup and restore data
+to and from some storage location.  A device can have multipe transports installed, though only
+one is active at any given time.  Transports are identified by name.  You can see what
+transports are available on your device or emulator by running the
+<code>bmgr list transports</code> command:
+
+    <pre>adb shell bmgr list transports</pre>
+
+<p>The output of this command is a list of the transports available on the device.  The currently
+active transport is flagged with a <code>*</code> character.  Transport names may look like
+component names -- for example, <code>android/com.android.internal.backup.LocalTransport</code> --
+but they need not be, and the strings are never used as direct class references.  The use of
+a component-like naming scheme is simply for purposes of preventing name collisions.
+
+<p>You can change which transport is currently active from the command line as well:
+
+    <pre>adb shell bmgr transport NAME</pre>
+
+<p>where <code>NAME</code> is one of the names as printed by the <code>bmgr list transports</code>
+command.  From this point forward, backup and restore operations will be directed through the
+newly-selected transport.  Backup state tracking is managed separately for each transport, so
+switching back and forth between them will not corrupt the saved state.
+
+
+<a name="restoresets"></a>
+<h2>About restore sets</h2>
+
+<p>All of the application data that a device has written to a given backup transport is tracked
+together, and is collectively sometimes called a <em>restore set,</em> because the typical use
+of the data set is during restore operations.  Each time a device is initially provisioned, a
+new data set is established.  The user can get a listing of all the data sets that can be
+restored through the current transport by running this shell command:
+
+    <pre>adb shell bmgr list sets</pre>
+
+<p>The output is listing of available restore sets, one per line.  The first item on each line is
+a <em>token,</em> a number in hexadecimal that identifies the restore set to the transport.  After
+that is a string that may provide some brief identifying information about the restore set.  Only
+the token is actually used within the backup and restore mechanism.
+
+
+<a name="backup"></a>
+<h2>Forcing a backup operation</h2>
+
+<p>Normally, applications notify the backup manager directly that their data has changed, in
+response to which the backup manager will make sure to invoke that application's agent when the
+next backup operation is run.  You can simulate this manually from the command line if you wish,
+by running this shell command:
+
+    <pre>adb shell bmgr backup PACKAGE</pre>
+
+<p><code>PACKAGE</code> is the formal package name of the application you wish to schedule for
+backup.  At this point you know that the application's agent will be invoked for backup at some
+point in the future, though there is no hard guarantee of when that will occur.  You can force
+all pending backup operations to run immediately by using the following command:
+
+    <pre>adb shell bmgr run</pre>
+
+<p>This causes a backup pass to execute immediately, invoking the agents of all applications that
+had called <code>BackupManager.dataChanged()</code> since the time of the last backup operation,
+plus any applications which had been manually scheduled for backup via
+<code>bmgr backup PACKAGE</code>.
+
+
+<a name="restore"></a>
+<h2>Forcing a restore operation</h2>
+
+<p>Unlike backup operations, which are batched together and run on an occasional basis, restore
+operations execute immediately.  The backup manager currently provides two kinds of restore
+operations.  The first restores an entire device with the data from a given restore set.  This
+is typically only performed when a device is first provisioned, to replicate settings and other
+such saved state from the user's previous device.  The second kind of restore operation restores
+a single application from the <em>active</em> data set; that is, from the data set currently
+being written to by backup operations.  This second form is available as part of the public API.
+It allows applications to abandon their current data and revert to the last-known-good data as
+represented in their current backup image.
+
+<p>A full-system restore operation can be initiated with this shell command:
+
+    <pre>adb shell bmgr restore TOKEN</pre>
+
+<p>where <code>TOKEN</code> is the desired restore set's token as printed out by the <code>bmgr
+list sets</code> command.  <strong>Warning!</strong>  This operation will <em>replace</em> the
+data of all backup-enabled applications with the contents of the given restore set.  Be careful,
+and be aware of the potential consequences.
+
+<p>A single-application restore operation does not reference a restore set token; it always uses
+the data from the currently active data set.  You can induce such an operation from the command
+line like this:
+
+    <pre>adb shell bmgr restore PACKAGE</pre>
+
+<p><code>PACKAGE</code> is the formal package name of an application that is participating in the
+backup/restore mechanism.  The backup manager will immediately instantiate the application's
+agent and invoke it for restore.
+
+<a name="other"></a>
+<h2>Other commands</h2>
+
+<p>The data for a single application can be erased from the active data set on demand.  This is
+very useful during development of backup agents, in case bugs lead you to write corrupt data
+or saved state information.  The shell command for wiping an application's data is this:
+
+    <pre>adb shell bmgr wipe PACKAGE</pre>
+
+<p><code>PACKAGE</code> is the formal package name of the application whose data you wish to
+erase.  The next backup operation that the application's agent processes will look as
+though the application had never backed anything up before.
+
+<p>You can see whether the backup manager is operational at all by running this command:
+
+    <pre>adb shell bmgr enabled</pre>
+
+<p>This might be useful if your application's agent is never being invoked for backup, to verify
+whether the operating system thinks it should be performing such operations at all.  You can also
+directly disable or enable the backup manager with this command:
+
+    <pre>adb shell bmgr enable BOOLEAN</pre>
+
+<p>where <code>BOOLEAN</code> is either <code>true</code> or <code>false</code>.  This is
+equivalent to disabling or enabling backup in the device's main Settings UI.
+<strong>Warning!</strong>  When backup is disabled, the current transport will explicitly wipe
+the entire active data set from its backend storage.  This is so that when a user says that no,
+they do not want their data backed up, the backup manager respects that wish.  No further data
+will be saved from the device, and no restore operations will be possible, unless the backup
+manager is re-enabled (either through Settings or through the above <code>bmgr</code> command).
+
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index fd163f6..269e807 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -282,6 +282,7 @@
       <!--<li><a href="<?cs var:toroot ?>guide/developing/tools/adt.html">ADT Plugin</a></li>-->
       		<li><a href="<?cs var:toroot ?>guide/developing/tools/aidl.html">aidl</a></li>
       		<li><a href="<?cs var:toroot ?>guide/developing/tools/avd.html">AVDs</a></li>
+      		<li><a href="<?cs var:toroot ?>guide/developing/tools/bmgr.html">bmgr</a></li>
       		<li><a href="<?cs var:toroot ?>guide/developing/tools/ddms.html">ddms</a></li>
       		<li><a href="<?cs var:toroot ?>guide/developing/tools/othertools.html#dx">dx</a></li>
       		<li><a href="<?cs var:toroot ?>guide/developing/tools/draw9patch.html">Draw 9-Patch</a></li>
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 79c8f9a..6eaf0cc 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -416,7 +416,7 @@
                 return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
             }
         }
-        if (checkExt || checkBoth && !mediaAvailable) {
+        if ((checkExt || checkBoth) && !mediaAvailable) {
             return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;
         }
         return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 91dfaf3..d67dde0 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -479,10 +479,25 @@
         // Attach to the Google backup transport.  When this comes up, it will set
         // itself as the current transport because we explicitly reset mCurrentTransport
         // to null.
-        Intent intent = new Intent().setComponent(new ComponentName(
-                "com.google.android.backup",
-                "com.google.android.backup.BackupTransportService"));
-        context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
+        ComponentName transportComponent = new ComponentName("com.google.android.backup",
+                "com.google.android.backup.BackupTransportService");
+        try {
+            // If there's something out there that is supposed to be the Google
+            // backup transport, make sure it's legitimately part of the OS build
+            // and not an app lying about its package name.
+            ApplicationInfo info = mPackageManager.getApplicationInfo(
+                    transportComponent.getPackageName(), 0);
+            if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                if (DEBUG) Slog.v(TAG, "Binding to Google transport");
+                Intent intent = new Intent().setComponent(transportComponent);
+                context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
+            } else {
+                Slog.w(TAG, "Possible Google transport spoof: ignoring " + info);
+            }
+        } catch (PackageManager.NameNotFoundException nnf) {
+            // No such package?  No binding.
+            if (DEBUG) Slog.v(TAG, "Google transport not present");
+        }
 
         // Now that we know about valid backup participants, parse any
         // leftover journal files into the pending backup set
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 4d2d2f9..2fe7420 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -68,12 +68,14 @@
     private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
 
     private static final String TAG = "ThrottleService";
-    private static boolean DBG = true;
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
     private Handler mHandler;
     private HandlerThread mThread;
 
     private Context mContext;
 
+    private static final int INITIAL_POLL_DELAY_SEC = 90;
     private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
     private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
     private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
@@ -330,6 +332,12 @@
 
             // get policy
             mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
+
+            // if we poll now we won't have network connectivity or even imsi access
+            // queue up a poll to happen in a little while - after ntp and imsi are avail
+            // TODO - make this callback based (ie, listen for notificaitons)
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM),
+                    INITIAL_POLL_DELAY_SEC * 1000);
         }
 
         // check for new policy info (threshold limit/value/etc)
@@ -383,6 +391,9 @@
                     ", resetDay=" + mPolicyResetDay + ", noteType=" +
                     mPolicyNotificationsAllowedMask);
 
+            // force updates
+            mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
+
             onResetAlarm();
 
             onPollAlarm();
@@ -424,7 +435,7 @@
             long periodTx = mRecorder.getPeriodTx(0);
             long total = periodRx + periodTx;
             if (DBG) {
-                Slog.d(TAG, "onPollAlarm - now =" + now + ", roaming =" + roaming +
+                Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
                         ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
             }
             mLastRead += incRead;
@@ -482,6 +493,7 @@
 
                 } // else already up!
             } else {
+                clearThrottleAndNotification();
                 if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
                     // check if we should warn about throttle
                     // pretend we only have 1/2 the time remaining that we actually do
@@ -558,9 +570,9 @@
                 Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
                 broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
                 mContext.sendStickyBroadcast(broadcast);
+                mNotificationManager.cancel(R.drawable.stat_sys_throttled);
+                mWarningNotificationSent = false;
             }
-            mNotificationManager.cancel(R.drawable.stat_sys_throttled);
-            mWarningNotificationSent = false;
         }
 
         private Calendar calculatePeriodEnd(long now) {
@@ -619,7 +631,6 @@
                 Calendar start = calculatePeriodStart(end);
 
                 if (mRecorder.setNextPeriod(start, end)) {
-                    clearThrottleAndNotification();
                     onPollAlarm();
                 }
 
@@ -653,6 +664,7 @@
             if (mNtpActive) {
                 long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
                 if (ntpAge < MAX_NTP_CACHE_AGE) {
+                    if (VDBG) Slog.v(TAG, "using cached time");
                     return cachedNtp + ntpAge;
                 }
             }
@@ -665,12 +677,12 @@
                     if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
                     mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
                 }
-                if (DBG) Slog.d(TAG, "using Authoritative time: " + cachedNtp);
+                if (VDBG) Slog.v(TAG, "using Authoritative time: " + cachedNtp);
                 return cachedNtp;
             }
         }
         long time = System.currentTimeMillis();
-        if (DBG) Slog.d(TAG, "using User time: " + time);
+        if (VDBG) Slog.v(TAG, "using User time: " + time);
         mNtpActive = false;
         return time;
     }
@@ -718,15 +730,14 @@
             // TODO - how would we deal with a dual-IMSI device?
             checkForSubscriberId();
             boolean startNewPeriod = true;
-            if (DBG) {
-                Slog.d(TAG, "setting next period to " + start.getTimeInMillis() +
-                        " --until-- " + end.getTimeInMillis());
-            }
+
             // if we rolled back in time, toss out
             // if we rolled foward, advance to the next
             if (end.before(mPeriodStart)) {
                 if (DBG) {
-                    Slog.d(TAG, " old start was " + mPeriodStart.getTimeInMillis() + ", wiping");
+                    Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
+                        end.getTimeInMillis() + ") - old start was " +
+                        mPeriodStart.getTimeInMillis() + ", wiping");
                 }
                 synchronized (mParent) {
                     mPeriodRxData[mCurrentPeriod] = 0;
@@ -734,7 +745,9 @@
                 }
             } else if(start.after(mPeriodEnd)) {
                 if (DBG) {
-                    Slog.d(TAG, " old end was " + mPeriodEnd.getTimeInMillis() + ", following");
+                    Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
+                            end.getTimeInMillis() + ") - old end was " +
+                            mPeriodEnd.getTimeInMillis() + ", following");
                 }
                 synchronized (mParent) {
                     ++mCurrentPeriod;
@@ -744,7 +757,10 @@
                 }
             } else {
                 startNewPeriod = false;
-                if (DBG) Slog.d(TAG, " we fit - ammending to last period");
+                if (DBG) {
+                    Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
+                            end.getTimeInMillis() + ") - we fit - ammending to last period");
+                }
             }
             setPeriodStart(start);
             setPeriodEnd(end);
@@ -813,7 +829,7 @@
             File dataFile;
             if (mImsi == null) {
                 dataFile = useMRUFile(throttleDir);
-                Slog.d(TAG, "imsi not available yet, using " + dataFile);
+                if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
             } else {
                 String imsiHash = Integer.toString(mImsi.hashCode());
                 dataFile = new File(throttleDir, imsiHash);
@@ -831,7 +847,7 @@
             mImsi = mTelephonyManager.getSubscriberId();
             if (mImsi == null) return;
 
-            Slog.d(TAG, "finally have imsi - retreiving data");
+            if (DBG) Slog.d(TAG, "finally have imsi - retreiving data");
             retrieve();
         }
 
@@ -841,7 +857,7 @@
             File[] files = dir.listFiles();
 
             if (files.length <= MAX_SIMS_SUPPORTED) return;
-            Slog.d(TAG, "Too many data files");
+            if (DBG) Slog.d(TAG, "Too many data files");
             do {
                 File oldest = null;
                 for (File f : files) {
@@ -850,7 +866,7 @@
                     }
                 }
                 if (oldest == null) return;
-                Slog.d(TAG, " deleting " + oldest);
+                if (DBG) Slog.d(TAG, " deleting " + oldest);
                 oldest.delete();
                 files = dir.listFiles();
             } while (files.length > MAX_SIMS_SUPPORTED);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 657b6af..53de7d9 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -7580,15 +7580,17 @@
                 while (i > 0) {
                     i--;
                     WindowState c = (WindowState)mChildWindows.get(i);
-                    if (c.mSurface != null && c.mAttachedHidden) {
+                    if (c.mAttachedHidden) {
                         c.mAttachedHidden = false;
-                        c.performShowLocked();
-                        // It hadn't been shown, which means layout not
-                        // performed on it, so now we want to make sure to
-                        // do a layout.  If called from within the transaction
-                        // loop, this will cause it to restart with a new
-                        // layout.
-                        mLayoutNeeded = true;
+                        if (c.mSurface != null) {
+                            c.performShowLocked();
+                            // It hadn't been shown, which means layout not
+                            // performed on it, so now we want to make sure to
+                            // do a layout.  If called from within the transaction
+                            // loop, this will cause it to restart with a new
+                            // layout.
+                            mLayoutNeeded = true;
+                        }
                     }
                 }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7e095b5..436bd17 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -315,6 +315,11 @@
     // without empty apps being able to push them out of memory.
     static final int MIN_HIDDEN_APPS = 2;
     
+    // The maximum number of hidden processes we will keep around before
+    // killing them; this is just a control to not let us go too crazy with
+    // keeping around processes on devices with large amounts of RAM.
+    static final int MAX_HIDDEN_APPS = 15;
+    
     // We put empty content processes after any hidden processes that have
     // been idle for less than 30 seconds.
     static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
@@ -8488,8 +8493,7 @@
                 }
                 int adj = proc.setAdj;
                 if (adj >= worstType) {
-                    Slog.w(TAG, "Killing " + reason + " : " + proc + " (adj "
-                            + adj + ")");
+                    Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
                     EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
                             proc.processName, adj, reason);
                     killed = true;
@@ -8904,9 +8908,10 @@
             }
             if (app.pid > 0 && app.pid != MY_PID) {
                 handleAppCrashLocked(app);
-                Slog.i(ActivityManagerService.TAG, "Killing process "
-                        + app.processName
-                        + " (pid=" + app.pid + ") at user's request");
+                Slog.i(ActivityManagerService.TAG, "Killing "
+                        + app.processName + " (pid=" + app.pid + "): user's request");
+                EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                        app.processName, app.setAdj, "user's request after error");
                 Process.killProcess(app.pid);
             }
         }
@@ -10434,10 +10439,11 @@
             if (!capp.persistent && capp.thread != null
                     && capp.pid != 0
                     && capp.pid != MY_PID) {
-                Slog.i(TAG, "Killing app " + capp.processName
-                        + " (pid " + capp.pid
-                        + ") because provider " + cpr.info.name
-                        + " is in dying process " + proc.processName);
+                Slog.i(TAG, "Kill " + capp.processName
+                        + " (pid " + capp.pid + "): provider " + cpr.info.name
+                        + " in dying process " + proc.processName);
+                EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
+                        capp.processName, capp.setAdj, "dying provider " + proc.processName);
                 Process.killProcess(capp.pid);
             }
         }
@@ -11522,6 +11528,7 @@
                     if (r.isForeground) {
                         r.isForeground = false;
                         if (r.app != null) {
+                            updateLruProcessLocked(r.app, false, true);
                             updateServiceForegroundLocked(r.app, true);
                         }
                     }
@@ -14244,6 +14251,7 @@
         int factor = (mLruProcesses.size()-4)/numSlots;
         if (factor < 1) factor = 1;
         int step = 0;
+        int numHidden = 0;
         
         // First try updating the OOM adjustment for each of the
         // application processes based on their current state.
@@ -14262,6 +14270,17 @@
                         curHiddenAdj++;
                     }
                 }
+                if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
+                    numHidden++;
+                    if (numHidden > MAX_HIDDEN_APPS) {
+                        Slog.i(TAG, "Kill " + app.processName
+                                + " (pid " + app.pid + "): hidden #" + numHidden
+                                + " beyond limit " + MAX_HIDDEN_APPS);
+                        EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                                app.processName, app.setAdj, "too many background");
+                        Process.killProcess(app.pid);
+                    }
+                }
             } else {
                 didOomAdj = false;
             }
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 3c2f2ed..af6c5f8 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -21,6 +21,7 @@
 import java.util.Arrays;
 
 import static android.telephony.SmsMessage.MessageClass;
+import android.provider.Telephony;
 
 /**
  * Base class declaring the specific methods and members for SmsMessage.
@@ -386,7 +387,7 @@
          if (parts.length < 2) return;
          emailFrom = parts[0];
          emailBody = parts[1];
-         isEmail = true;
+         isEmail = Telephony.Mms.isEmailAddress(emailFrom);
     }
 
 }