Merge "ActivityManager: kill frozen processes receiving sync transactions" into rvc-qpr-dev am: acd04189d9 am: 00523e6c27

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12568351

Change-Id: Ic904787a426b3ebf10f037544aa8a706529b3ab9
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 9660389..8112bb8 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -22,6 +22,7 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityThread;
+import android.app.ApplicationExitInfo;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.Message;
@@ -132,11 +133,15 @@
     static final int REPORT_UNFREEZE_MSG = 4;
 
     //TODO:change this static definition into a configurable flag.
-    static final int FREEZE_TIMEOUT_MS = 500;
+    static final int FREEZE_TIMEOUT_MS = 10000;
 
     static final int DO_FREEZE = 1;
     static final int REPORT_UNFREEZE = 2;
 
+    // Bitfield values for sync/async transactions reveived by frozen processes
+    static final int SYNC_RECEIVED_WHILE_FROZEN = 1;
+    static final int ASYNC_RECEIVED_WHILE_FROZEN = 2;
+
     /**
      * This thread must be moved to the system background cpuset.
      * If that doesn't happen, it's probably going to draw a lot of power.
@@ -494,6 +499,15 @@
     private static native void freezeBinder(int pid, boolean freeze);
 
     /**
+     * Retrieves binder freeze info about a process.
+     * @param pid the pid for which binder freeze info is to be retrieved.
+     *
+     * @throws RuntimeException if the operation could not complete successfully.
+     * @return a bit field reporting the binder freeze info for the process.
+     */
+    private static native int getBinderFreezeInfo(int pid);
+
+    /**
      * Determines whether the freezer is supported by this system
      */
     public static boolean isFreezerSupported() {
@@ -729,6 +743,37 @@
             return;
         }
 
+        boolean processKilled = false;
+
+        try {
+            int freezeInfo = getBinderFreezeInfo(app.pid);
+
+            if ((freezeInfo & SYNC_RECEIVED_WHILE_FROZEN) != 0) {
+                Slog.d(TAG_AM, "pid " + app.pid + " " + app.processName + " "
+                        + " received sync transactions while frozen, killing");
+                app.kill("Sync transaction while in frozen state",
+                        ApplicationExitInfo.REASON_OTHER,
+                        ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+                processKilled = true;
+            }
+
+            if ((freezeInfo & ASYNC_RECEIVED_WHILE_FROZEN) != 0) {
+                Slog.d(TAG_AM, "pid " + app.pid + " " + app.processName + " "
+                        + " received async transactions while frozen");
+            }
+        } catch (Exception e) {
+            Slog.d(TAG_AM, "Unable to query binder frozen info for pid " + app.pid + " "
+                    + app.processName + ". Killing it. Exception: " + e);
+            app.kill("Unable to query binder frozen stats",
+                    ApplicationExitInfo.REASON_OTHER,
+                    ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+            processKilled = true;
+        }
+
+        if (processKilled) {
+            return;
+        }
+
         long freezeTime = app.freezeUnfreezeTime;
 
         try {
@@ -745,8 +790,12 @@
             try {
                 freezeBinder(app.pid, false);
             } catch (RuntimeException e) {
-                // TODO: it might be preferable to kill the target pid in this case
-                Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName);
+                Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName
+                        + ". Killing it");
+                app.kill("Unable to unfreeze",
+                        ApplicationExitInfo.REASON_OTHER,
+                        ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+                return;
             }
 
             if (DEBUG_FREEZER) {
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 95d4ba7..678308a 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -36,6 +36,9 @@
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 
+#define SYNC_RECEIVED_WHILE_FROZEN (1)
+#define ASYNC_RECEIVED_WHILE_FROZEN (2)
+
 namespace android {
 
 // This performs per-process reclaim on all processes belonging to non-app UIDs.
@@ -99,12 +102,37 @@
     }
 }
 
+static jint com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo(JNIEnv *env,
+        jobject clazz, jint pid) {
+    bool syncReceived = false, asyncReceived = false;
+
+    int error = IPCThreadState::getProcessFreezeInfo(pid, &syncReceived, &asyncReceived);
+
+    if (error < 0) {
+        jniThrowException(env, "java/lang/RuntimeException", strerror(error));
+    }
+
+    jint retVal = 0;
+
+    if(syncReceived) {
+        retVal |= SYNC_RECEIVED_WHILE_FROZEN;;
+    }
+
+    if(asyncReceived) {
+        retVal |= ASYNC_RECEIVED_WHILE_FROZEN;
+    }
+
+    return retVal;
+}
+
 static const JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     {"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
     {"enableFreezerInternal", "(Z)V",
         (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal},
-    {"freezeBinder", "(IZ)V", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder}
+    {"freezeBinder", "(IZ)V", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder},
+    {"getBinderFreezeInfo", "(I)I",
+        (void*)com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo}
 };
 
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env)