diff options
| author | 2020-09-10 13:36:14 -0700 | |
|---|---|---|
| committer | 2020-09-14 20:25:15 +0000 | |
| commit | 5b5fdb80ec9ffa00a4d35dfc84fa8f28d9a6d8fb (patch) | |
| tree | 010539c052b5d906a460cf572ada31aa14debf26 | |
| parent | a2da145ff6cdf0767b91998c17d33d0c601c543c (diff) | |
ActivityManager: kill frozen processes receiving sync transactions
Synchronous transactions to frozen processes are rejected by binder,
which can potentially leave these processes in an unclean state when
unfrozen. Kill such processes insted of unfreezing then when they're
removed from the cache. This patch also increases the timeout before
freezing an app, to allow pending transactions to be processes for
a longer window after caching and so to reduce the amount of background
kills.
Bug: 143717177
Test: cached/frozen a few apps, sent sync and async transactions to them
and verified that killing happened when expected.
Change-Id: Ieca9d49e1befd1358862aa7afeeec15a408d7ef3
| -rw-r--r-- | services/core/java/com/android/server/am/CachedAppOptimizer.java | 55 | ||||
| -rw-r--r-- | services/core/jni/com_android_server_am_CachedAppOptimizer.cpp | 30 |
2 files changed, 81 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 966038986791..8112bb854b71 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 static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 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 @@ public final class CachedAppOptimizer { 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 @@ public final class CachedAppOptimizer { 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 @@ public final class CachedAppOptimizer { 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 @@ public final class CachedAppOptimizer { 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 95d4ba7c199a..678308af34ea 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 void com_android_server_am_CachedAppOptimizer_freezeBinder( } } +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) |