Merge "Fix for bug 2672749: StringIndexOutOfBoundsException in Uri.getQueryParameter" into froyo
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 4887783..5640a06 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -747,6 +747,24 @@
      */
     public static final native void sendSignal(int pid, int signal);
     
+    /**
+     * @hide
+     * Private impl for avoiding a log message...  DO NOT USE without doing
+     * your own log, or the Android Illuminati will find you some night and
+     * beat you up.
+     */
+    public static final void killProcessQuiet(int pid) {
+        sendSignalQuiet(pid, SIGNAL_KILL);
+    }
+
+    /**
+     * @hide
+     * Private impl for avoiding a log message...  DO NOT USE without doing
+     * your own log, or the Android Illuminati will find you some night and
+     * beat you up.
+     */
+    public static final native void sendSignalQuiet(int pid, int signal);
+    
     /** @hide */
     public static final native long getFreeMemory();
     
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6b316ce..f921caa 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -30,10 +30,12 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Interpolator;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Picture;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
@@ -1994,6 +1996,23 @@
     }
 
     /**
+     * Given a x coordinate in view space, convert it to content space.
+     * Returns the result as a float.
+     */
+    private float viewToContentXf(int x) {
+        return x * mInvActualScale;
+    }
+
+    /**
+     * Given a y coordinate in view space, convert it to content space.
+     * Takes into account the height of the title bar if there is one
+     * embedded into the WebView. Returns the result as a float.
+     */
+    private float viewToContentYf(int y) {
+        return (y - getTitleHeight()) * mInvActualScale;
+    }
+
+    /**
      * Given a distance in content space, convert it to view space. Note: this
      * does not reflect translation, just scaling, so this should not be called
      * with coordinates, but should be called for dimensions like width or
@@ -2230,6 +2249,24 @@
         r.bottom = Math.min(viewToContentY(r.bottom), mContentHeight);
     }
 
+    // Sets r to be our visible rectangle in content coordinates. We use this
+    // method on the native side to compute the position of the fixed layers.
+    // Uses floating coordinates (necessary to correctly place elements when
+    // the scale factor is not 1)
+    private void calcOurContentVisibleRectF(RectF r) {
+        Rect ri = new Rect(0,0,0,0);
+        calcOurVisibleRect(ri);
+        // pin the rect to the bounds of the content
+        r.left = Math.max(viewToContentXf(ri.left), 0.0f);
+        // viewToContentY will remove the total height of the title bar.  Add
+        // the visible height back in to account for the fact that if the title
+        // bar is partially visible, the part of the visible rect which is
+        // displaying our content is displaced by that amount.
+        r.top = Math.max(viewToContentYf(ri.top + getVisibleTitleHeight()), 0.0f);
+        r.right = Math.min(viewToContentXf(ri.right), (float)mContentWidth);
+        r.bottom = Math.min(viewToContentYf(ri.bottom), (float)mContentHeight);
+    }
+
     static class ViewSizeData {
         int mWidth;
         int mHeight;
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index e84f2e5..68be741 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -311,8 +311,8 @@
             sprintf(text, "%d", adj);
             write(fd, text, strlen(text));
             close(fd);
-            return true;
         }
+        return true;
     }
 #endif
     return false;
@@ -797,6 +797,13 @@
     }
 }
 
+void android_os_Process_sendSignalQuiet(JNIEnv* env, jobject clazz, jint pid, jint sig)
+{
+    if (pid > 0) {
+        kill(pid, sig);
+    }
+}
+
 static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
 {
     struct timespec ts;
@@ -854,6 +861,7 @@
     {"setUid", "(I)I", (void*)android_os_Process_setUid},
     {"setGid", "(I)I", (void*)android_os_Process_setGid},
     {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
+    {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
     {"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
     {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
     {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 706e15a..948d292 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -321,12 +321,12 @@
     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;
+    // been idle for less than 15 seconds.
+    static final long CONTENT_APP_IDLE_OFFSET = 15*1000;
     
     // We put empty content processes after any hidden processes that have
-    // been idle for less than 60 seconds.
-    static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
+    // been idle for less than 120 seconds.
+    static final long EMPTY_APP_IDLE_OFFSET = 120*1000;
     
     static {
         // These values are set in system/rootdir/init.rc on startup.
@@ -880,6 +880,11 @@
     int mAdjSeq = 0;
 
     /**
+     * Current sequence id for process LRU updating.
+     */
+    int mLruSeq = 0;
+    
+    /**
      * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
      * is set, indicating the user wants processes started in such a way
      * that they can use ANDROID_PROCESS_WRAPPER and know what will be
@@ -1588,8 +1593,8 @@
         }
     }
 
-    private final void updateLruProcessLocked(ProcessRecord app,
-            boolean oomAdj, boolean updateActivityTime) {
+    private final void updateLruProcessInternalLocked(ProcessRecord app,
+            boolean oomAdj, boolean updateActivityTime, int bestPos) {
         // put it on the LRU to keep track of when it should be exited.
         int lrui = mLruProcesses.indexOf(app);
         if (lrui >= 0) mLruProcesses.remove(lrui);
@@ -1597,6 +1602,8 @@
         int i = mLruProcesses.size()-1;
         int skipTop = 0;
         
+        app.lruSeq = mLruSeq;
+        
         // compute the new weight for this process.
         if (updateActivityTime) {
             app.lastActivityTime = SystemClock.uptimeMillis();
@@ -1619,6 +1626,7 @@
             // Also don't let it kick out the first few "real" hidden processes.
             skipTop = MIN_HIDDEN_APPS;
         }
+        
         while (i >= 0) {
             ProcessRecord p = mLruProcesses.get(i);
             // If this app shouldn't be in front of the first N background
@@ -1626,7 +1634,7 @@
             if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
                 skipTop--;
             }
-            if (p.lruWeight <= app.lruWeight){
+            if (p.lruWeight <= app.lruWeight || i < bestPos) {
                 mLruProcesses.add(i+1, app);
                 break;
             }
@@ -1636,12 +1644,39 @@
             mLruProcesses.add(0, app);
         }
         
+        // If the app is currently using a content provider or service,
+        // bump those processes as well.
+        if (app.connections.size() > 0) {
+            for (ConnectionRecord cr : app.connections) {
+                if (cr.binding != null && cr.binding.service != null
+                        && cr.binding.service.app != null
+                        && cr.binding.service.app.lruSeq != mLruSeq) {
+                    updateLruProcessInternalLocked(cr.binding.service.app, oomAdj,
+                            updateActivityTime, i+1);
+                }
+            }
+        }
+        if (app.conProviders.size() > 0) {
+            for (ContentProviderRecord cpr : app.conProviders.keySet()) {
+                if (cpr.app != null && cpr.app.lruSeq != mLruSeq) {
+                    updateLruProcessInternalLocked(cpr.app, oomAdj,
+                            updateActivityTime, i+1);
+                }
+            }
+        }
+        
         //Slog.i(TAG, "Putting proc to front: " + app.processName);
         if (oomAdj) {
             updateOomAdjLocked();
         }
     }
 
+    private final void updateLruProcessLocked(ProcessRecord app,
+            boolean oomAdj, boolean updateActivityTime) {
+        mLruSeq++;
+        updateLruProcessInternalLocked(app, oomAdj, updateActivityTime, 0);
+    }
+    
     private final boolean updateLRUListLocked(HistoryRecord r) {
         final boolean hadit = mLRUActivities.remove(r);
         mLRUActivities.add(r);
@@ -4677,8 +4712,10 @@
         // Clean up already done if the process has been re-started.
         if (app.pid == pid && app.thread != null &&
                 app.thread.asBinder() == thread.asBinder()) {
-            Slog.i(TAG, "Process " + app.processName + " (pid " + pid
-                    + ") has died.");
+            if (!app.killedBackground) {
+                Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+                        + ") has died.");
+            }
             EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
             if (localLOGV) Slog.v(
                 TAG, "Dying app: " + app + ", pid: " + pid
@@ -7826,6 +7863,13 @@
                 }
 
                 if (cpr.app != null) {
+                    if (r.setAdj >= VISIBLE_APP_ADJ) {
+                        // If this is a visible app accessing the provider,
+                        // make sure to count it as being accessed and thus
+                        // back up on the LRU list.  This is good because
+                        // content providers are often expensive to start.
+                        updateLruProcessLocked(cpr.app, false, true);
+                    }
                     updateOomAdjLocked(cpr.app);
                 }
 
@@ -8492,12 +8536,13 @@
                     continue;
                 }
                 int adj = proc.setAdj;
-                if (adj >= worstType) {
+                if (adj >= worstType && !proc.killedBackground) {
                     Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
                     EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
                             proc.processName, adj, reason);
                     killed = true;
-                    Process.killProcess(pids[i]);
+                    proc.killedBackground = true;
+                    Process.killProcessQuiet(pids[i]);
                 }
             }
         }
@@ -9829,6 +9874,7 @@
                     + " mFactoryTest=" + mFactoryTest);
             pw.println("  mGoingToSleep=" + mGoingToSleep);
             pw.println("  mLaunchingActivity=" + mLaunchingActivity);
+            pw.println("  mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq);
         }
         
         return true;
@@ -14292,13 +14338,12 @@
                     if (!app.killedBackground) {
                         numHidden++;
                         if (numHidden > MAX_HIDDEN_APPS) {
-                            Slog.i(TAG, "Kill " + app.processName
-                                    + " (pid " + app.pid + "): hidden #" + numHidden
-                                    + " beyond limit " + MAX_HIDDEN_APPS);
+                            Slog.i(TAG, "No longer want " + app.processName
+                                    + " (pid " + app.pid + "): hidden #" + numHidden);
                             EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
                                     app.processName, app.setAdj, "too many background");
                             app.killedBackground = true;
-                            Process.killProcess(app.pid);
+                            Process.killProcessQuiet(app.pid);
                         }
                     }
                 }
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 7620468..f49a182 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -66,7 +66,8 @@
     boolean bad;                // True if disabled in the bad process list
     boolean killedBackground;   // True when proc has been killed due to too many bg
     IBinder forcingToForeground;// Token that is forcing this process to be foreground
-    int adjSeq;                 // Sequence id for identifying repeated trav
+    int adjSeq;                 // Sequence id for identifying oom_adj assignment cycles
+    int lruSeq;                 // Sequence id for identifying LRU update cycles
     ComponentName instrumentationClass;// class installed to instrument app
     ApplicationInfo instrumentationInfo; // the application being instrumented
     String instrumentationProfileFile; // where to save profiling
@@ -175,6 +176,8 @@
         pw.print(prefix); pw.print("persistent="); pw.print(persistent);
                 pw.print(" removed="); pw.print(removed);
                 pw.print(" persistentActivities="); pw.println(persistentActivities);
+        pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
+                pw.print(" lruSeq="); pw.println(lruSeq);
         if (killedBackground) {
             pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground);
         }