Merge "Fix various issues in ordering of grouped bindings."
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 6f0b6c8..c7a9d99 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1731,8 +1731,11 @@
             throw new IllegalArgumentException("connection is null");
         }
         if (mPackageInfo != null) {
-            IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
-                    getOuterContext(), conn);
+            IServiceConnection sd = mPackageInfo.lookupServiceDispatcher(conn, getOuterContext());
+            if (sd == null) {
+                throw new IllegalArgumentException("ServiceConnection not currently bound: "
+                        + conn);
+            }
             try {
                 ActivityManager.getService().updateServiceGroup(sd, group, importance);
             } catch (RemoteException e) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 719bba0..759763b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1659,6 +1659,19 @@
         }
     }
 
+    @UnsupportedAppUsage
+    public IServiceConnection lookupServiceDispatcher(ServiceConnection c,
+            Context context) {
+        synchronized (mServices) {
+            LoadedApk.ServiceDispatcher sd = null;
+            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
+            if (map != null) {
+                sd = map.get(c);
+            }
+            return sd != null ? sd.getIServiceConnection() : null;
+        }
+    }
+
     public final IServiceConnection forgetServiceDispatcher(Context context,
             ServiceConnection c) {
         synchronized (mServices) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fe11acb..e2c7b85 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3003,6 +3003,11 @@
      * how the process will be managed in some cases based on those flags.  Currently only
      * works on isolated processes (will be ignored for non-isolated processes).
      *
+     * <p>Note that this call does not take immediate effect, but will be applied the next
+     * time the impacted process is adjusted for some other reason.  Typically you would
+     * call this before then calling a new {@link #bindIsolatedService} on the service
+     * of interest, with that binding causing the process to be shuffled accordingly.</p>
+     *
      * @param conn The connection interface previously supplied to bindService().  This
      *             parameter must not be null.
      * @param group A group to put this connection's process in.  Upon calling here, this
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 98a135f..07d6e47 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1303,7 +1303,7 @@
     /** {@hide} */
     public void writeToProto(ProtoOutputStream proto, long fieldId, int dumpFlags) {
         long token = proto.start(fieldId);
-        super.writeToProto(proto, ApplicationInfoProto.PACKAGE);
+        super.writeToProto(proto, ApplicationInfoProto.PACKAGE, dumpFlags);
         proto.write(ApplicationInfoProto.PERMISSION, permission);
         proto.write(ApplicationInfoProto.PROCESS_NAME, processName);
         proto.write(ApplicationInfoProto.UID, uid);
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index cdb7814..ff7b347 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -433,18 +433,18 @@
     /**
      * @hide
      */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void writeToProto(ProtoOutputStream proto, long fieldId, int dumpFlags) {
         long token = proto.start(fieldId);
         if (name != null) {
             proto.write(PackageItemInfoProto.NAME, name);
         }
         proto.write(PackageItemInfoProto.PACKAGE_NAME, packageName);
-        if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) {
-            proto.write(PackageItemInfoProto.LABEL_RES, labelRes);
+        proto.write(PackageItemInfoProto.LABEL_RES, labelRes);
+        if (nonLocalizedLabel != null) {
             proto.write(PackageItemInfoProto.NON_LOCALIZED_LABEL, nonLocalizedLabel.toString());
-            proto.write(PackageItemInfoProto.ICON, icon);
-            proto.write(PackageItemInfoProto.BANNER, banner);
         }
+        proto.write(PackageItemInfoProto.ICON, icon);
+        proto.write(PackageItemInfoProto.BANNER, banner);
         proto.end(token);
     }
 
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index ab50ad1..60561bd 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -185,6 +185,7 @@
     optional int32 app_id = 5;
     optional int32 isolated_app_id = 6;
     optional bool persistent = 7;
+    optional int32 lru_index = 8;
 }
 
 message BroadcastRecordProto {
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
index 8cd9d188..15de3de 100644
--- a/services/core/java/com/android/server/am/ActiveInstrumentation.java
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -133,7 +133,7 @@
             proto.write(ActiveInstrumentationProto.TARGET_PROCESSES, p);
         }
         if (mTargetInfo != null) {
-            mTargetInfo.writeToProto(proto, ActiveInstrumentationProto.TARGET_INFO);
+            mTargetInfo.writeToProto(proto, ActiveInstrumentationProto.TARGET_INFO, 0);
         }
         proto.write(ActiveInstrumentationProto.PROFILE_FILE, mProfileFile);
         proto.write(ActiveInstrumentationProto.WATCHER, mWatcher.toString());
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a19e928..23287cf 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1801,16 +1801,25 @@
         for (int i = clist.size() - 1; i >= 0; i--) {
             final ConnectionRecord crec = clist.get(i);
             final ServiceRecord srec = crec.binding.service;
-            if (srec != null && srec.app != null
-                    && (srec.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
-                if (group > 0) {
-                    srec.app.connectionService = srec;
-                    srec.app.connectionGroup = group;
-                    srec.app.connectionImportance = importance;
+            if (srec != null && (srec.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
+                if (srec.app != null) {
+                    if (group > 0) {
+                        srec.app.connectionService = srec;
+                        srec.app.connectionGroup = group;
+                        srec.app.connectionImportance = importance;
+                    } else {
+                        srec.app.connectionService = null;
+                        srec.app.connectionGroup = 0;
+                        srec.app.connectionImportance = 0;
+                    }
                 } else {
-                    srec.app.connectionService = null;
-                    srec.app.connectionGroup = 0;
-                    srec.app.connectionImportance = 0;
+                    if (group > 0) {
+                        srec.pendingConnectionGroup = group;
+                        srec.pendingConnectionImportance = importance;
+                    } else {
+                        srec.pendingConnectionGroup = 0;
+                        srec.pendingConnectionImportance = 0;
+                    }
                 }
             }
         }
@@ -2058,8 +2067,8 @@
                                 sInfo.applicationInfo.uid, name.getPackageName(),
                                 name.getClassName());
                     }
-                    r = new ServiceRecord(mAm, ss, className, name, filter, sInfo, callingFromFg,
-                            res);
+                    r = new ServiceRecord(mAm, ss, className, name, filter, sInfo,
+                            callingFromFg, res);
                     res.setService(r);
                     smap.mServicesByInstanceName.put(name, r);
                     smap.mServicesByIntent.put(filter, r);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8842f41..dc4eeaf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9209,6 +9209,19 @@
             }
             sdumper.dumpWithClient();
         }
+        if (dumpPackage == null) {
+            // Intentionally dropping the lock for this, because dumpBinderProxies() will make many
+            // outgoing binder calls to retrieve interface descriptors; while that is system code,
+            // there is nothing preventing an app from overriding this implementation by talking to
+            // the binder driver directly, and hang up system_server in the process. So, dump
+            // without locks held, and even then only when there is an unreasonably large number of
+            // proxies in the first place.
+            pw.println();
+            if (dumpAll) {
+                pw.println("-------------------------------------------------------------------------------");
+            }
+            dumpBinderProxies(pw, BINDER_PROXY_HIGH_WATERMARK /* minToDump */);
+        }
         synchronized(this) {
             pw.println();
             if (dumpAll) {
@@ -9274,19 +9287,6 @@
             }
             dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
         }
-        if (dumpPackage == null) {
-            // Intentionally dropping the lock for this, because dumpBinderProxies() will make many
-            // outgoing binder calls to retrieve interface descriptors; while that is system code,
-            // there is nothing preventing an app from overriding this implementation by talking to
-            // the binder driver directly, and hang up system_server in the process. So, dump
-            // without locks held, and even then only when there is an unreasonably large number of
-            // proxies in the first place.
-            pw.println();
-            if (dumpAll) {
-                pw.println("-------------------------------------------------------------------------------");
-            }
-            dumpBinderProxies(pw, BINDER_PROXY_HIGH_WATERMARK /* minToDump */);
-        }
     }
 
     /**
@@ -10266,7 +10266,8 @@
                 if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
                     continue;
                 }
-                r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS);
+                r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS, mProcessList.mLruProcesses.indexOf(r)
+                );
                 if (r.isPersistent()) {
                     numPers++;
                 }
@@ -10278,7 +10279,9 @@
             if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
                 continue;
             }
-            r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS);
+            r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS,
+                    mProcessList.mLruProcesses.indexOf(r)
+            );
         }
 
         for (int i=0; i<mActiveInstrumentation.size(); i++) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 62f1009..8cf9f1e 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -537,40 +537,44 @@
     }
 
     private static String buildOomTag(String prefix, String space, int val, int base) {
-        if (val == base) {
+        final int diff = val - base;
+        if (diff == 0) {
             if (space == null) return prefix;
-            return prefix + "  ";
+            return prefix + space;
         }
-        return prefix + "+" + Integer.toString(val - base);
+        if (diff < 10) {
+            return prefix + "+ " + Integer.toString(diff);
+        }
+        return prefix + "+" + Integer.toString(diff);
     }
 
     public static String makeOomAdjString(int setAdj) {
         if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
-            return buildOomTag("cch", "  ", setAdj, ProcessList.CACHED_APP_MIN_ADJ);
+            return buildOomTag("cch", "   ", setAdj, ProcessList.CACHED_APP_MIN_ADJ);
         } else if (setAdj >= ProcessList.SERVICE_B_ADJ) {
-            return buildOomTag("svcb ", null, setAdj, ProcessList.SERVICE_B_ADJ);
+            return buildOomTag("svcb  ", null, setAdj, ProcessList.SERVICE_B_ADJ);
         } else if (setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
-            return buildOomTag("prev ", null, setAdj, ProcessList.PREVIOUS_APP_ADJ);
+            return buildOomTag("prev  ", null, setAdj, ProcessList.PREVIOUS_APP_ADJ);
         } else if (setAdj >= ProcessList.HOME_APP_ADJ) {
-            return buildOomTag("home ", null, setAdj, ProcessList.HOME_APP_ADJ);
+            return buildOomTag("home  ", null, setAdj, ProcessList.HOME_APP_ADJ);
         } else if (setAdj >= ProcessList.SERVICE_ADJ) {
-            return buildOomTag("svc  ", null, setAdj, ProcessList.SERVICE_ADJ);
+            return buildOomTag("svc   ", null, setAdj, ProcessList.SERVICE_ADJ);
         } else if (setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
-            return buildOomTag("hvy  ", null, setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+            return buildOomTag("hvy   ", null, setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
         } else if (setAdj >= ProcessList.BACKUP_APP_ADJ) {
-            return buildOomTag("bkup ", null, setAdj, ProcessList.BACKUP_APP_ADJ);
+            return buildOomTag("bkup  ", null, setAdj, ProcessList.BACKUP_APP_ADJ);
         } else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
-            return buildOomTag("prcp ", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
+            return buildOomTag("prcp  ", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
         } else if (setAdj >= ProcessList.VISIBLE_APP_ADJ) {
-            return buildOomTag("vis  ", null, setAdj, ProcessList.VISIBLE_APP_ADJ);
+            return buildOomTag("vis", "   ", setAdj, ProcessList.VISIBLE_APP_ADJ);
         } else if (setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
-            return buildOomTag("fore ", null, setAdj, ProcessList.FOREGROUND_APP_ADJ);
+            return buildOomTag("fore  ", null, setAdj, ProcessList.FOREGROUND_APP_ADJ);
         } else if (setAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
-            return buildOomTag("psvc ", null, setAdj, ProcessList.PERSISTENT_SERVICE_ADJ);
+            return buildOomTag("psvc  ", null, setAdj, ProcessList.PERSISTENT_SERVICE_ADJ);
         } else if (setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
-            return buildOomTag("pers ", null, setAdj, ProcessList.PERSISTENT_PROC_ADJ);
+            return buildOomTag("pers  ", null, setAdj, ProcessList.PERSISTENT_PROC_ADJ);
         } else if (setAdj >= ProcessList.SYSTEM_ADJ) {
-            return buildOomTag("sys  ", null, setAdj, ProcessList.SYSTEM_ADJ);
+            return buildOomTag("sys   ", null, setAdj, ProcessList.SYSTEM_ADJ);
         } else if (setAdj >= ProcessList.NATIVE_ADJ) {
             return buildOomTag("ntv  ", null, setAdj, ProcessList.NATIVE_ADJ);
         } else {
@@ -2237,6 +2241,191 @@
         return index;
     }
 
+    /**
+     * Handle the case where we are inserting a process hosting client activities:
+     * Make sure any groups have their order match their importance, and take care of
+     * distributing old clients across other activity processes so they can't spam
+     * the LRU list.  Processing of the list will be restricted by the indices provided,
+     * and not extend out of them.
+     *
+     * @param topApp The app at the top that has just been inserted in to the list.
+     * @param topI The position in the list where topApp was inserted; this is the start (at the
+     *             top) where we are going to do our processing.
+     * @param bottomI The last position at which we will be processing; this is the end position
+     *                of whichever section of the LRU list we are in.  Nothing past it will be
+     *                touched.
+     * @param endIndex The current end of the top being processed.  Typically topI - 1.  That is,
+     *                 where we are going to start potentially adjusting other entries in the list.
+     */
+    private void updateClientActivitiesOrdering(final ProcessRecord topApp, final int topI,
+            final int bottomI, int endIndex) {
+        if (topApp.hasActivitiesOrRecentTasks() || topApp.treatLikeActivity
+                || !topApp.hasClientActivities()) {
+            // If this is not a special process that has client activities, then there is
+            // nothing to do.
+            return;
+        }
+
+        final int uid = topApp.info.uid;
+        if (topApp.connectionGroup > 0) {
+            int endImportance = topApp.connectionImportance;
+            for (int i = endIndex; i >= bottomI; i--) {
+                final ProcessRecord subProc = mLruProcesses.get(i);
+                if (subProc.info.uid == uid
+                        && subProc.connectionGroup == topApp.connectionGroup) {
+                    if (i == endIndex && subProc.connectionImportance >= endImportance) {
+                        // This process is already in the group, and its importance
+                        // is not as strong as the process before it, so keep it
+                        // correctly positioned in the group.
+                        if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                "Keeping in-place above " + subProc
+                                        + " endImportance=" + endImportance
+                                        + " group=" + subProc.connectionGroup
+                                        + " importance=" + subProc.connectionImportance);
+                        endIndex--;
+                        endImportance = subProc.connectionImportance;
+                    } else {
+                        // We want to pull this up to be with the rest of the group,
+                        // and order within the group by importance.
+                        if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                "Pulling up " + subProc
+                                        + " to position in group with importance="
+                                        + subProc.connectionImportance);
+                        boolean moved = false;
+                        for (int pos = topI; pos > endIndex; pos--) {
+                            final ProcessRecord posProc = mLruProcesses.get(pos);
+                            if (subProc.connectionImportance
+                                    <= posProc.connectionImportance) {
+                                mLruProcesses.remove(i);
+                                mLruProcesses.add(pos, subProc);
+                                if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                        "Moving " + subProc
+                                                + " from position " + i + " to above " + posProc
+                                                + " @ " + pos);
+                                moved = true;
+                                endIndex--;
+                                break;
+                            }
+                        }
+                        if (!moved) {
+                            // Goes to the end of the group.
+                            mLruProcesses.remove(i);
+                            mLruProcesses.add(endIndex - 1, subProc);
+                            if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                    "Moving " + subProc
+                                            + " from position " + i + " to end of group @ "
+                                            + endIndex);
+                            endIndex--;
+                            endImportance = subProc.connectionImportance;
+                        }
+                    }
+                }
+            }
+
+        }
+        // To keep it from spamming the LRU list (by making a bunch of clients),
+        // we will distribute other entries owned by it to be in-between other apps.
+        int i = endIndex;
+        while (i >= bottomI) {
+            ProcessRecord subProc = mLruProcesses.get(i);
+            if (DEBUG_LRU) Slog.d(TAG_LRU,
+                    "Looking to spread old procs, at " + subProc + " @ " + i);
+            if (subProc.info.uid != uid) {
+                // This is a different app...  if we have gone through some of the
+                // target app, pull this up to be before them.  We want to pull up
+                // one activity process, but any number of non-activity processes.
+                if (i < endIndex) {
+                    boolean hasActivity = false;
+                    int connUid = 0;
+                    int connGroup = 0;
+                    while (i >= bottomI) {
+                        mLruProcesses.remove(i);
+                        mLruProcesses.add(endIndex, subProc);
+                        if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                "Different app, moving to " + endIndex);
+                        i--;
+                        if (i < bottomI) {
+                            break;
+                        }
+                        subProc = mLruProcesses.get(i);
+                        if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                "Looking at next app at " + i + ": " + subProc);
+                        if (subProc.hasActivitiesOrRecentTasks() || subProc.treatLikeActivity) {
+                            if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                    "This is hosting an activity!");
+                            if (hasActivity) {
+                                // Already found an activity, done.
+                                if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                        "Already found an activity, done");
+                                break;
+                            }
+                            hasActivity = true;
+                        } else if (subProc.hasClientActivities()) {
+                            if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                    "This is a client of an activity");
+                            if (hasActivity) {
+                                if (connUid == 0 || connUid != subProc.info.uid) {
+                                    // Already have an activity that is not from from a client
+                                    // connection or is a different client connection, done.
+                                    if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                            "Already found a different activity: connUid="
+                                            + connUid + " uid=" + subProc.info.uid);
+                                    break;
+                                } else if (connGroup == 0 || connGroup != subProc.connectionGroup) {
+                                    // Previously saw a different group or not from a group,
+                                    // want to treat these as different things.
+                                    if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                            "Already found a different group: connGroup="
+                                            + connGroup + " group=" + subProc.connectionGroup);
+                                    break;
+                                }
+                            } else {
+                                if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                        "This is an activity client!  uid="
+                                        + subProc.info.uid + " group=" + subProc.connectionGroup);
+                                hasActivity = true;
+                                connUid = subProc.info.uid;
+                                connGroup = subProc.connectionGroup;
+                            }
+                        }
+                        endIndex--;
+                    }
+                }
+                // Find the end of the next group of processes for target app.  This
+                // is after any entries of different apps (so we don't change the existing
+                // relative order of apps) and then after the next last group of processes
+                // of the target app.
+                for (endIndex--; endIndex >= bottomI; endIndex--) {
+                    final ProcessRecord endProc = mLruProcesses.get(endIndex);
+                    if (endProc.info.uid == uid) {
+                        if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                "Found next group of app: " + endProc + " @ "
+                                        + endIndex);
+                        break;
+                    }
+                }
+                if (endIndex >= bottomI) {
+                    final ProcessRecord endProc = mLruProcesses.get(endIndex);
+                    for (endIndex--; endIndex >= bottomI; endIndex--) {
+                        final ProcessRecord nextEndProc = mLruProcesses.get(endIndex);
+                        if (nextEndProc.info.uid != uid
+                                || nextEndProc.connectionGroup != endProc.connectionGroup) {
+                            if (DEBUG_LRU) Slog.d(TAG_LRU,
+                                    "Found next group or app: " + nextEndProc + " @ "
+                                            + endIndex + " group=" + nextEndProc.connectionGroup);
+                            break;
+                        }
+                    }
+                }
+                if (DEBUG_LRU) Slog.d(TAG_LRU,
+                        "Bumping scan position to " + endIndex);
+                i = endIndex;
+            } else {
+                i--;
+            }
+        }
+    }
+
     final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
             ProcessRecord client) {
         final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities()
@@ -2349,91 +2538,31 @@
             if (!app.hasActivitiesOrRecentTasks() && !app.treatLikeActivity
                     && mLruProcessActivityStart < (N - 1)) {
                 // Process doesn't have activities, but has clients with
-                // activities...  move it up, but one below the top (the top
-                // should always have a real activity).
+                // activities...  move it up, but below the app that is binding to it.
                 if (DEBUG_LRU) Slog.d(TAG_LRU,
-                        "Adding to second-top of LRU activity list: " + app);
-                mLruProcesses.add(N - 1, app);
+                        "Adding to second-top of LRU activity list: " + app
+                        + " group=" + app.connectionGroup
+                        + " importance=" + app.connectionImportance);
+                int pos = N - 1;
+                while (pos > mLruProcessActivityStart) {
+                    final ProcessRecord posproc = mLruProcesses.get(pos);
+                    if (posproc.info.uid == app.info.uid) {
+                        // Technically this app could have multiple processes with different
+                        // activities and so we should be looking for the actual process that
+                        // is bound to the target proc...  but I don't really care, do you?
+                        break;
+                    }
+                    pos--;
+                }
+                mLruProcesses.add(pos, app);
                 // If this process is part of a group, need to pull up any other processes
                 // in that group to be with it.
-                final int uid = app.info.uid;
-                int endIndex = N - 2;
-                nextActivityIndex = N - 2;
-                if (app.connectionGroup > 0) {
-                    int endImportance = app.connectionImportance;
-                    for (int i = endIndex; i >= mLruProcessActivityStart; i--) {
-                        final ProcessRecord subProc = mLruProcesses.get(i);
-                        if (subProc.info.uid == uid
-                                && subProc.connectionGroup == subProc.connectionGroup) {
-                            if (i == endIndex && subProc.connectionImportance >= endImportance) {
-                                // This process is already in the group, and its importance
-                                // is not as strong as the process before it, so it keep it
-                                // correctly positioned in the group.
-                                endIndex--;
-                                endImportance = subProc.connectionImportance;
-                            } else {
-                                // We want to pull this up to be with the rest of the group,
-                                // and order within the group by importance.
-                                boolean moved = false;
-                                for (int pos = N - 1; pos > endIndex; pos--) {
-                                    final ProcessRecord posProc = mLruProcesses.get(pos);
-                                    if (subProc.connectionImportance
-                                            <= posProc.connectionImportance) {
-                                        mLruProcesses.remove(i);
-                                        mLruProcesses.add(pos, subProc);
-                                        moved = true;
-                                        endIndex--;
-                                        break;
-                                    }
-                                }
-                                if (!moved) {
-                                    // Goes to the end of the group.
-                                    mLruProcesses.remove(i);
-                                    mLruProcesses.add(endIndex - 1, subProc);
-                                    endIndex--;
-                                    endImportance = subProc.connectionImportance;
-                                }
-                            }
-                        }
-                    }
-
+                int endIndex = pos - 1;
+                if (endIndex < mLruProcessActivityStart) {
+                    endIndex = mLruProcessActivityStart;
                 }
-                // To keep it from spamming the LRU list (by making a bunch of clients),
-                // we will distribute other entries owned by it to be in-between other apps.
-                for (int i = endIndex; i >= mLruProcessActivityStart; i--) {
-                    final ProcessRecord subProc = mLruProcesses.get(i);
-                    if (subProc.info.uid != uid) {
-                        // This is a different app...  if we have gone through some of the
-                        // target app, pull this up to be before them.
-                        if (i < endIndex) {
-                            mLruProcesses.remove(i);
-                            mLruProcesses.add(endIndex, subProc);
-                        }
-                        // Find the end of the next group of processes for target app.  This
-                        // is after any entries of different apps (so we don't change the existing
-                        // relative order of apps) and then after the next last group of processes
-                        // of the target app.
-                        for (endIndex--; endIndex >= mLruProcessActivityStart; endIndex--) {
-                            final ProcessRecord endProc = mLruProcesses.get(endIndex);
-                            if (endProc.info.uid == uid) {
-                                break;
-                            }
-                        }
-                        if (endIndex >= mLruProcessActivityStart) {
-                            final ProcessRecord endProc = mLruProcesses.get(endIndex);
-                            for (endIndex--; endIndex >= mLruProcessActivityStart; endIndex--) {
-                                final ProcessRecord nextEndProc = mLruProcesses.get(endIndex);
-                                if (nextEndProc.info.uid != uid
-                                        || nextEndProc.connectionGroup != endProc.connectionGroup) {
-                                    break;
-                                }
-                            }
-                        }
-                        if (i > endIndex) {
-                            i = endIndex;
-                        }
-                    }
-                }
+                nextActivityIndex = endIndex;
+                updateClientActivitiesOrdering(app, pos, mLruProcessActivityStart, endIndex);
             } else {
                 // Process has activities, put it at the very tipsy-top.
                 if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app);
@@ -2469,6 +2598,9 @@
             nextIndex = index - 1;
             mLruProcessActivityStart++;
             mLruProcessServiceStart++;
+            if (index > 1) {
+                updateClientActivitiesOrdering(app, mLruProcessServiceStart - 1, 0, index - 1);
+            }
         }
 
         app.lruSeq = mLruSeq;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 013de93..4826f48 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -586,7 +586,7 @@
                 }
                 origBase.makeInactive();
             }
