OSDN Git Service

Allow for more than one home app.
authorCraig Mautner <cmautner@google.com>
Sun, 18 Aug 2013 00:04:56 +0000 (17:04 -0700)
committerCraig Mautner <cmautner@google.com>
Sun, 18 Aug 2013 00:04:56 +0000 (17:04 -0700)
Having a single mHomeProcess in ActivityManagerService ignores the
possibility of multiple processes serving as home. Particularly when
we have a home activity that only serves to launch the true home
activity.

Fixes bug b10296766

Change-Id: I9e5c9c955c64f4b3df856b6bc66d6a0d93f85aab

services/java/com/android/server/am/ActivityManagerService.java
services/java/com/android/server/am/ActivityStack.java
services/java/com/android/server/am/ActivityStackSupervisor.java

index be6119d..3f58fa4 100644 (file)
@@ -21,12 +21,12 @@ import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
-
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
 import android.app.AppOpsManager;
 import android.appwidget.AppWidgetManager;
 import android.util.ArrayMap;
+
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
@@ -52,6 +52,7 @@ import com.android.server.pm.UserManagerService;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.StackBox;
 import com.android.server.wm.WindowManagerService;
+
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -154,6 +155,7 @@ import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.format.Time;
+import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
@@ -536,7 +538,7 @@ public final class ActivityManagerService extends ActivityManagerNative
      * This is the process holding what we currently consider to be
      * the "home" activity.
      */
-    ProcessRecord mHomeProcess;
+    ArraySet<ProcessRecord> mHomeProcess = new ArraySet<ProcessRecord>();
 
     /**
      * This is the process holding the activity the user last visited that
@@ -8951,11 +8953,11 @@ public final class ActivityManagerService extends ActivityManagerNative
         // replaced by a third-party app, clear the package preferred activities from packages
         // with a home activity running in the process to prevent a repeatedly crashing app
         // from blocking the user to manually clear the list.
-        if (app == mHomeProcess && mHomeProcess.activities.size() > 0
-                    && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
-            Iterator<ActivityRecord> it = mHomeProcess.activities.iterator();
-            while (it.hasNext()) {
-                ActivityRecord r = it.next();
+        final ArrayList<ActivityRecord> activities = app.activities;
+        if (mHomeProcess.contains(app) && activities.size() > 0
+                    && (app.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
                 if (r.isHomeActivity()) {
                     Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
                     try {
@@ -10230,13 +10232,20 @@ public final class ActivityManagerService extends ActivityManagerNative
                 pw.print("  mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
             }
         }
-        if (mHomeProcess != null && (dumpPackage == null
-                || mHomeProcess.pkgList.containsKey(dumpPackage))) {
-            if (needSep) {
-                pw.println();
-                needSep = false;
+        if (!mHomeProcess.isEmpty()) {
+            final int size = mHomeProcess.size();
+            ProcessRecord[] processes = new ProcessRecord[size];
+            mHomeProcess.toArray(processes);
+            for (int processNdx = 0; processNdx < size; ++processNdx) {
+                final ProcessRecord app = processes[processNdx];
+                if (dumpPackage == null || app.pkgList.containsKey(dumpPackage)) {
+                    if (needSep) {
+                        pw.println();
+                        needSep = false;
+                    }
+                    pw.println("  mHomeProcess[" + processNdx + "]: " + app);
+                }
             }
-            pw.println("  mHomeProcess: " + mHomeProcess);
         }
         if (mPreviousProcess != null && (dumpPackage == null
                 || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
@@ -11737,10 +11746,10 @@ public final class ActivityManagerService extends ActivityManagerNative
         }
         return inLaunching;
     }
-    
+
     /**
      * Main code for cleaning up a process when it has gone away.  This is
-     * called both as a result of the process dying, or directly when stopping 
+     * called both as a result of the process dying, or directly when stopping
      * a process when running in single process mode.
      */
     private final void cleanUpApplicationRecordLocked(ProcessRecord app,
@@ -11751,7 +11760,7 @@ public final class ActivityManagerService extends ActivityManagerNative
 
         mProcessesToGc.remove(app);
         mPendingPssProcesses.remove(app);
-        
+
         // Dismiss any open dialogs.
         if (app.crashDialog != null && !app.forceCrashReport) {
             app.crashDialog.dismiss();
@@ -11768,7 +11777,7 @@ public final class ActivityManagerService extends ActivityManagerNative
 
         app.crashing = false;
         app.notResponding = false;
-        
+
         app.resetPackageList(mProcessStats);
         app.unlinkDeathRecipient();
         app.thread = null;
@@ -11801,7 +11810,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         if (checkAppInLaunchingProvidersLocked(app, false)) {
             restart = true;
         }
-        
+
         // Unregister from connected content providers.
         if (!app.conProviders.isEmpty()) {
             for (int i=0; i<app.conProviders.size(); i++) {
@@ -11828,7 +11837,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 }
             }
         }
-        
+
         skipCurrentReceiverLocked(app);
 
         // Unregister any receivers.
@@ -11859,6 +11868,8 @@ public final class ActivityManagerService extends ActivityManagerNative
         }
         mHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget();
 
