Merge "Merge changes from topics "merge BT bond", "parameterize BT enable", "remove BT isEnabled" am: bd4031de4a am: 2fb54515a2 am: b39a419fa4"
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b191338d..01f3c26 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6694,7 +6694,7 @@
 
     private final long[] mProcessStateStatsLongs = new long[1];
 
-    private boolean isProcessAliveLocked(ProcessRecord proc) {
+    boolean isProcessAliveLocked(ProcessRecord proc) {
         if (proc.pid <= 0) {
             if (DEBUG_OOM_ADJ) Slog.d(TAG, "Process hasn't started yet: " + proc);
             return false;
@@ -6711,7 +6711,10 @@
         final long state = mProcessStateStatsLongs[0];
         if (DEBUG_OOM_ADJ) Slog.d(TAG, "RETRIEVED STATE FOR " + proc.procStatFile + ": "
                 + (char)state);
-        return state != 'Z' && state != 'X' && state != 'x' && state != 'K';
+        if (state != 'Z' && state != 'X' && state != 'x' && state != 'K') {
+            return Process.getUidForPid(proc.pid) == proc.uid;
+        }
+        return false;
     }
 
     private String checkContentProviderAssociation(ProcessRecord callingApp, int callingUid,
@@ -6784,14 +6787,14 @@
                 // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
                 // how to test this case.)
                 if (cpr.proc.killed && cpr.proc.killedByAm) {
-                    checkTime(startTime, "getContentProviderImpl: before appDied (killedByAm)");
                     final long iden = Binder.clearCallingIdentity();
                     try {
-                        appDiedLocked(cpr.proc);
+                        mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, false,
+                                cpr.uid == cpr.proc.uid || cpr.proc.isolated,
+                                "getContentProviderImpl: %s (killedByAm)", startTime);
                     } finally {
                         Binder.restoreCallingIdentity(iden);
                     }
-                    checkTime(startTime, "getContentProviderImpl: after appDied (killedByAm)");
                 }
             }
 
@@ -6895,9 +6898,8 @@
                     Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
                             + " is crashing; detaching " + r);
                     boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
-                    checkTime(startTime, "getContentProviderImpl: before appDied");
-                    appDiedLocked(cpr.proc);
-                    checkTime(startTime, "getContentProviderImpl: after appDied");
+                    mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc,
+                            false, true, "getContentProviderImpl: %s", startTime);
                     if (!lastRef) {
                         // This wasn't the last ref our process had on
                         // the provider...  we have now been killed, bail.
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 2bb7035..32975d7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -78,6 +78,9 @@
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.EventLog;
@@ -283,6 +286,16 @@
     // lmkd reconnect delay in msecs
     private final static long LMDK_RECONNECT_DELAY_MS = 1000;
 
+    /**
+     * How long between a process kill and we actually receive its death recipient
+     */
+    private static final long PROC_KILL_TIMEOUT = 2000; // 2 seconds;
+
+    /**
+     * How long between polls to check if the given process is dead or not.
+     */
+    private static final long PROC_DEATH_POLL_INTERVAL = 100;
+
     ActivityManagerService mService = null;
 
     // To kill process groups asynchronously
@@ -1421,7 +1434,7 @@
         if (app.pendingStart) {
             return true;
         }
-        long startTime = SystemClock.elapsedRealtime();
+        long startTime = SystemClock.uptimeMillis();
         if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
             checkSlow(startTime, "startProcess: removing from pids map");
             mService.mPidsSelfLocked.remove(app);
@@ -1856,7 +1869,7 @@
             boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
             boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
             String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
-        long startTime = SystemClock.elapsedRealtime();
+        long startTime = SystemClock.uptimeMillis();
         ProcessRecord app;
         if (!isolated) {
             app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
@@ -1917,10 +1930,9 @@
             // An application record is attached to a previous process,
             // clean it up now.
             if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
-            checkSlow(startTime, "startProcess: bad proc running, killing");
-            ProcessList.killProcessGroup(app.uid, app.pid);
-            mService.handleAppDiedLocked(app, true, true);
-            checkSlow(startTime, "startProcess: done killing old proc");
+            // do the killing
+            killProcAndWaitIfNecessaryLocked(app, true, app.uid == info.uid || app.isolated,
+                    "startProcess: bad proc running, killing: %s", startTime);
         }
 
         if (app == null) {
@@ -1961,6 +1973,70 @@
         return success ? app : null;
     }
 
+    /**
+     * A lite version of checking if a process is alive or not, by using kill(2) with signal 0.
+     *
+     * <p>
+     * Note that, zombie processes are stil "alive" in this case, use the {@link
+     * ActivityManagerService#isProcessAliveLocked} if zombie processes need to be excluded.
+     * </p>
+     */
+    @GuardedBy("mService")
+    private boolean isProcessAliveLiteLocked(ProcessRecord app) {
+        try {
+            Os.kill(app.pid, 0);
+        } catch (ErrnoException e) {
+            return e.errno != OsConstants.ESRCH;
+        }
+        return true;
+    }
+
+    /**
+     * Kill (if asked to) and wait for the given process died if necessary
+     * @param app - The process record to kill
+     * @param doKill - Kill the given process record
+     * @param wait - Wait for the death of the given process
+     * @param formatString - The log message for slow operation
+     * @param startTime - The start timestamp of the operation
+     */
+    @GuardedBy("mService")
+    void killProcAndWaitIfNecessaryLocked(final ProcessRecord app, final boolean doKill,
+            final boolean wait, final String formatString, final long startTime) {
+
+        checkSlow(startTime, String.format(formatString, "before appDied"));
+
+        if (doKill) {
+            // do the killing
+            ProcessList.killProcessGroup(app.uid, app.pid);
+        }
+
+        // wait for the death
+        if (wait) {
+            boolean isAlive = true;
+            // ideally we should use pidfd_open(2) but it's available on kernel 5.3 or later
+
+            final long timeout = SystemClock.uptimeMillis() + PROC_KILL_TIMEOUT;
+            isAlive = isProcessAliveLiteLocked(app);
+            while (timeout > SystemClock.uptimeMillis() && isAlive) {
+                try {
+                    Thread.sleep(PROC_DEATH_POLL_INTERVAL);
+                } catch (InterruptedException e) {
+                }
+                isAlive = isProcessAliveLiteLocked(app);
+            }
+
+            if (isAlive) {
+                // Maybe the process goes into zombie, use an expensive API to check again.
+                if (mService.isProcessAliveLocked(app)) {
+                    Slog.w(TAG, String.format(formatString,
+                              "waiting for app killing timed out"));
+                }
+            }
+        }
+
+        checkSlow(startTime, String.format(formatString, "after appDied"));
+    }
+
     @GuardedBy("mService")
     private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) {
         StringBuilder sb = null;