Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3f4c3b6 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Handle ANR in a separate thread" into rvc-dev am: d11b9a31 am: db5a62df

Change-Id: I23f2e8231750ffee0e6ce8933f88d73374dadcf6
parents f66837b1 db5a62df
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -4213,7 +4213,7 @@ public final class ActiveServices {
        }
        }


        if (anrMessage != null) {
        if (anrMessage != null) {
            proc.appNotResponding(null, null, null, null, false, anrMessage);
            mAm.mAnrHelper.appNotResponding(proc, anrMessage);
        }
        }
    }
    }


@@ -4238,7 +4238,7 @@ public final class ActiveServices {
        }
        }


        if (app != null) {
        if (app != null) {
            app.appNotResponding(null, null, null, null, false,
            mAm.mAnrHelper.appNotResponding(app,
                    "Context.startForegroundService() did not then call Service.startForeground(): "
                    "Context.startForegroundService() did not then call Service.startForeground(): "
                        + r);
                        + r);
        }
        }
+7 −19
Original line number Original line Diff line number Diff line
@@ -1522,6 +1522,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        void onOomAdjMessage(String msg);
        void onOomAdjMessage(String msg);
    }
    }
    final AnrHelper mAnrHelper = new AnrHelper();
    /**
    /**
     * Runtime CPU use collection thread.  This object's lock is used to
     * Runtime CPU use collection thread.  This object's lock is used to
     * perform synchronization with the thread (notifying it to run).
     * perform synchronization with the thread (notifying it to run).
@@ -7797,13 +7799,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            return;
            return;
        }
        }
        mHandler.post(new Runnable() {
        mAnrHelper.appNotResponding(host, "ContentProvider not responding");
            @Override
            public void run() {
                host.appNotResponding(
                        null, null, null, null, false, "ContentProvider not responding");
            }
        });
    }
    }
    @Override
    @Override
@@ -7816,13 +7812,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                throw new SecurityException("Unknown process: " + callingPid);
                throw new SecurityException("Unknown process: " + callingPid);
            }
            }
            mHandler.post(new Runnable() {
            mAnrHelper.appNotResponding(app, null, app.info, null, null, false,
                @Override
                    "App requested: " + reason);
                public void run() {
                    app.appNotResponding(
                            null, app.info, null, null, false, "App requested: " + reason);
                }
            });
        }
        }
    }
    }
@@ -19323,10 +19314,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        @Override
        @Override
        public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) {
        public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) {
            synchronized (ActivityManagerService.this) {
            return ActivityManagerService.this.inputDispatchingTimedOut(pid, aboveSystem, reason);
                return ActivityManagerService.this.inputDispatchingTimedOut(
                        pid, aboveSystem, reason);
            }
        }
        }
        @Override
        @Override
@@ -19617,7 +19605,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    return true;
                    return true;
                }
                }
            }
            }
            proc.appNotResponding(activityShortComponentName, aInfo,
            mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
                    parentShortComponentName, parentProcess, aboveSystem, annotation);
                    parentShortComponentName, parentProcess, aboveSystem, annotation);
        }
        }
+142 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2020 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 static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;

import android.content.pm.ApplicationInfo;
import android.os.SystemClock;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.server.wm.WindowProcessController;

import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * The helper class to handle no response process. An independent thread will be created on demand
 * so the caller can report the ANR without worrying about taking long time.
 */
class AnrHelper {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "AnrHelper" : TAG_AM;

    /**
     * If the system is extremely slow somehow that the ANR has been pending too long for more than
     * this time, the information might be outdated. So we only the dump the unresponsive process
     * instead of including other processes to avoid making the system more busy.
     */
    private static final long EXPIRED_REPORT_TIME_MS = TimeUnit.MINUTES.toMillis(1);

    @GuardedBy("mAnrRecords")
    private final ArrayList<AnrRecord> mAnrRecords = new ArrayList<>();
    private final AtomicBoolean mRunning = new AtomicBoolean(false);