+        mHomeProcess.remove(app);
+
         // If the caller is restarting this app, then leave it in its
         // current lists and let the caller take care of it.
         if (restarting) {
@@ -11888,8 +11899,8 @@ public final class ActivityManagerService extends ActivityManagerNative
                 "Clean-up removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
-        if (app == mHomeProcess) {
-            mHomeProcess = null;
+        if (mHomeProcess.contains(app)) {
+            mHomeProcess.remove(app);
         }
         if (app == mPreviousProcess) {
             mPreviousProcess = null;
@@ -13815,7 +13826,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             }
         }
 
-        if (app == mHomeProcess) {
+        if (mHomeProcess.contains(app)) {
             if (adj > ProcessList.HOME_APP_ADJ) {
                 // This process is hosting what we currently consider to be the
                 // home app, so we don't want to let it go into the background.
@@ -13882,7 +13893,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
                     procState = ActivityManager.PROCESS_STATE_SERVICE;
                 }
-                if (app.hasShownUi && app != mHomeProcess) {
+                if (app.hasShownUi && !mHomeProcess.contains(app)) {
                     // If this process has shown some UI, let it immediately
                     // go to the LRU list because it may be pretty heavy with
                     // UI stuff.  We'll tag it with a label just to help
@@ -13945,7 +13956,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                         if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
                             // Not doing bind OOM management, so treat
                             // this guy more like a started service.
-                            if (app.hasShownUi && app != mHomeProcess) {
+                            if (app.hasShownUi && !mHomeProcess.contains(app)) {
                                 // If this process has shown some UI, let it immediately
                                 // go to the LRU list because it may be pretty heavy with
                                 // UI stuff.  We'll tag it with a label just to help
@@ -14000,7 +14011,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                             // about letting this process get into the LRU
                             // list to be killed and restarted if needed for
                             // memory.
-                            if (app.hasShownUi && app != mHomeProcess
+                            if (app.hasShownUi && !mHomeProcess.contains(app)
                                     && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                 adjType = "cch-bound-ui-services";
                             } else {
@@ -14114,7 +14125,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                     clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
                 }
                 if (adj > clientAdj) {
-                    if (app.hasShownUi && app != mHomeProcess
+                    if (app.hasShownUi && !mHomeProcess.contains(app)
                             && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                         app.adjType = "cch-ui-provider";
                     } else {
@@ -14974,7 +14985,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                             // to be good enough at this point that destroying
                             // activities causes more harm than good.
                             if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
-                                    && app != mHomeProcess && app != mPreviousProcess) {
+                                    && !mHomeProcess.contains(app) && app != mPreviousProcess) {
                                 // Need to do this on its own message because the stack may not
                                 // be in a consistent state at this point.
                                 // For these apps we will also finish their activities
index a0bbfad..2fefadf 100644 (file)
@@ -2246,7 +2246,7 @@ final class ActivityStack {
                 if (r.state == ActivityState.RESUMED
                         || r.state == ActivityState.PAUSING
                         || r.state == ActivityState.PAUSED) {
-                    if (!r.isHomeActivity() || mService.mHomeProcess != r.app) {
+                    if (!r.isHomeActivity() || !mService.mHomeProcess.contains(r.app)) {
                         Slog.w(TAG, "  Force finishing activity "
                                 + r.intent.getComponent().flattenToShortString());
                         finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
index 0808861..250ab4a 100644 (file)
@@ -905,7 +905,7 @@ public final class ActivityStackSupervisor {
                         r.task.taskId, r.shortComponentName);
             }
             if (r.isHomeActivity() && r.isNotResolverActivity()) {
-                mService.mHomeProcess = app;
+                mService.mHomeProcess.add(app);
             }
             mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             r.sleeping = false;
@@ -1946,7 +1946,7 @@ public final class ActivityStackSupervisor {
         // makes sense to.
         if (r.app != null && fgApp != null && r.app != fgApp
                 && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
-                && r.app != mService.mHomeProcess) {
+                && !mService.mHomeProcess.contains(r.app)) {
             mService.mPreviousProcess = r.app;
             mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
         }