This is the sixth day of my participation in the November Gwen Challenge. See details: The Last Gwen Challenge 2021.
BlockMoonlightTreasureBox caton Pandora’s box
We concluded earlier
App Caton series 1: Handler synchronization barrier
App Caton series II: Learning screen refresh mechanism
App Caton series three: ANR principle
App Caton series iv: Toutiao Caton monitoring scheme landing
Finally, it’s time for the final release
Technical theory comes from:
Toutiao ANR Optimization Practice series – Design principles and influencing factors
Toutiao ANR Optimization Practice series – Monitoring tools and analysis ideas
use
Introduction:
Implementation 'IO. Making. Xiaolutang: BlockMoonlightTreasureBox: 1.0.0'Copy the code
Initialization:
The initiation of the Luna Box is divided into two parts
- BlcokMonitor initialization
- Native listener initialization
BlockBoxConfig blockMonitorface.init (this).updateconfig (new BlockBoxconfig.Builder ()) .useAnalyze(true) .build()) .startMonitor(); / / registered native monitoring SIGNAL SystemAnrMonitor QUIT SIGNAL. The init (BlockMonitorFace. GetBlockMonitorFace ());Copy the code
BlockBoxConfig#Builder
Issue warning messages and aggregate the main thread messages separately
SetGapTime: A gap message will be generated when the main thread is in ideL state for longer than this time. If the ideL state is smaller than this value, no separate processing is performed
SetAnrTime: AnR is determined to have occurred when the main thread message is dispatched for more than this time
SetJankFrame: can be simply understood as warning when the View drawing process takes more than three frames. App Caton series four: Toutiao Caton monitoring scheme landing
UseAnalyze: Specifies whether to generate an analysis application icon on the desktop. A typical scenario is that a test version can be built, but a release version is not
AddAnrSampleListener: Adds listening ANR information. A lot of ANR files occur online. If there are only offline ANR logs, it is obviously not conducive to analyzing ANR, so this interface is provided.
The interface receives an IAnrSamplerListener
/ * * * from ISampleListener specialized information acquisition anr callback * / public interface IAnrSamplerListener extends IMainThreadSampleListener {/ * * * Collect unprocessed messages in the message queue */ void onMessageQueueSample(long baseTime, String msgId, String MSG); void onCpuSample(long baseTime, String msgId, String msg); void onMemorySample(long baseTime, String msgId, String msg); void onMainThreadStackSample(long baseTime, String msgId, String msg); } / * * * all these method calls in the main thread * take care not to make time-consuming operation * / public interface IMainThreadSampleListener {/ * * * the current main thread scheduling ability * * @ param start true */ void onScheduledSample(Boolean start, Long baseTime, String msgId, Long Dealt); Void onMsgSample(long baseTime, String msgId, MessageInfo MSG); void onJankSample(String msgId, MessageInfo msg); / * * * anr's message has been processed in the message queue * * / void messageQueueDispatchAnrFinish (); void onSampleAnrMsg(); }Copy the code
Among them is onSampleAnrMsg and messageQueueDispatchAnrFinish need special attention. OnSampleAnrMsg means received ANR news, information can be stored at this time (if no messageQueueDispatchAnrFinish behind the news, can use this as the basis of analysis). When receiving the messageQueueDispatchAnrFinish mean the end of the ANR news gathering.
Native to initialize
System ANR uses SIGNAL QUIT SIGNAL to monitor. Here, we replace the system’s monitor with our own registration and return the SIGNAL to the system after the message processing is completed.
However, the location of the Moonlight box is a complement to the ANR message, in order to be compatible with other frameworks that handle ANR by listening for SIGNAL QUIT signals
SystemAnrMonitor. Init (BlockMonitorFace getBlockMonitorFace ()) to register notice BlockMonitor received ANR news.
public class SystemAnrMonitor {
static {
System.loadLibrary("block_signal");
}
private native void hookSignalCatcher(ISystemAnrObserver observed);
private native void unHookSignalCatcher();
public static void init(ISystemAnrObserver systemAnrObserver){
new SystemAnrMonitor().hookSignalCatcher(systemAnrObserver);
}
}
public interface ISystemAnrObserver {
void onSystemAnr();
}
Copy the code
With other frameworks, you simply call onSystemAnr when listening for the system ANR.
instructions
Although IAnrSamplerListener has CPU and Memory information collection callbacks, there is no corresponding implementation of Moonlight Box, because moonlight box is a complement to the system ANR information, not a corresponding replacement. When ANR occurs in the system, it is more convenient to analyze ANR with the information collected by the system and moonlight box.
Case study:
Reference project Test module, mainly tested three contents
Jank frame drop
We hibernate for 500ms in View’s Draw method to observe the log
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
long start = SystemClock.elapsedRealtime();
if(jank){
SystemClock.sleep(500);
}
long end = SystemClock.elapsedRealtime();
Log.d("JankView","BlockMonitor start "+start + " end "+end + " "+(end - start));
}
Copy the code
Log message:
Time spent on a single message, ANR
We send a long runnable to the message queue, and then send a foreground broadcast to test it. Finally, we found that two ANR records were generated
The reason is that when a message queue processes a message, we discover the ANR first and then, or the moonlight box, or the system triggers the ANR end message. Because this termination is triggered twice, two messages are generated.
The message is sent through the instance object of Android.os. Hander, where callback is an internal class in MainActivity, and there are still two messages waiting to be processed in the message queue. Time stack hit Thread.sleep
The second log is not parsed in this position because the first log uses the information collected. The second log does not have much information available, but if a main thread Looper is found to take longer than the specified ANR time (3s by default), then this method should always take precedence.
Message queue messages are frequent, ANR
We simulate the main thread message queue being busy by sending more time-consuming tasks to the main thread
findViewById(R.id.tvTestAnr2).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { For (int I =25; i>0; i--){ mainHandler.post(new Runnable() { @Override public void run() { //500ms SystemClock.sleep(500); }}); } AnrTestBroadcast.sentBroadcast(MainActivity.this); }});Copy the code
Results analysis:
So this is a reflection of, a lot of times we may not be doing time-consuming operations, but ANR is happening from the system side.
Other threads or processes preempt the CPU, resulting in insufficient main thread scheduling capability
This is not very easy to simulate
How to expand online log collection
Reference BlockBoxConfig# Builder
Technical Exchange Group:
Code Address:
Github.com/xiaolutang/…
\