Loading services/core/java/com/android/server/am/ActivityManagerService.java +19 −1 Original line number Diff line number Diff line Loading @@ -1716,6 +1716,12 @@ public class ActivityManagerService extends IActivityManager.Stub */ @Nullable volatile ContentCaptureManagerInternal mContentCaptureService; /** * The interface to the freezer. */ @NonNull private final Freezer mFreezer; /* * The default duration for the binder heavy hitter auto sampler */ Loading Loading @@ -2506,6 +2512,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Nullable UserController userController) { mInjector = injector; mContext = mInjector.getContext(); mFreezer = injector.getFreezer(); mUiContext = null; mAppErrors = injector.getAppErrors(); mPackageWatchdog = null; Loading Loading @@ -2555,6 +2562,7 @@ public class ActivityManagerService extends IActivityManager.Stub LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY); mInjector = new Injector(systemContext); mContext = systemContext; mFreezer = mInjector.getFreezer(); mFactoryTest = FactoryTest.getMode(); mSystemThread = ActivityThread.currentActivityThread(); Loading Loading @@ -20919,6 +20927,11 @@ public class ActivityManagerService extends IActivityManager.Stub public IntentFirewall getIntentFirewall() { return null; } /** @return the default Freezer. */ public Freezer getFreezer() { return new Freezer(); } } @Override Loading Loading @@ -21022,7 +21035,7 @@ public class ActivityManagerService extends IActivityManager.Stub final long token = Binder.clearCallingIdentity(); try { return CachedAppOptimizer.isFreezerSupported(); return mFreezer.isFreezerSupported(); } finally { Binder.restoreCallingIdentity(token); } Loading Loading @@ -21177,4 +21190,9 @@ public class ActivityManagerService extends IActivityManager.Stub void clearPendingTopAppLocked() { mPendingStartActivityUids.clear(); } @NonNull Freezer getFreezer() { return mFreezer; } } services/core/java/com/android/server/am/CachedAppOptimizer.java +29 −93 Original line number Diff line number Diff line Loading @@ -664,6 +664,8 @@ public final class CachedAppOptimizer { private final ProcessDependencies mProcessDependencies; private final ProcLocksReader mProcLocksReader; private final Freezer mFreezer; public CachedAppOptimizer(ActivityManagerService am) { this(am, null, new DefaultProcessDependencies()); } Loading @@ -680,6 +682,7 @@ public final class CachedAppOptimizer { mTestCallback = callback; mSettingsObserver = new SettingsContentObserver(); mProcLocksReader = new ProcLocksReader(); mFreezer = mAm.getFreezer(); } /** Loading Loading @@ -1049,89 +1052,6 @@ public final class CachedAppOptimizer { return true; } /** * Informs binder that a process is about to be frozen. If freezer is enabled on a process via * this method, this method will synchronously dispatch all pending transactions to the * specified pid. This method will not add significant latencies when unfreezing. * After freezing binder calls, binder will block all transaction to the frozen pid, and return * an error to the sending process. * * @param pid the target pid for which binder transactions are to be frozen * @param freeze specifies whether to flush transactions and then freeze (true) or unfreeze * binder for the specificed pid. * @param timeoutMs the timeout in milliseconds to wait for the binder interface to freeze * before giving up. * * @throws RuntimeException in case a flush/freeze operation could not complete successfully. * @return 0 if success, or -EAGAIN indicating there's pending transaction. */ public static native int freezeBinder(int pid, boolean freeze, int timeoutMs); /** * 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); /** * Returns the path to be checked to verify whether the freezer is supported by this system. * @return absolute path to the file */ private static native String getFreezerCheckPath(); /** * Check if task_profiles.json includes valid freezer profiles and actions * @return false if there are invalid profiles or actions */ private static native boolean isFreezerProfileValid(); /** * Determines whether the freezer is supported by this system */ public static boolean isFreezerSupported() { boolean supported = false; FileReader fr = null; try { String path = getFreezerCheckPath(); Slog.d(TAG_AM, "Checking cgroup freezer: " + path); fr = new FileReader(path); char state = (char) fr.read(); if (state == '1' || state == '0') { // Also check freezer binder ioctl Slog.d(TAG_AM, "Checking binder freezer ioctl"); getBinderFreezeInfo(Process.myPid()); // Check if task_profiles.json contains invalid profiles Slog.d(TAG_AM, "Checking freezer profiles"); supported = isFreezerProfileValid(); } else { Slog.e(TAG_AM, "Unexpected value in cgroup.freeze"); } } catch (java.io.FileNotFoundException e) { Slog.w(TAG_AM, "File cgroup.freeze not present"); } catch (RuntimeException e) { Slog.w(TAG_AM, "Unable to read freezer info"); } catch (Exception e) { Slog.w(TAG_AM, "Unable to read cgroup.freeze: " + e.toString()); } if (fr != null) { try { fr.close(); } catch (java.io.IOException e) { Slog.e(TAG_AM, "Exception closing cgroup.freeze: " + e.toString()); } } Slog.d(TAG_AM, "Freezer supported: " + supported); return supported; } /** * Reads the flag value from DeviceConfig to determine whether app freezer * should be enabled, and starts the freeze/compaction thread if needed. Loading @@ -1146,7 +1066,7 @@ public final class CachedAppOptimizer { } else if ("enabled".equals(configOverride) || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) { mUseFreezer = isFreezerSupported(); mUseFreezer = mFreezer.isFreezerSupported(); updateFreezerDebounceTimeout(); updateFreezerExemptInstPkg(); } else { Loading Loading @@ -1528,7 +1448,7 @@ public final class CachedAppOptimizer { boolean processKilled = false; try { int freezeInfo = getBinderFreezeInfo(pid); int freezeInfo = mFreezer.getBinderFreezeInfo(pid); if ((freezeInfo & SYNC_RECEIVED_WHILE_FROZEN) != 0) { Slog.d(TAG_AM, "pid " + pid + " " + app.processName Loading Loading @@ -1562,7 +1482,7 @@ public final class CachedAppOptimizer { long freezeTime = opt.getFreezeUnfreezeTime(); try { freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); mFreezer.freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); } catch (RuntimeException e) { Slog.e(TAG_AM, "Unable to unfreeze binder for " + pid + " " + app.processName + ". Killing it"); Loading @@ -1574,7 +1494,7 @@ public final class CachedAppOptimizer { try { traceAppFreeze(app.processName, pid, reason); Process.setProcessFrozen(pid, app.uid, false); mFreezer.setProcessFrozen(pid, app.uid, false); opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); opt.setFrozen(false); Loading Loading @@ -1617,7 +1537,7 @@ public final class CachedAppOptimizer { } Slog.d(TAG_AM, "quick sync unfreeze " + pid + " for " + reason); try { freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); mFreezer.freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); } catch (RuntimeException e) { Slog.e(TAG_AM, "Unable to quick unfreeze binder for " + pid); return; Loading @@ -1625,7 +1545,7 @@ public final class CachedAppOptimizer { try { traceAppFreeze(app.processName, pid, reason); Process.setProcessFrozen(pid, app.uid, false); mFreezer.setProcessFrozen(pid, app.uid, false); } catch (Exception e) { Slog.e(TAG_AM, "Unable to quick unfreeze " + pid); } Loading Loading @@ -2394,7 +2314,7 @@ public final class CachedAppOptimizer { // Freeze binder interface before the process, to flush any // transactions that might be pending. try { if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) { if (mFreezer.freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) { handleBinderFreezerFailure(proc, "outstanding txns"); return; } Loading @@ -2413,7 +2333,7 @@ public final class CachedAppOptimizer { try { traceAppFreeze(proc.processName, pid, -1); Process.setProcessFrozen(pid, proc.uid, true); mFreezer.setProcessFrozen(pid, proc.uid, true); opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); opt.setFrozen(true); opt.setHasCollectedFrozenPSS(false); Loading Loading @@ -2452,7 +2372,7 @@ public final class CachedAppOptimizer { try { // post-check to prevent races int freezeInfo = getBinderFreezeInfo(pid); int freezeInfo = mFreezer.getBinderFreezeInfo(pid); if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) { synchronized (mProcLock) { Loading Loading @@ -2619,6 +2539,22 @@ public final class CachedAppOptimizer { }); } /** * Freeze or unfreeze a process. This should only be used for testing. */ @VisibleForTesting void forceFreezeForTest(ProcessRecord proc, boolean freeze) { synchronized (mAm) { synchronized (mProcLock) { if (freeze) { forceFreezeAppAsyncLSP(proc); } else { unfreezeAppInternalLSP(proc, UNFREEZE_REASON_NONE, true); } } } } /** * Sending binder transactions to frozen apps most likely indicates there's a bug. Log it and * kill the frozen apps if they 1) receive sync binder transactions while frozen, or 2) miss Loading Loading @@ -2660,7 +2596,7 @@ public final class CachedAppOptimizer { for (int i = 0; i < pids.size(); i++) { int current = pids.get(i); try { int freezeInfo = getBinderFreezeInfo(current); int freezeInfo = mFreezer.getBinderFreezeInfo(current); if ((freezeInfo & SYNC_RECEIVED_WHILE_FROZEN) != 0) { killProcess(current, "Sync transaction while frozen", Loading services/core/java/com/android/server/am/Freezer.java 0 → 100644 +115 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import android.os.Process; /** * A collection of interfaces to manage the freezer. All access to the freezer goes through an * instance of this class. The class can be overridden for testing. * * Methods may be called without external synchronization. Multiple instances of this class can be * used concurrently. */ class Freezer { /** * Freeze or unfreeze the specified process. * * @param pid Identifier of the process to freeze or unfreeze. * @param uid Identifier of the user the process is running under. * @param frozen Specify whether to free (true) or unfreeze (false). */ public void setProcessFrozen(int pid, int uid, boolean frozen) { Process.setProcessFrozen(pid, uid, frozen); } /** * Informs binder that a process is about to be frozen. If freezer is enabled on a process via * this method, this method will synchronously dispatch all pending transactions to the * specified pid. This method will not add significant latencies when unfreezing. * After freezing binder calls, binder will block all transaction to the frozen pid, and return * an error to the sending process. * * @param pid the target pid for which binder transactions are to be frozen * @param freeze specifies whether to flush transactions and then freeze (true) or unfreeze * binder for the specified pid. * @param timeoutMs the timeout in milliseconds to wait for the binder interface to freeze * before giving up. * * @throws RuntimeException in case a flush/freeze operation could not complete successfully. * @return 0 if success, or -EAGAIN indicating there's pending transaction. */ public int freezeBinder(int pid, boolean freeze, int timeoutMs) { return nativeFreezeBinder(pid, freeze, timeoutMs); } /** * 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. */ public int getBinderFreezeInfo(int pid) { return nativeGetBinderFreezeInfo(pid); } /** * Determines whether the freezer is supported by this system. * @return true if the freezer is supported. */ public boolean isFreezerSupported() { return nativeIsFreezerSupported(); } // Native methods /** * Informs binder that a process is about to be frozen. If freezer is enabled on a process via * this method, this method will synchronously dispatch all pending transactions to the * specified pid. This method will not add significant latencies when unfreezing. * After freezing binder calls, binder will block all transaction to the frozen pid, and return * an error to the sending process. * * @param pid the target pid for which binder transactions are to be frozen * @param freeze specifies whether to flush transactions and then freeze (true) or unfreeze * binder for the specified pid. * @param timeoutMs the timeout in milliseconds to wait for the binder interface to freeze * before giving up. * * @throws RuntimeException in case a flush/freeze operation could not complete successfully. * @return 0 if success, or -EAGAIN indicating there's pending transaction. */ private static native int nativeFreezeBinder(int pid, boolean freeze, int timeoutMs); /** * 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 nativeGetBinderFreezeInfo(int pid); /** * Return 0 if the freezer is supported on this platform and -1 otherwise. */ private static native boolean nativeIsFreezerSupported(); } services/core/java/com/android/server/am/ProcessList.java +2 −2 Original line number Diff line number Diff line Loading @@ -3005,7 +3005,7 @@ public final class ProcessList { return freezePackageCgroup(packageUID, false); } private static void freezeBinderAndPackageCgroup(List<Pair<ProcessRecord, Boolean>> procs, private void freezeBinderAndPackageCgroup(List<Pair<ProcessRecord, Boolean>> procs, int packageUID) { // Freeze all binder processes under the target UID (whose cgroup is about to be frozen). // Since we're going to kill these, we don't need to unfreze them later. Loading @@ -3019,7 +3019,7 @@ public final class ProcessList { try { int rc; do { rc = CachedAppOptimizer.freezeBinder(pid, true, 10 /* timeout_ms */); rc = mService.getFreezer().freezeBinder(pid, true, 10 /* timeout_ms */); } while (rc == -EAGAIN && nRetries++ < 1); if (rc != 0) Slog.e(TAG, "Unable to freeze binder for " + pid + ": " + rc); } catch (RuntimeException e) { Loading services/core/jni/Android.bp +8 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ cc_library_static { "com_android_server_wm_TaskFpsCallbackController.cpp", "onload.cpp", ":lib_cachedAppOptimizer_native", ":lib_freezer_native", ":lib_gameManagerService_native", ":lib_oomConnection_native", ":lib_anrTimer_native", Loading Loading @@ -240,6 +241,13 @@ filegroup { ], } filegroup { name: "lib_freezer_native", srcs: [ "com_android_server_am_Freezer.cpp", ], } filegroup { name: "lib_gameManagerService_native", srcs: [ Loading Loading
services/core/java/com/android/server/am/ActivityManagerService.java +19 −1 Original line number Diff line number Diff line Loading @@ -1716,6 +1716,12 @@ public class ActivityManagerService extends IActivityManager.Stub */ @Nullable volatile ContentCaptureManagerInternal mContentCaptureService; /** * The interface to the freezer. */ @NonNull private final Freezer mFreezer; /* * The default duration for the binder heavy hitter auto sampler */ Loading Loading @@ -2506,6 +2512,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Nullable UserController userController) { mInjector = injector; mContext = mInjector.getContext(); mFreezer = injector.getFreezer(); mUiContext = null; mAppErrors = injector.getAppErrors(); mPackageWatchdog = null; Loading Loading @@ -2555,6 +2562,7 @@ public class ActivityManagerService extends IActivityManager.Stub LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY); mInjector = new Injector(systemContext); mContext = systemContext; mFreezer = mInjector.getFreezer(); mFactoryTest = FactoryTest.getMode(); mSystemThread = ActivityThread.currentActivityThread(); Loading Loading @@ -20919,6 +20927,11 @@ public class ActivityManagerService extends IActivityManager.Stub public IntentFirewall getIntentFirewall() { return null; } /** @return the default Freezer. */ public Freezer getFreezer() { return new Freezer(); } } @Override Loading Loading @@ -21022,7 +21035,7 @@ public class ActivityManagerService extends IActivityManager.Stub final long token = Binder.clearCallingIdentity(); try { return CachedAppOptimizer.isFreezerSupported(); return mFreezer.isFreezerSupported(); } finally { Binder.restoreCallingIdentity(token); } Loading Loading @@ -21177,4 +21190,9 @@ public class ActivityManagerService extends IActivityManager.Stub void clearPendingTopAppLocked() { mPendingStartActivityUids.clear(); } @NonNull Freezer getFreezer() { return mFreezer; } }
services/core/java/com/android/server/am/CachedAppOptimizer.java +29 −93 Original line number Diff line number Diff line Loading @@ -664,6 +664,8 @@ public final class CachedAppOptimizer { private final ProcessDependencies mProcessDependencies; private final ProcLocksReader mProcLocksReader; private final Freezer mFreezer; public CachedAppOptimizer(ActivityManagerService am) { this(am, null, new DefaultProcessDependencies()); } Loading @@ -680,6 +682,7 @@ public final class CachedAppOptimizer { mTestCallback = callback; mSettingsObserver = new SettingsContentObserver(); mProcLocksReader = new ProcLocksReader(); mFreezer = mAm.getFreezer(); } /** Loading Loading @@ -1049,89 +1052,6 @@ public final class CachedAppOptimizer { return true; } /** * Informs binder that a process is about to be frozen. If freezer is enabled on a process via * this method, this method will synchronously dispatch all pending transactions to the * specified pid. This method will not add significant latencies when unfreezing. * After freezing binder calls, binder will block all transaction to the frozen pid, and return * an error to the sending process. * * @param pid the target pid for which binder transactions are to be frozen * @param freeze specifies whether to flush transactions and then freeze (true) or unfreeze * binder for the specificed pid. * @param timeoutMs the timeout in milliseconds to wait for the binder interface to freeze * before giving up. * * @throws RuntimeException in case a flush/freeze operation could not complete successfully. * @return 0 if success, or -EAGAIN indicating there's pending transaction. */ public static native int freezeBinder(int pid, boolean freeze, int timeoutMs); /** * 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); /** * Returns the path to be checked to verify whether the freezer is supported by this system. * @return absolute path to the file */ private static native String getFreezerCheckPath(); /** * Check if task_profiles.json includes valid freezer profiles and actions * @return false if there are invalid profiles or actions */ private static native boolean isFreezerProfileValid(); /** * Determines whether the freezer is supported by this system */ public static boolean isFreezerSupported() { boolean supported = false; FileReader fr = null; try { String path = getFreezerCheckPath(); Slog.d(TAG_AM, "Checking cgroup freezer: " + path); fr = new FileReader(path); char state = (char) fr.read(); if (state == '1' || state == '0') { // Also check freezer binder ioctl Slog.d(TAG_AM, "Checking binder freezer ioctl"); getBinderFreezeInfo(Process.myPid()); // Check if task_profiles.json contains invalid profiles Slog.d(TAG_AM, "Checking freezer profiles"); supported = isFreezerProfileValid(); } else { Slog.e(TAG_AM, "Unexpected value in cgroup.freeze"); } } catch (java.io.FileNotFoundException e) { Slog.w(TAG_AM, "File cgroup.freeze not present"); } catch (RuntimeException e) { Slog.w(TAG_AM, "Unable to read freezer info"); } catch (Exception e) { Slog.w(TAG_AM, "Unable to read cgroup.freeze: " + e.toString()); } if (fr != null) { try { fr.close(); } catch (java.io.IOException e) { Slog.e(TAG_AM, "Exception closing cgroup.freeze: " + e.toString()); } } Slog.d(TAG_AM, "Freezer supported: " + supported); return supported; } /** * Reads the flag value from DeviceConfig to determine whether app freezer * should be enabled, and starts the freeze/compaction thread if needed. Loading @@ -1146,7 +1066,7 @@ public final class CachedAppOptimizer { } else if ("enabled".equals(configOverride) || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) { mUseFreezer = isFreezerSupported(); mUseFreezer = mFreezer.isFreezerSupported(); updateFreezerDebounceTimeout(); updateFreezerExemptInstPkg(); } else { Loading Loading @@ -1528,7 +1448,7 @@ public final class CachedAppOptimizer { boolean processKilled = false; try { int freezeInfo = getBinderFreezeInfo(pid); int freezeInfo = mFreezer.getBinderFreezeInfo(pid); if ((freezeInfo & SYNC_RECEIVED_WHILE_FROZEN) != 0) { Slog.d(TAG_AM, "pid " + pid + " " + app.processName Loading Loading @@ -1562,7 +1482,7 @@ public final class CachedAppOptimizer { long freezeTime = opt.getFreezeUnfreezeTime(); try { freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); mFreezer.freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); } catch (RuntimeException e) { Slog.e(TAG_AM, "Unable to unfreeze binder for " + pid + " " + app.processName + ". Killing it"); Loading @@ -1574,7 +1494,7 @@ public final class CachedAppOptimizer { try { traceAppFreeze(app.processName, pid, reason); Process.setProcessFrozen(pid, app.uid, false); mFreezer.setProcessFrozen(pid, app.uid, false); opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); opt.setFrozen(false); Loading Loading @@ -1617,7 +1537,7 @@ public final class CachedAppOptimizer { } Slog.d(TAG_AM, "quick sync unfreeze " + pid + " for " + reason); try { freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); mFreezer.freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); } catch (RuntimeException e) { Slog.e(TAG_AM, "Unable to quick unfreeze binder for " + pid); return; Loading @@ -1625,7 +1545,7 @@ public final class CachedAppOptimizer { try { traceAppFreeze(app.processName, pid, reason); Process.setProcessFrozen(pid, app.uid, false); mFreezer.setProcessFrozen(pid, app.uid, false); } catch (Exception e) { Slog.e(TAG_AM, "Unable to quick unfreeze " + pid); } Loading Loading @@ -2394,7 +2314,7 @@ public final class CachedAppOptimizer { // Freeze binder interface before the process, to flush any // transactions that might be pending. try { if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) { if (mFreezer.freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) { handleBinderFreezerFailure(proc, "outstanding txns"); return; } Loading @@ -2413,7 +2333,7 @@ public final class CachedAppOptimizer { try { traceAppFreeze(proc.processName, pid, -1); Process.setProcessFrozen(pid, proc.uid, true); mFreezer.setProcessFrozen(pid, proc.uid, true); opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); opt.setFrozen(true); opt.setHasCollectedFrozenPSS(false); Loading Loading @@ -2452,7 +2372,7 @@ public final class CachedAppOptimizer { try { // post-check to prevent races int freezeInfo = getBinderFreezeInfo(pid); int freezeInfo = mFreezer.getBinderFreezeInfo(pid); if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) { synchronized (mProcLock) { Loading Loading @@ -2619,6 +2539,22 @@ public final class CachedAppOptimizer { }); } /** * Freeze or unfreeze a process. This should only be used for testing. */ @VisibleForTesting void forceFreezeForTest(ProcessRecord proc, boolean freeze) { synchronized (mAm) { synchronized (mProcLock) { if (freeze) { forceFreezeAppAsyncLSP(proc); } else { unfreezeAppInternalLSP(proc, UNFREEZE_REASON_NONE, true); } } } } /** * Sending binder transactions to frozen apps most likely indicates there's a bug. Log it and * kill the frozen apps if they 1) receive sync binder transactions while frozen, or 2) miss Loading Loading @@ -2660,7 +2596,7 @@ public final class CachedAppOptimizer { for (int i = 0; i < pids.size(); i++) { int current = pids.get(i); try { int freezeInfo = getBinderFreezeInfo(current); int freezeInfo = mFreezer.getBinderFreezeInfo(current); if ((freezeInfo & SYNC_RECEIVED_WHILE_FROZEN) != 0) { killProcess(current, "Sync transaction while frozen", Loading
services/core/java/com/android/server/am/Freezer.java 0 → 100644 +115 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import android.os.Process; /** * A collection of interfaces to manage the freezer. All access to the freezer goes through an * instance of this class. The class can be overridden for testing. * * Methods may be called without external synchronization. Multiple instances of this class can be * used concurrently. */ class Freezer { /** * Freeze or unfreeze the specified process. * * @param pid Identifier of the process to freeze or unfreeze. * @param uid Identifier of the user the process is running under. * @param frozen Specify whether to free (true) or unfreeze (false). */ public void setProcessFrozen(int pid, int uid, boolean frozen) { Process.setProcessFrozen(pid, uid, frozen); } /** * Informs binder that a process is about to be frozen. If freezer is enabled on a process via * this method, this method will synchronously dispatch all pending transactions to the * specified pid. This method will not add significant latencies when unfreezing. * After freezing binder calls, binder will block all transaction to the frozen pid, and return * an error to the sending process. * * @param pid the target pid for which binder transactions are to be frozen * @param freeze specifies whether to flush transactions and then freeze (true) or unfreeze * binder for the specified pid. * @param timeoutMs the timeout in milliseconds to wait for the binder interface to freeze * before giving up. * * @throws RuntimeException in case a flush/freeze operation could not complete successfully. * @return 0 if success, or -EAGAIN indicating there's pending transaction. */ public int freezeBinder(int pid, boolean freeze, int timeoutMs) { return nativeFreezeBinder(pid, freeze, timeoutMs); } /** * 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. */ public int getBinderFreezeInfo(int pid) { return nativeGetBinderFreezeInfo(pid); } /** * Determines whether the freezer is supported by this system. * @return true if the freezer is supported. */ public boolean isFreezerSupported() { return nativeIsFreezerSupported(); } // Native methods /** * Informs binder that a process is about to be frozen. If freezer is enabled on a process via * this method, this method will synchronously dispatch all pending transactions to the * specified pid. This method will not add significant latencies when unfreezing. * After freezing binder calls, binder will block all transaction to the frozen pid, and return * an error to the sending process. * * @param pid the target pid for which binder transactions are to be frozen * @param freeze specifies whether to flush transactions and then freeze (true) or unfreeze * binder for the specified pid. * @param timeoutMs the timeout in milliseconds to wait for the binder interface to freeze * before giving up. * * @throws RuntimeException in case a flush/freeze operation could not complete successfully. * @return 0 if success, or -EAGAIN indicating there's pending transaction. */ private static native int nativeFreezeBinder(int pid, boolean freeze, int timeoutMs); /** * 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 nativeGetBinderFreezeInfo(int pid); /** * Return 0 if the freezer is supported on this platform and -1 otherwise. */ private static native boolean nativeIsFreezerSupported(); }
services/core/java/com/android/server/am/ProcessList.java +2 −2 Original line number Diff line number Diff line Loading @@ -3005,7 +3005,7 @@ public final class ProcessList { return freezePackageCgroup(packageUID, false); } private static void freezeBinderAndPackageCgroup(List<Pair<ProcessRecord, Boolean>> procs, private void freezeBinderAndPackageCgroup(List<Pair<ProcessRecord, Boolean>> procs, int packageUID) { // Freeze all binder processes under the target UID (whose cgroup is about to be frozen). // Since we're going to kill these, we don't need to unfreze them later. Loading @@ -3019,7 +3019,7 @@ public final class ProcessList { try { int rc; do { rc = CachedAppOptimizer.freezeBinder(pid, true, 10 /* timeout_ms */); rc = mService.getFreezer().freezeBinder(pid, true, 10 /* timeout_ms */); } while (rc == -EAGAIN && nRetries++ < 1); if (rc != 0) Slog.e(TAG, "Unable to freeze binder for " + pid + ": " + rc); } catch (RuntimeException e) { Loading
services/core/jni/Android.bp +8 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ cc_library_static { "com_android_server_wm_TaskFpsCallbackController.cpp", "onload.cpp", ":lib_cachedAppOptimizer_native", ":lib_freezer_native", ":lib_gameManagerService_native", ":lib_oomConnection_native", ":lib_anrTimer_native", Loading Loading @@ -240,6 +241,13 @@ filegroup { ], } filegroup { name: "lib_freezer_native", srcs: [ "com_android_server_am_Freezer.cpp", ], } filegroup { name: "lib_gameManagerService_native", srcs: [ Loading