通过源码搞定ANR Log如何产生(二)

1,418 阅读2分钟

上文:juejin.cn/post/685041…

上回说到,调用了Java端的notifyANR()方法,那么这个方法是在哪被执行的呢?

2.

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

2.1 

notifyANR()方法就是在InputManagerService.java中被执行的,来看代码

mWindowManagerCallbacks是一个WindowManagerCallbacks接口,它被InputManagerCallback实现

// Native callback.
private long notifyANR(IBinder token, String reason) {
     return mWindowManagerCallbacks.notifyANR(token, reason);
}
    
/Q_Mainline/frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java
final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {

所以再看InputManagerCallback中的notifyANR()

2.2 

notifyANR() :通过判断appWindowToken,appWindowToken.appToken和windowState,去调用不同的方法keyDispatchingTimedOut()和inputDispatchingTimedOut()

首先看keyDispatchingTimedOut():调用链为
ppWindowToken.keyDispatchingTimedOut

再看inputDispatchingTimedOut():调用链为

mService.mAmInternal.inputDispatchingTimedOut
----> proc.appNotResponding()     

两个方法最后都调用了appNotResponding()方法,来处理app无响应时的情况

public long notifyANR(IBinder token, String reason) {
        if (appWindowToken != null && appWindowToken.appToken != null) {
            // Notify the activity manager about the timeout and let it decide whether
            // to abort dispatching or keep waiting.
            final boolean abort = appWindowToken.keyDispatchingTimedOut(reason,
                    (windowState != null) ? windowState.mSession.mPid : -1);
        } else if (windowState != null) {
            // Notify the activity manager about the timeout and let it decide whether
            // to abort dispatching or keep waiting.
            long timeout = mService.mAmInternal.inputDispatchingTimedOut(
                    windowState.mSession.mPid, aboveSystem, reason);
        }
        return 0; // abort dispatching
    }

 2.3

proc.appNotResponding()最后又调用了ProcessRecord.java中的appNotRespondingImpl(),然后继续调用AMS中的dumpStackTraces方法

void appNotRespondingImpl(String activityShortComponentName, ApplicationInfo aInfo,
            String parentShortComponentName, WindowProcessController parentProcess,
            boolean aboveSystem, String annotation) {

            // Original code
            // For background ANRs, don't pass the ProcessCpuTracker to
            // avoid spending 1/2 second collecting stats to rank lastPids.
            tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
                    (isSilentAnr()) ? null : processCpuTracker, (isSilentAnr()) ? null : lastPids,
                    nativePids);
          
    }
    
    

2.4  

ActivityManagerService.dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePids),这个方法中,创建了tracesFile,调用了dumpStackTraces()的重载函数,传入文件路径

public static final String ANR_TRACE_DIR = "/data/anr";
    
    public static File dumpStackTraces(ArrayList firstPids,
            ProcessCpuTracker processCpuTracker, SparseArray lastPids,
            ArrayList nativePids) {
        ArrayList extraPids = null;
        //ANR_TRACE_DIR = "/data/anr"
        final File tracesDir = new File(ANR_TRACE_DIR);
        File tracesFile = createAnrDumpFile(tracesDir);
        if (tracesFile == null) {
            return null;
        }
        //tracesFile..getAbsolutePath() = "/data/anr/anr_Date"
        dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids);
        return tracesFile;
    }
    
   private static synchronized File createAnrDumpFile(File tracesDir) {
        if (sAnrFileDateFormat == null) {
            sAnrFileDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS");
        }
        final String formattedDate = sAnrFileDateFormat.format(new Date());
        final File anrFile = new File(tracesDir, "anr_" + formattedDate);
        try {
            if (anrFile.createNewFile()) {
                FileUtils.setPermissions(anrFile.getAbsolutePath(), 0600, -1, -1); // -rw-------
                return anrFile;
            } else {
                Slog.w(TAG, "Unable to create ANR dump file: createNewFile failed");
            }
        } catch (IOException ioe) {
            Slog.w(TAG, "Exception creating ANR dump file:", ioe);
        }
        return null;
    }

2.5

ActivityManagerService.dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
ArrayList<Integer> nativePids, ArrayList<Integer> extraPids),

for循环遍历了firstPids集合,对每个pid都调用dumpJavaTracesTombstoned()方法

参数:tracesFile = "/data/anr/anr_Date"

public static void dumpStackTraces(String tracesFile, ArrayList firstPids,
            ArrayList nativePids, ArrayList extraPids) {
        // First collect all of the stacks of the most important pids.
        if (firstPids != null) {
            int num = firstPids.size();
            for (int i = 0; i < num; i++) {
                Slog.i(TAG, "Collecting stacks for pid " + firstPids.get(i));
                final long timeTaken = dumpJavaTracesTombstoned(firstPids.get(i), tracesFile, remainingTime);
            }
        }
    }

2.6 

dumpJavaTracesTombstoned():调用了Debug.dumpJavaBacktraceToFileTimeout()

参数pid = pid , fileName = "/data/anr/anr_Date",timeoutMs = 20 * 1000;

private static long dumpJavaTracesTombstoned(int pid, String fileName, long timeoutMs) {
        final long timeStart = SystemClock.elapsedRealtime();
        boolean javaSuccess = Debug.dumpJavaBacktraceToFileTimeout(pid, fileName,
                (int) (timeoutMs / 1000));
    }

2.7

Debug.dumpJavaBacktraceToFileTimeout():是一个native方法,通过jni,实现在c++中,方法名为android_os_Debug_dumpJavaBacktraceToFileTimeout

接下来进入c++ code中分析

public static native boolean dumpJavaBacktraceToFileTimeout(int pid, String file,
                                                                int timeoutSecs);
                                                                
/*
 * JNI registration.
 */
static const JNINativeMethod gMethods[] = {
    { "dumpJavaBacktraceToFileTimeout", "(ILjava/lang/String;I)Z",
            (void*)android_os_Debug_dumpJavaBacktraceToFileTimeout },
};  

待续。。。。。