freezer: reentrant enable/disable method
the app freezer state can be toggled in multiple situations when a debugging tool like heapdump is invoked, or when system_server dumps its binder connections. All these uses are potentially concurrent and a robust method to handle reentrancy is necessary to avoid leaving the freezer in a state incompatible with a specific operation. This patch moves freezer enable and disable operations from Process to CachedAppOptimizer (ActivityManager), introduces a new ActivityManager API to centralize all freezer state changes to ActivityManager and modifies client code accordingly. Bug: 151225245 Test: manually verified that no regression are introduced on freezer behavior, verified that concurrent behavior is handled properly Change-Id: I7d588cc6e0499012dce64ed4e42ff2adb336062d
This commit is contained in:
@@ -695,4 +695,14 @@ interface IActivityManager {
|
|||||||
* android.permission.RESET_APP_ERRORS.
|
* android.permission.RESET_APP_ERRORS.
|
||||||
*/
|
*/
|
||||||
void resetAppErrors();
|
void resetAppErrors();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control the app freezer state. Returns true in case of success, false if the operation
|
||||||
|
* didn't succeed (for example, when the app freezer isn't supported).
|
||||||
|
* Handling the freezer state via this method is reentrant, that is it can be
|
||||||
|
* disabled and re-enabled multiple times in parallel. As long as there's a 1:1 disable to
|
||||||
|
* enable match, the freezer is re-enabled at last enable only.
|
||||||
|
* @param enable set it to true to enable the app freezer, false to disable it.
|
||||||
|
*/
|
||||||
|
boolean enableAppFreezer(in boolean enable);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package android.os;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.app.ActivityManager;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
@@ -255,7 +256,12 @@ public final class BinderProxy implements IBinder {
|
|||||||
// out of system_server to all processes hosting binder objects it holds a reference to;
|
// out of system_server to all processes hosting binder objects it holds a reference to;
|
||||||
// since some of those processes might be frozen, we don't want to block here
|
// since some of those processes might be frozen, we don't want to block here
|
||||||
// forever. Disable the freezer.
|
// forever. Disable the freezer.
|
||||||
Process.enableFreezer(false);
|
try {
|
||||||
|
ActivityManager.getService().enableAppFreezer(false);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(Binder.TAG, "RemoteException while disabling app freezer");
|
||||||
|
}
|
||||||
|
|
||||||
for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
|
for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
|
||||||
BinderProxy bp = weakRef.get();
|
BinderProxy bp = weakRef.get();
|
||||||
String key;
|
String key;
|
||||||
@@ -278,7 +284,11 @@ public final class BinderProxy implements IBinder {
|
|||||||
counts.put(key, i + 1);
|
counts.put(key, i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Process.enableFreezer(true);
|
try {
|
||||||
|
ActivityManager.getService().enableAppFreezer(true);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(Binder.TAG, "RemoteException while re-enabling app freezer");
|
||||||
|
}
|
||||||
Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray(
|
Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray(
|
||||||
new Map.Entry[counts.size()]);
|
new Map.Entry[counts.size()]);
|
||||||
|
|
||||||
|
|||||||
@@ -372,22 +372,6 @@ void android_os_Process_setProcessFrozen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void android_os_Process_enableFreezer(
|
|
||||||
JNIEnv *env, jobject clazz, jboolean enable)
|
|
||||||
{
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
if (enable) {
|
|
||||||
success = SetTaskProfiles(0, {"FreezerEnabled"}, true);
|
|
||||||
} else {
|
|
||||||
success = SetTaskProfiles(0, {"FreezerDisabled"}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
|
jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
|
||||||
{
|
{
|
||||||
SchedPolicy sp;
|
SchedPolicy sp;
|
||||||
@@ -1424,7 +1408,6 @@ static const JNINativeMethod methods[] = {
|
|||||||
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
|
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
|
||||||
{"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
|
{"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
|
||||||
{"setProcessFrozen", "(IIZ)V", (void*)android_os_Process_setProcessFrozen},
|
{"setProcessFrozen", "(IIZ)V", (void*)android_os_Process_setProcessFrozen},
|
||||||
{"enableFreezer", "(Z)V", (void*)android_os_Process_enableFreezer},
|
|
||||||
{"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
|
{"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
|
||||||
{"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
|
{"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
|
||||||
{"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V",
|
{"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V",
|
||||||
|
|||||||
@@ -2103,17 +2103,13 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
@Override
|
@Override
|
||||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
try {
|
try {
|
||||||
if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
|
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
|
||||||
Process.enableFreezer(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
|
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
|
||||||
"meminfo", pw)) return;
|
"meminfo", pw)) return;
|
||||||
PriorityDump.dump(mPriorityDumper, fd, pw, args);
|
PriorityDump.dump(mPriorityDumper, fd, pw, args);
|
||||||
} finally {
|
} finally {
|
||||||
if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
|
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
|
||||||
Process.enableFreezer(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2127,17 +2123,13 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
@Override
|
@Override
|
||||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
try {
|
try {
|
||||||
if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
|
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
|
||||||
Process.enableFreezer(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
|
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
|
||||||
"gfxinfo", pw)) return;
|
"gfxinfo", pw)) return;
|
||||||
mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);
|
mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);
|
||||||
} finally {
|
} finally {
|
||||||
if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
|
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
|
||||||
Process.enableFreezer(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2151,17 +2143,13 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
@Override
|
@Override
|
||||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
try {
|
try {
|
||||||
if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
|
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
|
||||||
Process.enableFreezer(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
|
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
|
||||||
"dbinfo", pw)) return;
|
"dbinfo", pw)) return;
|
||||||
mActivityManagerService.dumpDbInfo(fd, pw, args);
|
mActivityManagerService.dumpDbInfo(fd, pw, args);
|
||||||
} finally {
|
} finally {
|
||||||
if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
|
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
|
||||||
Process.enableFreezer(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2207,9 +2195,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
@Override
|
@Override
|
||||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
try {
|
try {
|
||||||
if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
|
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
|
||||||
Process.enableFreezer(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
|
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
|
||||||
"cacheinfo", pw)) {
|
"cacheinfo", pw)) {
|
||||||
@@ -2218,9 +2204,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
|
|
||||||
mActivityManagerService.dumpBinderCacheContents(fd, pw, args);
|
mActivityManagerService.dumpBinderCacheContents(fd, pw, args);
|
||||||
} finally {
|
} finally {
|
||||||
if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
|
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
|
||||||
Process.enableFreezer(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16800,14 +16784,14 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process.enableFreezer(false);
|
mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
|
||||||
|
|
||||||
final RemoteCallback intermediateCallback = new RemoteCallback(
|
final RemoteCallback intermediateCallback = new RemoteCallback(
|
||||||
new RemoteCallback.OnResultListener() {
|
new RemoteCallback.OnResultListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onResult(Bundle result) {
|
public void onResult(Bundle result) {
|
||||||
finishCallback.sendResult(result);
|
finishCallback.sendResult(result);
|
||||||
Process.enableFreezer(true);
|
mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
|
||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
@@ -18737,4 +18721,16 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
mAppErrors.resetStateLocked();
|
mAppErrors.resetStateLocked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean enableAppFreezer(boolean enable) {
|
||||||
|
int callerUid = Binder.getCallingUid();
|
||||||
|
|
||||||
|
// Only system can toggle the freezer state
|
||||||
|
if (callerUid == SYSTEM_UID) {
|
||||||
|
return mOomAdjuster.mCachedAppOptimizer.enableFreezer(enable);
|
||||||
|
} else {
|
||||||
|
throw new SecurityException("Caller uid " + callerUid + " cannot set freezer state ");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,6 +208,8 @@ public final class CachedAppOptimizer {
|
|||||||
@GuardedBy("mPhenotypeFlagLock")
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
|
private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
|
||||||
private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER;
|
private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER;
|
||||||
|
@GuardedBy("this")
|
||||||
|
private int mFreezerDisableCount = 1; // Freezer is initially disabled, until enabled
|
||||||
private final Random mRandom = new Random();
|
private final Random mRandom = new Random();
|
||||||
@GuardedBy("mPhenotypeFlagLock")
|
@GuardedBy("mPhenotypeFlagLock")
|
||||||
@VisibleForTesting volatile float mCompactStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
|
@VisibleForTesting volatile float mCompactStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
|
||||||
@@ -419,6 +421,63 @@ public final class CachedAppOptimizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disabled the app freezer.
|
||||||
|
* @param enable Enables the freezer if true, disables it if false.
|
||||||
|
* @return true if the operation completed successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
public synchronized boolean enableFreezer(boolean enable) {
|
||||||
|
if (!mUseFreezer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
mFreezerDisableCount--;
|
||||||
|
|
||||||
|
if (mFreezerDisableCount > 0) {
|
||||||
|
return true;
|
||||||
|
} else if (mFreezerDisableCount < 0) {
|
||||||
|
Slog.e(TAG_AM, "unbalanced call to enableFreezer, ignoring");
|
||||||
|
mFreezerDisableCount = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mFreezerDisableCount++;
|
||||||
|
|
||||||
|
if (mFreezerDisableCount > 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
enableFreezerInternal(enable);
|
||||||
|
return true;
|
||||||
|
} catch (java.lang.RuntimeException e) {
|
||||||
|
if (enable) {
|
||||||
|
mFreezerDisableCount = 0;
|
||||||
|
} else {
|
||||||
|
mFreezerDisableCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slog.e(TAG_AM, "Exception handling freezer state (enable: " + enable + "): "
|
||||||
|
+ e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable the freezer. When enable == false all frozen processes are unfrozen,
|
||||||
|
* but aren't removed from the freezer. While in this state, processes can be added or removed
|
||||||
|
* by using Process.setProcessFrozen(), but they wouldn't be actually frozen until the freezer
|
||||||
|
* is enabled. If enable == true all processes in the freezer are frozen.
|
||||||
|
*
|
||||||
|
* @param enable Specify whether to enable (true) or disable (false) the freezer.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
private static native void enableFreezerInternal(boolean enable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the freezer is supported by this system
|
* Determines whether the freezer is supported by this system
|
||||||
*/
|
*/
|
||||||
@@ -471,7 +530,7 @@ public final class CachedAppOptimizer {
|
|||||||
|
|
||||||
if (mUseFreezer && mFreezeHandler == null) {
|
if (mUseFreezer && mFreezeHandler == null) {
|
||||||
Slog.d(TAG_AM, "Freezer enabled");
|
Slog.d(TAG_AM, "Freezer enabled");
|
||||||
Process.enableFreezer(true);
|
enableFreezer(true);
|
||||||
|
|
||||||
if (!mCachedAppOptimizerThread.isAlive()) {
|
if (!mCachedAppOptimizerThread.isAlive()) {
|
||||||
mCachedAppOptimizerThread.start();
|
mCachedAppOptimizerThread.start();
|
||||||
@@ -482,7 +541,7 @@ public final class CachedAppOptimizer {
|
|||||||
Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
|
Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
|
||||||
Process.THREAD_GROUP_SYSTEM);
|
Process.THREAD_GROUP_SYSTEM);
|
||||||
} else {
|
} else {
|
||||||
Process.enableFreezer(false);
|
enableFreezer(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ cc_defaults {
|
|||||||
"libnativehelper",
|
"libnativehelper",
|
||||||
"libnativewindow",
|
"libnativewindow",
|
||||||
"libpowermanager",
|
"libpowermanager",
|
||||||
|
"libprocessgroup",
|
||||||
"libutils",
|
"libutils",
|
||||||
"libui",
|
"libui",
|
||||||
"libvibratorservice",
|
"libvibratorservice",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <nativehelper/JNIHelp.h>
|
#include <nativehelper/JNIHelp.h>
|
||||||
#include <android_runtime/AndroidRuntime.h>
|
#include <android_runtime/AndroidRuntime.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
#include <processgroup/processgroup.h>
|
||||||
|
|
||||||
using android::base::StringPrintf;
|
using android::base::StringPrintf;
|
||||||
using android::base::WriteStringToFile;
|
using android::base::WriteStringToFile;
|
||||||
@@ -74,9 +75,26 @@ static void com_android_server_am_CachedAppOptimizer_compactSystem(JNIEnv *, job
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void com_android_server_am_CachedAppOptimizer_enableFreezerInternal(
|
||||||
|
JNIEnv *env, jobject clazz, jboolean enable) {
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
success = SetTaskProfiles(0, {"FreezerEnabled"}, true);
|
||||||
|
} else {
|
||||||
|
success = SetTaskProfiles(0, {"FreezerDisabled"}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const JNINativeMethod sMethods[] = {
|
static const JNINativeMethod sMethods[] = {
|
||||||
/* name, signature, funcPtr */
|
/* name, signature, funcPtr */
|
||||||
{"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
|
{"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
|
||||||
|
{"enableFreezerInternal", "(Z)V",
|
||||||
|
(void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal},
|
||||||
};
|
};
|
||||||
|
|
||||||
int register_android_server_am_CachedAppOptimizer(JNIEnv* env)
|
int register_android_server_am_CachedAppOptimizer(JNIEnv* env)
|
||||||
|
|||||||
Reference in New Issue
Block a user