本问介绍一下anr之后,系统打印log的流程。加深对anr问题的理解。
anr触发原理分析可以看看这个文章http://gityuan.com/2017/01/01/input-anr/
cpp代码比较多,我选择放弃了。从java层log往后看吧。。。
anr触发在native层,触发后回调Java层打印anr log和cpu信息等。
本文以input事件anr为例,进行调试。
private void notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid,
String reason) {
mWindowManagerCallbacks.notifyWindowUnresponsive(token,
isPidValid ? OptionalInt.of(pid) : OptionalInt.empty(), reason);
}
public void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
@NonNull String reason) {
mService.mAnrController.notifyWindowUnresponsive(token, pid, reason);
}
void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
@NonNull String reason) {
if (notifyWindowUnresponsive(token, reason)) {
return;
}
if (!pid.isPresent()) {
Slog.w(TAG_WM, "Failed to notify that window token=" + token + " was unresponsive.");
return;
}
notifyWindowUnresponsive(pid.getAsInt(), reason);
}
private boolean notifyWindowUnresponsive(@NonNull IBinder inputToken, String reason) {
preDumpIfLockTooSlow();
final int pid;
final boolean aboveSystem;
final ActivityRecord activity;
synchronized (mService.mGlobalLock) {
InputTarget target = mService.getInputTargetFromToken(inputToken);
if (target == null) {
return false;
}
WindowState windowState = target.getWindowState();
pid = target.getPid();
// Blame the activity if the input token belongs to the window. If the target is
// embedded, then we will blame the pid instead.
activity = (windowState.mInputChannelToken == inputToken)
? windowState.mActivityRecord : null;
Slog.i(TAG_WM, "ANR in " + target + ". Reason:" + reason);//触发anr的第一个log
aboveSystem = isWindowAboveSystem(windowState);
dumpAnrStateLocked(activity, windowState, reason);//dump anr log
}
if (activity != null) {
activity.inputDispatchingTimedOut(reason, pid);//anr in cpu那段log
} else {
mService.mAmInternal.inputDispatchingTimedOut(pid, aboveSystem, reason);
}
return true;
}
private void dumpAnrStateLocked(ActivityRecord activity, WindowState windowState,
String reason) {
mService.saveANRStateLocked(activity, windowState, reason);
mService.mAtmService.saveANRState(reason);
}
saveANRStateLocked
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/wm/UnisocWindowManagerService.java
saveANRStateLocked
@Override
public void saveANRStateLocked(ActivityRecord activity, WindowState windowState,
String reason) {
super.saveANRStateLocked(activity, windowState, reason);
dumpWindowStatusLocked(activity);//dump windowStatus
dumpAllWindowStatusLocked();//dump all windowStatus
//Unisoc:add WMS eventId(102200000) for UniEvent
if (windowState != null) {
UniEvent uniEvent = new UniEvent(102200000);
uniEvent.putInt("Visible",windowState.mViewVisibility)
.putInt("State",windowState.mWinAnimator.mDrawState);
UniView.report(uniEvent);
}
}
@Override
public boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName, Object parentProc,
boolean aboveSystem, String reason) {
return ActivityManagerService.this.inputDispatchingTimedOut((ProcessRecord) proc,
activityShortComponentName, aInfo, parentShortComponentName,
(WindowProcessController) parentProc, aboveSystem, reason);
}
boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String reason) {
...
checkDevicePowerOnOrPowerOff();//自己加的log,anr之前打印一下是否灭屏
//最终会调用到这里
mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation);
}
return true;
}
void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
final int incomingPid = anrProcess.mPid;
synchronized (mAnrRecords) {
...
//add new AnrRecord
mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation));
}
//start 循环mAnrRecords
startAnrConsumerIfNeeded();
}
private void startAnrConsumerIfNeeded() {
if (mRunning.compareAndSet(false, true)) {
new AnrConsumerThread().start();
}
}
private class AnrConsumerThread extends Thread是AnrHelper的内部类
直接看run方法
@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);//anr log
//anr log打印完成
final long endTime = SystemClock.uptimeMillis();
Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in "
+ (endTime - startTime) + "ms, latency " + reportLatency
+ (onlyDumpSelf ? "ms (expired, only dump ANR app)" : "ms"));
}
...
}
}
r.appNotResponding
void appNotResponding(boolean onlyDumpSelf) {
mApp.mErrorState.appNotResponding(mActivityShortComponentName, mAppInfo,
mParentShortComponentName, mParentProcess, mAboveSystem, mAnnotation,
onlyDumpSelf);
}
appNotResponding
这个方法巨长无比,大概有三四百行,简单看一下log信息。
基本上做了这么几件事
1、更新cpu信息
2、am_amr log
2.1、anr 主体log
2.2、Output from /proc/pressure/memory
2.3、printCurrentCpuState
3、tracesFile保存
4、bg anr,直接kill
5、anr dialog弹窗,test的时候不会弹
void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
String parentShortComponentName, WindowProcessController parentProcess,
boolean aboveSystem, String annotation, boolean onlyDumpSelf) {
ArrayList<Integer> firstPids = new ArrayList<>(5);
SparseArray<Boolean> lastPids = new SparseArray<>(20);
...
if (isMonitorCpuUsage()) {
mService.updateCpuStatsNow();//更新cpu信息
}
final boolean isSilentAnr;
final int pid = mApp.getPid();
final UUID errorId;
synchronized (mService) {
//am_amr这一行log
// Log the ANR to the event log.
EventLog.writeEvent(EventLogTags.AM_ANR, mApp.userId, pid, mApp.processName,
mApp.info.flags, annotation);
...
//anr 主体log
// Log the ANR to the main log.
StringBuilder info = new StringBuilder();
info.setLength(0);
info.append("ANR in ").append(mApp.processName);
if (activityShortComponentName != null) {
info.append(" (").append(activityShortComponentName).append(")");
}
info.append("\n");
info.append("PID: ").append(pid).append("\n");
if (annotation != null) {
info.append("Reason: ").append(annotation).append("\n");
}
if (parentShortComponentName != null
&& parentShortComponentName.equals(activityShortComponentName)) {
info.append("Parent: ").append(parentShortComponentName).append("\n");
}
if (errorId != null) {
info.append("ErrorId: ").append(errorId.toString()).append("\n");
}
info.append("Frozen: ").append(mApp.mOptRecord.isFrozen()).append("\n");
...
//----- Output from /proc/pressure/memory -----
//内存压力log
StringBuilder report = new StringBuilder();
report.append(MemoryPressureUtil.currentPsiState());
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
//Unisoc: if the ANR is simulated by cts, native backtrace will be ignored
boolean ctsUnresponsive = false;
if(Build.IS_DEBUGGABLE && (".unresponsive_activity_process".equals(mApp.processName) || ".render_process".equals(mApp.processName)))
ctsUnresponsive = true;
// don't dump native PIDs for background ANRs unless it is the process of interest
String[] nativeProcs = null;
if (isSilentAnr || onlyDumpSelf || ctsUnresponsive) {
for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
if (NATIVE_STACKS_OF_INTEREST[i].equals(mApp.processName)) {
nativeProcs = new String[] { mApp.processName };
break;
}
}
} else {
nativeProcs = NATIVE_STACKS_OF_INTEREST;
}
int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs);
ArrayList<Integer> nativePids = null;
if (pids != null) {
nativePids = new ArrayList<>(pids.length);
for (int i : pids) {
nativePids.add(i);
}
}
// For background ANRs, don't pass the ProcessCpuTracker to
// avoid spending 1/2 second collecting stats to rank lastPids.
StringWriter tracesFileException = new StringWriter();
// To hold the start and end offset to the ANR trace file respectively.
final long[] offsets = new long[2];
//tracesFile
File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
nativePids, tracesFileException, offsets, annotation, criticalEventLog);
if (isMonitorCpuUsage()) {
mService.updateCpuStatsNow();
mService.mAppProfiler.printCurrentCpuState(report, anrTime);//cpu状态添加到report字符串
info.append(processCpuTracker.printCurrentLoad());
info.append(report);//最终都添加到info字符串里了
}
report.append(tracesFileException.getBuffer());
info.append(processCpuTracker.printCurrentState(anrTime));
// Dumps tasks that are in uninterrruptable state(D-state)
if (Build.IS_DEBUGGABLE && !lowram) {
doSysrq('w');
}
//anr main log 打印
Slog.e(TAG, info.toString());
if (tracesFile == null) {
// There is no trace file, so dump (only) the alleged culprit's threads to the log
Process.sendSignal(pid, Process.SIGNAL_QUIT);
} else if (offsets[1] > 0) {
//保存tracesFile
// We've dumped into the trace file successfully
mService.mProcessList.mAppExitInfoTracker.scheduleLogAnrTrace(
pid, mApp.uid, mApp.getPackageList(), tracesFile, offsets[0], offsets[1]);
}
// Check if package is still being loaded
float loadingProgress = 1;
IncrementalMetrics incrementalMetrics = null;
final PackageManagerInternal packageManagerInternal = mService.getPackageManagerInternal();
if (mApp.info != null && mApp.info.packageName != null && packageManagerInternal != null) {
IncrementalStatesInfo incrementalStatesInfo =
packageManagerInternal.getIncrementalStatesInfo(
mApp.info.packageName, SYSTEM_UID, mApp.userId);
if (incrementalStatesInfo != null) {
loadingProgress = incrementalStatesInfo.getProgress();
}
final String codePath = mApp.info.getCodePath();
if (codePath != null && !codePath.isEmpty()
&& IncrementalManager.isIncrementalPath(codePath)) {
// Report in the main log that the incremental package is still loading
Slog.e(TAG, "App ANR on incremental package " + mApp.info.packageName
+ " which is " + ((int) (loadingProgress * 100)) + "% loaded.");
final IBinder incrementalService = ServiceManager.getService(
Context.INCREMENTAL_SERVICE);
if (incrementalService != null) {
final IncrementalManager incrementalManager = new IncrementalManager(
IIncrementalService.Stub.asInterface(incrementalService));
incrementalMetrics = incrementalManager.getMetrics(codePath);
}
}
}
if (incrementalMetrics != null) {
// Report in the main log about the incremental package
info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n");
}
...
if (mApp.getWindowProcessController().appNotResponding(info.toString(),
() -> {
synchronized (mService) {
mApp.killLocked("anr", ApplicationExitInfo.REASON_ANR, true);
}
},
() -> {
synchronized (mService) {
mService.mServices.scheduleServiceTimeoutLocked(mApp);
}
})) {
return;
}
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(mApp.processName, mApp.uid);
}
//bg anr,直接kill
if (isSilentAnr() && !mApp.isDebugging()) {
mApp.killLocked("bg anr", ApplicationExitInfo.REASON_ANR, true);
return;
}
synchronized (mProcLock) {
// Set the app's notResponding state, and look up the errorReportReceiver
makeAppNotRespondingLSP(activityShortComponentName,
annotation != null ? "ANR " + annotation : "ANR", info.toString());
mDialogController.setAnrController(anrController);
}
//anr ui弹框
// 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;
msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem);
mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs);
}
}
}
vendor/sprd/platform/frameworks/base/services/ex-interface/core/java/com/android/server/am/UnisocProcessErrorStateRecord.java
appNotResponding
展锐平台自定义的类,为了额外dump一些log信息。
啊 心好累,第一次跟踪anr log流程,相关的类太多了。
相关的类都在frameworks/base/services/core/java/com/android/server下面
主流程就在这些类里,里面可能会调用其它相关的类dump当前状态的log。
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java
frameworks/base/services/core/java/com/android/server/wm/AnrController.java
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/wm/UnisocWindowManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/AnrHelper.java
frameworks/base/services/core/java/com/android/server/am/ProcessErrorStateRecord.java