-            baseProcessTracker = tracker.getProcessStateLocked(info.packageName, uid,
+            baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
                     info.longVersionCode, processName);
             baseProcessTracker.makeActive();
             for (int i=0; i<pkgList.size(); i++) {
@@ -594,7 +594,7 @@
                 if (holder.state != null && holder.state != origBase) {
                     holder.state.makeInactive();
                 }
-                tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), uid,
+                tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), info.uid,
                         info.longVersionCode, processName);
                 if (holder.state != baseProcessTracker) {
                     holder.state.makeActive();
@@ -760,19 +760,25 @@
 
     @Override
     public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        writeToProto(proto, fieldId, -1);
+    }
+
+    public void writeToProto(ProtoOutputStream proto, long fieldId, int lruIndex) {
         long token = proto.start(fieldId);
         proto.write(ProcessRecordProto.PID, pid);
         proto.write(ProcessRecordProto.PROCESS_NAME, processName);
-        if (info.uid < Process.FIRST_APPLICATION_UID) {
-            proto.write(ProcessRecordProto.UID, uid);
-        } else {
+        proto.write(ProcessRecordProto.UID, info.uid);
+        if (UserHandle.getAppId(info.uid) >= Process.FIRST_APPLICATION_UID) {
             proto.write(ProcessRecordProto.USER_ID, userId);
             proto.write(ProcessRecordProto.APP_ID, UserHandle.getAppId(info.uid));
-            if (uid != info.uid) {
-                proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid));
-            }
+        }
+        if (uid != info.uid) {
+            proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid));
         }
         proto.write(ProcessRecordProto.PERSISTENT, mPersistent);
