Kill AppZygote when a package is removed with DONT_KILL.

When a package is being removed with DONT_KILL, we should still
kill any App Zygote instances that may be running, since they
are referring to old code, and will not be able to spawn any
new processes anyway. New service requests will automatically
spawn a new app zygote process.

Bug: 144095172
Test: Manual test with Chrome
Change-Id: I2e5de604312bb7739ba3ef6abb63d534c74522f2
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b036975..1e61d2e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1763,7 +1763,7 @@
                 case KILL_APP_ZYGOTE_MSG: {
                     synchronized (ActivityManagerService.this) {
                         final AppZygote appZygote = (AppZygote) msg.obj;
-                        mProcessList.killAppZygoteIfNeededLocked(appZygote);
+                        mProcessList.killAppZygoteIfNeededLocked(appZygote, false /* force */);
                     }
                 } break;
             case CHECK_EXCESSIVE_POWER_USE_MSG: {
@@ -4620,6 +4620,22 @@
     }
 
     @GuardedBy("this")
+    final void forceStopAppZygoteLocked(String packageName, int appId, int userId) {
+        if (packageName == null) {
+            return;
+        }
+        if (appId < 0) {
+            try {
+                appId = UserHandle.getAppId(AppGlobals.getPackageManager()
+                        .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, 0));
+            } catch (RemoteException e) {
+            }
+        }
+
+        mProcessList.killAppZygotesLocked(packageName, appId, userId, true /* force */);
+    }
+
+    @GuardedBy("this")
     final boolean forceStopPackageLocked(String packageName, int appId,
             boolean callerWillRestart, boolean purgeCache, boolean doit,
             boolean evenPersistent, boolean uninstalling, int userId, String reason) {
@@ -15583,6 +15599,12 @@
                                                 intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                                 false, true, true, false, fullUninstall, userId,
                                                 removed ? "pkg removed" : "pkg changed");
+                                    } else {
+                                        // Kill any app zygotes always, since they can't fork new
+                                        // processes with references to the old code
+                                        forceStopAppZygoteLocked(ssp, UserHandle.getAppId(
+                                                intent.getIntExtra(Intent.EXTRA_UID, -1)),
+                                                userId);
                                     }
                                     final int cmd = killProcess
                                             ? ApplicationThreadConstants.PACKAGE_REMOVED
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 7f9477ed..575ff1a 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1858,11 +1858,11 @@
     }
 
     @GuardedBy("mService")
-    public void killAppZygoteIfNeededLocked(AppZygote appZygote) {
+    public void killAppZygoteIfNeededLocked(AppZygote appZygote, boolean force) {
         final ApplicationInfo appInfo = appZygote.getAppInfo();
         ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
-        if (zygoteProcesses != null && zygoteProcesses.size() == 0) {
-            // Only remove if no longer in use now
+        if (zygoteProcesses != null && (force || zygoteProcesses.size() == 0)) {
+            // Only remove if no longer in use now, or forced kill
             mAppZygotes.remove(appInfo.processName, appInfo.uid);
             mAppZygoteProcesses.remove(appZygote);
             mAppIsolatedUidRangeAllocator.freeUidRangeLocked(appInfo);
@@ -1890,7 +1890,7 @@
                 if (app.removed) {
                     // If we stopped this process because the package hosting it was removed,
                     // there's no point in delaying the app zygote kill.
-                    killAppZygoteIfNeededLocked(appZygote);
+                    killAppZygoteIfNeededLocked(appZygote, false /* force */);
                 } else {
                     Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG);
                     msg.obj = appZygote;
@@ -2401,6 +2401,33 @@
     }
 
     @GuardedBy("mService")
+    void killAppZygotesLocked(String packageName, int appId, int userId, boolean force) {
+        // See if there are any app zygotes running for this packageName / UID combination,
+        // and kill it if so.
+        final ArrayList<AppZygote> zygotesToKill = new ArrayList<>();
+        for (SparseArray<AppZygote> appZygotes : mAppZygotes.getMap().values()) {
+            for (int i = 0; i < appZygotes.size(); ++i) {
+                final int appZygoteUid = appZygotes.keyAt(i);
+                if (userId != UserHandle.USER_ALL && UserHandle.getUserId(appZygoteUid) != userId) {
+                    continue;
+                }
+                if (appId >= 0 && UserHandle.getAppId(appZygoteUid) != appId) {
+                    continue;
+                }
+                final AppZygote appZygote = appZygotes.valueAt(i);
+                if (packageName != null
+                        && !packageName.equals(appZygote.getAppInfo().packageName)) {
+                    continue;
+                }
+                zygotesToKill.add(appZygote);
+            }
+        }
+        for (AppZygote appZygote : zygotesToKill) {
+            killAppZygoteIfNeededLocked(appZygote, force);
+        }
+    }
+
+    @GuardedBy("mService")
     final boolean killPackageProcessesLocked(String packageName, int appId,
             int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
             boolean doit, boolean evenPersistent, boolean setRemoved, String reason) {
@@ -2477,29 +2504,7 @@
         for (int i=0; i<N; i++) {
             removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
         }
-        // See if there are any app zygotes running for this packageName / UID combination,
-        // and kill it if so.
-        final ArrayList<AppZygote> zygotesToKill = new ArrayList<>();
-        for (SparseArray<AppZygote> appZygotes : mAppZygotes.getMap().values()) {
-            for (int i = 0; i < appZygotes.size(); ++i) {
-                final int appZygoteUid = appZygotes.keyAt(i);
-                if (userId != UserHandle.USER_ALL && UserHandle.getUserId(appZygoteUid) != userId) {
-                    continue;
-                }
-                if (appId >= 0 && UserHandle.getAppId(appZygoteUid) != appId) {
-                    continue;
-                }
-                final AppZygote appZygote = appZygotes.valueAt(i);
-                if (packageName != null
-                        && !packageName.equals(appZygote.getAppInfo().packageName)) {
-                    continue;
-                }
-                zygotesToKill.add(appZygote);
-            }
-        }
-        for (AppZygote appZygote : zygotesToKill) {
-            killAppZygoteIfNeededLocked(appZygote);
-        }
+        killAppZygotesLocked(packageName, appId, userId, false /* force */);
         mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
         return N > 0;
     }