package com.taobao.dexposed;
import android.os.Build;
import android.util.Log;
import android.view.Choreographer;
import com.taobao.android.dexposed.XC_MethodHook;
import com.taobao.android.dexposed.XC_MethodHook.Unhook;
import com.taobao.android.dexposed.DexposedBridge;
public class ChoreographerHook {
private static ChoreographerHook choreographerHook;
synchronized public static ChoreographerHook instance(){
if(choreographerHook == null)
choreographerHook = new ChoreographerHook();
return choreographerHook;
}
private boolean isEnable(){
if(Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 21) {
return true;
} else
return false;
}
private ChoreographerHook() {
if(!isEnable())
return;
try {
mFrameIntervalNanos = (Long) Choreographer.class.getDeclaredField("mFrameIntervalNanos").get(Choreographer.getInstance());
} catch (Exception e) {
mFrameIntervalNanos = 1000000000 / 60;
}
mTolerableSkippedNanos = 15 * mFrameIntervalNanos;
}
private void hook() {
Class<?> cls = null;
try {
cls = Class.forName("android.view.Choreographer$FrameDisplayEventReceiver");
} catch (ClassNotFoundException e) {
Log.w(TAG, "fail to find class FrameDisplayEventReceiver");
e.printStackTrace();
return;
}
XC_MethodHook mehodHook = new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
long timestampNanos = (Long)param.args[0];
// int builtInDisplayId = (Integer)param.args[1];
// int frame = (Integer)param.args[2];
long startNanos = System.nanoTime();
jitterNanos = startNanos - timestampNanos;
// we skip the frame that had been violate the mTolerableSkippedNanos when onVsync() arrived.
if (jitterNanos >= mTolerableSkippedNanos) {
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
Log.i(TAG, "main thread skip " + skippedFrames + "frames");
}
}
};
//Choreographer 在4.1系统才有,并且4.2与4.1在onVsync方法的参数上有区别
if(Build.VERSION.SDK_INT >= 17) {
onVsync = DexposedBridge.findAndHookMethod(cls, "onVsync", long.class, int.class, int.class, mehodHook);
}
else if(Build.VERSION.SDK_INT == 16){
onVsync = DexposedBridge.findAndHookMethod(cls, "onVsync", long.class, int.class, mehodHook);
}
}
private void unhook() {
if(onVsync != null) {
onVsync.unhook();
onVsync = null;
}
}
private static final String TAG = "Lag";
private long mFrameIntervalNanos;
private long mTolerableSkippedNanos;
private Unhook onVsync;
private long jitterNanos;
private boolean isStart = false;
public void start() {
if(!isEnable()) return;
if(isStart) return;
hook();
isStart = true;
}
public void stop() {
if(!isEnable()) return;
if(!isStart) return;
unhook();
isStart = false;
}
}