+        if (lruIndex >= 0) {
+            proto.write(ProcessRecordProto.LRU_INDEX, lruIndex);
+        }
         proto.end(token);
     }
 
@@ -864,7 +870,8 @@
             ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
                     versionCode);
             if (baseProcessTracker != null) {
-                tracker.updateProcessStateHolderLocked(holder, pkg, uid, versionCode, processName);
+                tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode,
+                        processName);
                 pkgList.put(pkg, holder);
                 if (holder.state != baseProcessTracker) {
                     holder.state.makeActive();
@@ -925,7 +932,7 @@
                 pkgList.clear();
                 ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
                         info.longVersionCode);
-                tracker.updateProcessStateHolderLocked(holder, info.packageName, uid,
+                tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid,
                         info.longVersionCode, processName);
                 pkgList.put(info.packageName, holder);
                 if (holder.state != baseProcessTracker) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 09f8c3e..da5ce1c 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -121,6 +121,8 @@
     long nextRestartTime;   // time when restartDelay will expire.
     boolean destroying;     // set when we have started destroying the service
     long destroyTime;       // time at which destory was initiated.
+    int pendingConnectionGroup;        // To be filled in to ProcessRecord once it connects
+    int pendingConnectionImportance;   // To be filled in to ProcessRecord once it connects
 
     String stringName;      // caching of toString
 