    void appNotResponding(ProcessRecord anrProcess, String annotation) {
        appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */,
                null /* parentShortComponentName */, null /* parentProcess */,
                false /* aboveSystem */, annotation);
    }

    void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
            ApplicationInfo aInfo, String parentShortComponentName,
            WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
        synchronized (mAnrRecords) {
            mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
                    parentShortComponentName, parentProcess, aboveSystem, annotation));
        }
        startAnrConsumerIfNeeded();
    }

    private void startAnrConsumerIfNeeded() {
        if (mRunning.compareAndSet(false, true)) {
            new AnrConsumerThread().start();
        }
    }

    /**
     * The thread to execute {@link ProcessRecord#appNotResponding}. It will terminate if all
     * records are handled.
     */
    private class AnrConsumerThread extends Thread {
        AnrConsumerThread() {
            super("AnrConsumer");
        }

        private AnrRecord next() {
            synchronized (mAnrRecords) {
                return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
            }
        }

        @Override
        public void run() {
            AnrRecord r;
            while ((r = next()) != null) {
                final long startTime = SystemClock.uptimeMillis();
                // If there are many ANR at the same time, the latency may be larger. If the latency
                // is too large, the stack trace might not be meaningful.
                final long reportLatency = startTime - r.mTimestamp;
                final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS;
                r.appNotResponding(onlyDumpSelf);
                final long endTime = SystemClock.uptimeMillis();
                Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in "
                        + (endTime - startTime) + "ms, latency " + reportLatency
                        + (onlyDumpSelf ? "ms" : "ms (expired, only dump ANR app)"));
            }

            mRunning.set(false);
            synchronized (mAnrRecords) {
                // The race should be unlikely to happen. Just to make sure we don't miss.
                if (!mAnrRecords.isEmpty()) {
                    startAnrConsumerIfNeeded();
                }
            }
        }
    }

    private static class AnrRecord {
        final ProcessRecord mApp;
        final String mActivityShortComponentName;
        final String mParentShortComponentName;
        final String mAnnotation;
        final ApplicationInfo mAppInfo;
        final WindowProcessController mParentProcess;
        final boolean mAboveSystem;
        final long mTimestamp = SystemClock.uptimeMillis();

        AnrRecord(ProcessRecord anrProcess, String activityShortComponentName,
                ApplicationInfo aInfo, String parentShortComponentName,
                WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
            mApp = anrProcess;
            mActivityShortComponentName = activityShortComponentName;
            mParentShortComponentName = parentShortComponentName;
            mAnnotation = annotation;
            mAppInfo = aInfo;
            mParentProcess = parentProcess;
            mAboveSystem = aboveSystem;
        }

        void appNotResponding(boolean onlyDumpSelf) {
            mApp.appNotResponding(mActivityShortComponentName, mAppInfo,
                    mParentShortComponentName, mParentProcess, mAboveSystem, mAnnotation,
                    onlyDumpSelf);
        }
    }
}
+1 −18
Original line number Original line Diff line number Diff line
@@ -198,21 +198,6 @@ public final class BroadcastQueue {
        }
        }
    }
    }


    private final class AppNotResponding implements Runnable {
        private final ProcessRecord mApp;
        private final String mAnnotation;

        public AppNotResponding(ProcessRecord app, String annotation) {
            mApp = app;
            mAnnotation = annotation;
        }

        @Override
        public void run() {
            mApp.appNotResponding(null, null, null, null, false, mAnnotation);
        }
    }

    BroadcastQueue(ActivityManagerService service, Handler handler,
    BroadcastQueue(ActivityManagerService service, Handler handler,
            String name, BroadcastConstants constants, boolean allowDelayBehindServices) {
            String name, BroadcastConstants constants, boolean allowDelayBehindServices) {
        mService = service;
        mService = service;
@@ -1808,9 +1793,7 @@ public final class BroadcastQueue {
        scheduleBroadcastsLocked();
        scheduleBroadcastsLocked();


        if (!debugging && anrMessage != null) {
        if (!debugging && anrMessage != null) {
            // Post the ANR to the handler since we do not want to process ANRs while
            mService.mAnrHelper.appNotResponding(app, anrMessage);
            // potentially holding our lock.
            mHandler.post(new AppNotResponding(app, anrMessage));
        }
        }
    }
    }


+7 −5
Original line number Original line Diff line number Diff line
@@ -1502,7 +1502,7 @@ class ProcessRecord implements WindowProcessListener {


    void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
    void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
            String parentShortComponentName, WindowProcessController parentProcess,
            String parentShortComponentName, WindowProcessController parentProcess,
            boolean aboveSystem, String annotation) {
            boolean aboveSystem, String annotation, boolean onlyDumpSelf) {
        ArrayList<Integer> firstPids = new ArrayList<>(5);
        ArrayList<Integer> firstPids = new ArrayList<>(5);
        SparseArray<Boolean> lastPids = new SparseArray<>(20);
        SparseArray<Boolean> lastPids = new SparseArray<>(20);


@@ -1514,6 +1514,7 @@ class ProcessRecord implements WindowProcessListener {
            mService.updateCpuStatsNow();
            mService.updateCpuStatsNow();
        }
        }


        final boolean isSilentAnr;
        synchronized (mService) {
        synchronized (mService) {
            // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
            // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
            if (mService.mAtmInternal.isShuttingDown()) {
            if (mService.mAtmInternal.isShuttingDown()) {
@@ -1544,8 +1545,9 @@ class ProcessRecord implements WindowProcessListener {
            // Dump thread traces as quickly as we can, starting with "interesting" processes.
            // Dump thread traces as quickly as we can, starting with "interesting" processes.
            firstPids.add(pid);
            firstPids.add(pid);


            // Don't dump other PIDs if it's a background ANR
            // Don't dump other PIDs if it's a background ANR or is requested to only dump self.
            if (!isSilentAnr()) {
            isSilentAnr = isSilentAnr();
            if (!isSilentAnr && !onlyDumpSelf) {
                int parentPid = pid;
                int parentPid = pid;
                if (parentProcess != null && parentProcess.getPid() > 0) {
                if (parentProcess != null && parentProcess.getPid() > 0) {
                    parentPid = parentProcess.getPid();
                    parentPid = parentProcess.getPid();
@@ -1598,7 +1600,7 @@ class ProcessRecord implements WindowProcessListener {


        // don't dump native PIDs for background ANRs unless it is the process of interest
        // don't dump native PIDs for background ANRs unless it is the process of interest
        String[] nativeProcs = null;
        String[] nativeProcs = null;
        if (isSilentAnr()) {
        if (isSilentAnr || onlyDumpSelf) {
            for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
            for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
                if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) {
                if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) {
                    nativeProcs = new String[] { processName };
                    nativeProcs = new String[] { processName };
@@ -1625,7 +1627,7 @@ class ProcessRecord implements WindowProcessListener {
        // To hold the start and end offset to the ANR trace file respectively.
        // To hold the start and end offset to the ANR trace file respectively.
        final long[] offsets = new long[2];
        final long[] offsets = new long[2];
        File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
        File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
                (isSilentAnr()) ? null : processCpuTracker, (isSilentAnr()) ? null : lastPids,
                isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
                nativePids, tracesFileException, offsets);
                nativePids, tracesFileException, offsets);


        if (isMonitorCpuUsage()) {
        if (isMonitorCpuUsage()) {
Loading