Loading services/core/java/com/android/server/am/ProcessRecord.java +57 −25 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.procstats.ProcessState; import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.BatteryStatsImpl; Loading @@ -73,7 +74,7 @@ import java.util.List; * Full information about a particular process that * is currently running. */ final class ProcessRecord implements WindowProcessListener { class ProcessRecord implements WindowProcessListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM; private final ActivityManagerService mService; // where we came from Loading Loading @@ -1303,6 +1304,27 @@ final class ProcessRecord implements WindowProcessListener { ServerProtoEnums.DATA_APP; } /** * Unless configured otherwise, swallow ANRs in background processes & kill the process. * Non-private access is for tests only. */ @VisibleForTesting boolean isSilentAnr() { return !getShowBackground() && !isInterestingForBackgroundTraces(); } /** Non-private access is for tests only. */ @VisibleForTesting List<ProcessRecord> getLruProcessList() { return mService.mProcessList.mLruProcesses; } /** Non-private access is for tests only. */ @VisibleForTesting boolean isMonitorCpuUsage() { return mService.MONITOR_CPU_USAGE; } void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, String annotation) { Loading @@ -1312,16 +1334,10 @@ final class ProcessRecord implements WindowProcessListener { mWindowProcessController.appEarlyNotResponding(annotation, () -> kill("anr", true)); long anrTime = SystemClock.uptimeMillis(); if (ActivityManagerService.MONITOR_CPU_USAGE) { if (isMonitorCpuUsage()) { mService.updateCpuStatsNow(); } // Unless configured otherwise, swallow ANRs in background processes & kill the process. boolean showBackground = Settings.Secure.getInt(mService.mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; boolean isSilentANR; synchronized (mService) { // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down. if (mService.mAtmInternal.isShuttingDown()) { Loading Loading @@ -1353,8 +1369,7 @@ final class ProcessRecord implements WindowProcessListener { firstPids.add(pid); // Don't dump other PIDs if it's a background ANR isSilentANR = !showBackground && !isInterestingForBackgroundTraces(); if (!isSilentANR) { if (!isSilentAnr()) { int parentPid = pid; if (parentProcess != null && parentProcess.getPid() > 0) { parentPid = parentProcess.getPid(); Loading @@ -1363,8 +1378,8 @@ final class ProcessRecord implements WindowProcessListener { if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID); for (int i = mService.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mService.mProcessList.mLruProcesses.get(i); for (int i = getLruProcessList().size() - 1; i >= 0; i--) { ProcessRecord r = getLruProcessList().get(i); if (r != null && r.thread != null) { int myPid = r.pid; if (myPid > 0 && myPid != pid && myPid != parentPid && myPid != MY_PID) { Loading Loading @@ -1405,7 +1420,7 @@ final class ProcessRecord implements WindowProcessListener { // don't dump native PIDs for background ANRs unless it is the process of interest String[] nativeProcs = null; if (isSilentANR) { if (isSilentAnr()) { for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) { if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) { nativeProcs = new String[] { processName }; Loading @@ -1429,11 +1444,11 @@ final class ProcessRecord implements WindowProcessListener { // For background ANRs, don't pass the ProcessCpuTracker to // avoid spending 1/2 second collecting stats to rank lastPids. File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, (isSilentANR) ? null : processCpuTracker, (isSilentANR) ? null : lastPids, (isSilentAnr()) ? null : processCpuTracker, (isSilentAnr()) ? null : lastPids, nativePids); String cpuInfo = null; if (ActivityManagerService.MONITOR_CPU_USAGE) { if (isMonitorCpuUsage()) { mService.updateCpuStatsNow(); synchronized (mService.mProcessCpuTracker) { cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime); Loading Loading @@ -1477,9 +1492,13 @@ final class ProcessRecord implements WindowProcessListener { } synchronized (mService) { // mBatteryStatsService can be null if the AMS is constructed with injector only. This // will only happen in tests. if (mService.mBatteryStatsService != null) { mService.mBatteryStatsService.noteProcessAnr(processName, uid); } if (isSilentANR) { if (isSilentAnr()) { kill("bg anr", true); return; } Loading @@ -1488,6 +1507,9 @@ final class ProcessRecord implements WindowProcessListener { makeAppNotRespondingLocked(activityShortComponentName, annotation != null ? "ANR " + annotation : "ANR", info.toString()); // mUiHandler can be null if the AMS is constructed with injector only. This will only // happen in tests. if (mService.mUiHandler != null) { // Bring up the infamous App Not Responding dialog Message msg = Message.obtain(); msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; Loading @@ -1496,12 +1518,17 @@ final class ProcessRecord implements WindowProcessListener { mService.mUiHandler.sendMessage(msg); } } } private void makeAppNotRespondingLocked(String activity, String shortMsg, String longMsg) { setNotResponding(true); // mAppErrors can be null if the AMS is constructed with injector only. This will only // happen in tests. if (mService.mAppErrors != null) { notRespondingReport = mService.mAppErrors.generateProcessError(this, ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, activity, shortMsg, longMsg, null); } startAppProblemLocked(); getWindowProcessController().stopFreezingActivities(); } Loading Loading @@ -1539,4 +1566,9 @@ final class ProcessRecord implements WindowProcessListener { (info != null && "com.android.systemui".equals(info.packageName)) || (hasTopUi() || hasOverlayUi()); } private boolean getShowBackground() { return Settings.Secure.getInt(mService.mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; } } services/core/java/com/android/server/wm/ActivityTaskManagerService.java +6 −0 Original line number Diff line number Diff line Loading @@ -776,6 +776,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mGlobalLock; } /** For test purpose only. */ @VisibleForTesting public ActivityTaskManagerInternal getAtmInternal() { return mInternal; } public void initialize(IntentFirewall intentFirewall, PendingIntentController intentController, Looper looper) { mH = new H(looper); Loading services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java 0 → 100644 +160 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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 android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import android.content.Context; import android.platform.test.annotations.Presubmit; import androidx.test.filters.FlakyTest; import com.android.server.wm.ActivityTaskManagerService; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.util.Collections; /** * Build/Install/Run: * atest FrameworksServicesTests:ProcessRecordTests */ @Presubmit @FlakyTest(detail = "Promote to presubmit when shown to be stable.") public class ProcessRecordTests { private static Context sContext; private static ActivityManagerService sService; private ProcessRecord mProcessRecord; @BeforeClass public static void setUpOnce() throws Exception { sContext = getInstrumentation().getTargetContext(); // We need to run with dexmaker share class loader to make use of ActivityTaskManagerService // from wm package. runWithDexmakerShareClassLoader(() -> { sService = mock(ActivityManagerService.class); sService.mActivityTaskManager = new ActivityTaskManagerService(sContext); sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper()); sService.mAtmInternal = sService.mActivityTaskManager.getAtmInternal(); }); } @Before public void setUpProcess() throws Exception { // Need to run with dexmaker share class loader to mock package private class. runWithDexmakerShareClassLoader(() -> { mProcessRecord = spy(new ProcessRecord(sService, sContext.getApplicationInfo(), "name", 12345)); doNothing().when(mProcessRecord).startAppProblemLocked(); doReturn(false).when(mProcessRecord).isSilentAnr(); doReturn(false).when(mProcessRecord).isMonitorCpuUsage(); doReturn(Collections.emptyList()).when(mProcessRecord).getLruProcessList(); }); } /** * This test verifies the process default status. If this doesn't pass, none of the other tests * should be able to pass. */ @Test public void testProcessDefaultAnrRelatedStatus() { assertFalse(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertFalse(mProcessRecord.killedByAm); assertFalse(mProcessRecord.killed); } /** * This test verifies that if the process is crashing, Anr will do nothing. */ @Test public void testAnrWhenCrash() { mProcessRecord.setCrashing(true); assertTrue(mProcessRecord.isCrashing()); mProcessRecord.appNotResponding(null, null, null, null, false, "Test ANR when crash"); assertFalse(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.killedByAm); assertFalse(mProcessRecord.killed); } /** * This test verifies that if the process is killed by AM, Anr will do nothing. */ @Test public void testAnrWhenKilledByAm() { mProcessRecord.killedByAm = true; mProcessRecord.appNotResponding(null, null, null, null, false, "Test ANR when killed by AM"); assertFalse(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertFalse(mProcessRecord.killed); } /** * This test verifies that if the process is killed, Anr will do nothing. */ @Test public void testAnrWhenKilled() { mProcessRecord.killed = true; mProcessRecord.appNotResponding(null, null, null, null, false, "Test ANR when killed"); assertFalse(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertFalse(mProcessRecord.killedByAm); } /** * This test verifies that non-silent ANR can run through successfully and the corresponding * flags can be set correctly. */ @Test public void testNonSilentAnr() { mProcessRecord.appNotResponding(null, null, null, null, false, "Test non-silent ANR"); assertTrue(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertFalse(mProcessRecord.killedByAm); assertFalse(mProcessRecord.killed); } /** * This test verifies that silent ANR can run through successfully and the corresponding flags * can be set correctly. */ @Test public void testSilentAnr() { // Silent Anr will run through even without a parent process, and directly killed by AM. doReturn(true).when(mProcessRecord).isSilentAnr(); mProcessRecord.appNotResponding(null, null, null, null, false, "Test silent ANR"); assertTrue(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertTrue(mProcessRecord.killedByAm); assertTrue(mProcessRecord.killed); } } Loading
services/core/java/com/android/server/am/ProcessRecord.java +57 −25 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.procstats.ProcessState; import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.BatteryStatsImpl; Loading @@ -73,7 +74,7 @@ import java.util.List; * Full information about a particular process that * is currently running. */ final class ProcessRecord implements WindowProcessListener { class ProcessRecord implements WindowProcessListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM; private final ActivityManagerService mService; // where we came from Loading Loading @@ -1303,6 +1304,27 @@ final class ProcessRecord implements WindowProcessListener { ServerProtoEnums.DATA_APP; } /** * Unless configured otherwise, swallow ANRs in background processes & kill the process. * Non-private access is for tests only. */ @VisibleForTesting boolean isSilentAnr() { return !getShowBackground() && !isInterestingForBackgroundTraces(); } /** Non-private access is for tests only. */ @VisibleForTesting List<ProcessRecord> getLruProcessList() { return mService.mProcessList.mLruProcesses; } /** Non-private access is for tests only. */ @VisibleForTesting boolean isMonitorCpuUsage() { return mService.MONITOR_CPU_USAGE; } void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, String annotation) { Loading @@ -1312,16 +1334,10 @@ final class ProcessRecord implements WindowProcessListener { mWindowProcessController.appEarlyNotResponding(annotation, () -> kill("anr", true)); long anrTime = SystemClock.uptimeMillis(); if (ActivityManagerService.MONITOR_CPU_USAGE) { if (isMonitorCpuUsage()) { mService.updateCpuStatsNow(); } // Unless configured otherwise, swallow ANRs in background processes & kill the process. boolean showBackground = Settings.Secure.getInt(mService.mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; boolean isSilentANR; synchronized (mService) { // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down. if (mService.mAtmInternal.isShuttingDown()) { Loading Loading @@ -1353,8 +1369,7 @@ final class ProcessRecord implements WindowProcessListener { firstPids.add(pid); // Don't dump other PIDs if it's a background ANR isSilentANR = !showBackground && !isInterestingForBackgroundTraces(); if (!isSilentANR) { if (!isSilentAnr()) { int parentPid = pid; if (parentProcess != null && parentProcess.getPid() > 0) { parentPid = parentProcess.getPid(); Loading @@ -1363,8 +1378,8 @@ final class ProcessRecord implements WindowProcessListener { if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID); for (int i = mService.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mService.mProcessList.mLruProcesses.get(i); for (int i = getLruProcessList().size() - 1; i >= 0; i--) { ProcessRecord r = getLruProcessList().get(i); if (r != null && r.thread != null) { int myPid = r.pid; if (myPid > 0 && myPid != pid && myPid != parentPid && myPid != MY_PID) { Loading Loading @@ -1405,7 +1420,7 @@ final class ProcessRecord implements WindowProcessListener { // don't dump native PIDs for background ANRs unless it is the process of interest String[] nativeProcs = null; if (isSilentANR) { if (isSilentAnr()) { for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) { if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) { nativeProcs = new String[] { processName }; Loading @@ -1429,11 +1444,11 @@ final class ProcessRecord implements WindowProcessListener { // For background ANRs, don't pass the ProcessCpuTracker to // avoid spending 1/2 second collecting stats to rank lastPids. File tracesFile = ActivityManagerService.dumpStackTraces(firstPids, (isSilentANR) ? null : processCpuTracker, (isSilentANR) ? null : lastPids, (isSilentAnr()) ? null : processCpuTracker, (isSilentAnr()) ? null : lastPids, nativePids); String cpuInfo = null; if (ActivityManagerService.MONITOR_CPU_USAGE) { if (isMonitorCpuUsage()) { mService.updateCpuStatsNow(); synchronized (mService.mProcessCpuTracker) { cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime); Loading Loading @@ -1477,9 +1492,13 @@ final class ProcessRecord implements WindowProcessListener { } synchronized (mService) { // mBatteryStatsService can be null if the AMS is constructed with injector only. This // will only happen in tests. if (mService.mBatteryStatsService != null) { mService.mBatteryStatsService.noteProcessAnr(processName, uid); } if (isSilentANR) { if (isSilentAnr()) { kill("bg anr", true); return; } Loading @@ -1488,6 +1507,9 @@ final class ProcessRecord implements WindowProcessListener { makeAppNotRespondingLocked(activityShortComponentName, annotation != null ? "ANR " + annotation : "ANR", info.toString()); // mUiHandler can be null if the AMS is constructed with injector only. This will only // happen in tests. if (mService.mUiHandler != null) { // Bring up the infamous App Not Responding dialog Message msg = Message.obtain(); msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; Loading @@ -1496,12 +1518,17 @@ final class ProcessRecord implements WindowProcessListener { mService.mUiHandler.sendMessage(msg); } } } private void makeAppNotRespondingLocked(String activity, String shortMsg, String longMsg) { setNotResponding(true); // mAppErrors can be null if the AMS is constructed with injector only. This will only // happen in tests. if (mService.mAppErrors != null) { notRespondingReport = mService.mAppErrors.generateProcessError(this, ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, activity, shortMsg, longMsg, null); } startAppProblemLocked(); getWindowProcessController().stopFreezingActivities(); } Loading Loading @@ -1539,4 +1566,9 @@ final class ProcessRecord implements WindowProcessListener { (info != null && "com.android.systemui".equals(info.packageName)) || (hasTopUi() || hasOverlayUi()); } private boolean getShowBackground() { return Settings.Secure.getInt(mService.mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; } }
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +6 −0 Original line number Diff line number Diff line Loading @@ -776,6 +776,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mGlobalLock; } /** For test purpose only. */ @VisibleForTesting public ActivityTaskManagerInternal getAtmInternal() { return mInternal; } public void initialize(IntentFirewall intentFirewall, PendingIntentController intentController, Looper looper) { mH = new H(looper); Loading
services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java 0 → 100644 +160 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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 android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import android.content.Context; import android.platform.test.annotations.Presubmit; import androidx.test.filters.FlakyTest; import com.android.server.wm.ActivityTaskManagerService; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.util.Collections; /** * Build/Install/Run: * atest FrameworksServicesTests:ProcessRecordTests */ @Presubmit @FlakyTest(detail = "Promote to presubmit when shown to be stable.") public class ProcessRecordTests { private static Context sContext; private static ActivityManagerService sService; private ProcessRecord mProcessRecord; @BeforeClass public static void setUpOnce() throws Exception { sContext = getInstrumentation().getTargetContext(); // We need to run with dexmaker share class loader to make use of ActivityTaskManagerService // from wm package. runWithDexmakerShareClassLoader(() -> { sService = mock(ActivityManagerService.class); sService.mActivityTaskManager = new ActivityTaskManagerService(sContext); sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper()); sService.mAtmInternal = sService.mActivityTaskManager.getAtmInternal(); }); } @Before public void setUpProcess() throws Exception { // Need to run with dexmaker share class loader to mock package private class. runWithDexmakerShareClassLoader(() -> { mProcessRecord = spy(new ProcessRecord(sService, sContext.getApplicationInfo(), "name", 12345)); doNothing().when(mProcessRecord).startAppProblemLocked(); doReturn(false).when(mProcessRecord).isSilentAnr(); doReturn(false).when(mProcessRecord).isMonitorCpuUsage(); doReturn(Collections.emptyList()).when(mProcessRecord).getLruProcessList(); }); } /** * This test verifies the process default status. If this doesn't pass, none of the other tests * should be able to pass. */ @Test public void testProcessDefaultAnrRelatedStatus() { assertFalse(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertFalse(mProcessRecord.killedByAm); assertFalse(mProcessRecord.killed); } /** * This test verifies that if the process is crashing, Anr will do nothing. */ @Test public void testAnrWhenCrash() { mProcessRecord.setCrashing(true); assertTrue(mProcessRecord.isCrashing()); mProcessRecord.appNotResponding(null, null, null, null, false, "Test ANR when crash"); assertFalse(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.killedByAm); assertFalse(mProcessRecord.killed); } /** * This test verifies that if the process is killed by AM, Anr will do nothing. */ @Test public void testAnrWhenKilledByAm() { mProcessRecord.killedByAm = true; mProcessRecord.appNotResponding(null, null, null, null, false, "Test ANR when killed by AM"); assertFalse(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertFalse(mProcessRecord.killed); } /** * This test verifies that if the process is killed, Anr will do nothing. */ @Test public void testAnrWhenKilled() { mProcessRecord.killed = true; mProcessRecord.appNotResponding(null, null, null, null, false, "Test ANR when killed"); assertFalse(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertFalse(mProcessRecord.killedByAm); } /** * This test verifies that non-silent ANR can run through successfully and the corresponding * flags can be set correctly. */ @Test public void testNonSilentAnr() { mProcessRecord.appNotResponding(null, null, null, null, false, "Test non-silent ANR"); assertTrue(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertFalse(mProcessRecord.killedByAm); assertFalse(mProcessRecord.killed); } /** * This test verifies that silent ANR can run through successfully and the corresponding flags * can be set correctly. */ @Test public void testSilentAnr() { // Silent Anr will run through even without a parent process, and directly killed by AM. doReturn(true).when(mProcessRecord).isSilentAnr(); mProcessRecord.appNotResponding(null, null, null, null, false, "Test silent ANR"); assertTrue(mProcessRecord.isNotResponding()); assertFalse(mProcessRecord.isCrashing()); assertTrue(mProcessRecord.killedByAm); assertTrue(mProcessRecord.killed); } }