@@ -386,6 +388,11 @@
                 pw.print(" restartTime=");
                 TimeUtils.formatDuration(restartTime, now, pw);
                 pw.print(" createdFromFg="); pw.println(createdFromFg);
+        if (pendingConnectionGroup != 0) {
+            pw.print(prefix); pw.print(" pendingConnectionGroup=");
+            pw.print(pendingConnectionGroup);
+            pw.print(" Importance="); pw.println(pendingConnectionImportance);
+        }
         if (startRequested || delayedStop || lastStartId != 0) {
             pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
                     pw.print(" delayedStop="); pw.print(delayedStop);
@@ -461,7 +468,11 @@
         serviceInfo = sInfo;
         appInfo = sInfo.applicationInfo;
         packageName = sInfo.applicationInfo.packageName;
-        processName = sInfo.processName;
+        if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
+            processName = sInfo.processName + ":" + instanceName.getClassName();
+        } else {
+            processName = sInfo.processName;
+        }
         permission = sInfo.permission;
         exported = sInfo.exported;
         this.restarter = restarter;
@@ -507,6 +518,12 @@
 
     public void setProcess(ProcessRecord _proc) {
         app = _proc;
+        if (pendingConnectionGroup > 0) {
+            app.connectionService = this;
+            app.connectionGroup = pendingConnectionGroup;
+            app.connectionImportance = pendingConnectionImportance;
+            pendingConnectionGroup = pendingConnectionImportance = 0;
+        }
         if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) {
             for (int conni = connections.size() - 1; conni >= 0; conni--) {
                 ArrayList<ConnectionRecord> cr = connections.valueAt(conni);