目录
- 0.前言
- 1.初始化
- 2.内存监控MemoryCanaryPlugin
- 3.性能监控TracePlugin
0.前面随便写点什么
项目地址
https://github.com/Tencent/matrix
1.初始化
Matrix.Builder builder = new Matrix.Builder(application);
// build matrix
builder.patchListener(new TestPluginListener(this));
// add general pluginListener
DynamicConfigImplDemo dynamicConfig = new DynamicConfigImplDemo();
// dynamic config
// init plugin
IOCanaryPlugin ioCanaryPlugin = new IOCanaryPlugin(new IOConfig.Builder()
.dynamicConfig(dynamicConfig)
.build());
//add to matrix
builder.plugin(ioCanaryPlugin);
//init matrix
Matrix.init(builder.build());
// start plugin
ioCanaryPlugin.start();
建造者模式,内部类Builder
patchListener就是监听每一个patch的生命周期
DynamicConfigImplDemo 实际是IDynamicConfig的实现类,用于动态设置参数,里面也有个matrix-config.xml是参数配置文件。
Plugin后续再说。
Matrix内部维护了一个HashSet
public Builder plugin(Plugin plugin) {
if (plugins == null) {
plugins = new HashSet<>();
}
String tag = plugin.getTag();
for (Plugin exist : plugins) {
if (tag.equals(exist.getTag())) {
throw new RuntimeException(String.format("plugin with tag %s is already exist", tag));
}
}
plugins.add(plugin);
return this;
}
先用tag做判断,再者HashSet也不允许有重复的值存在,也就是Matrix里同一类型的plugin只能有一个。
接下来就是
public Matrix build() {
if (pluginListener == null) {
pluginListener = new DefaultPluginListener(application);
}
return new Matrix(application, pluginListener, plugins);
}
private Matrix(Application app, PluginListener listener, HashSet plugins) {
this.application = app;
this.pluginListener = listener;
this.plugins = plugins;
for (Plugin plugin : plugins) {
plugin.init(application, pluginListener);
pluginListener.onInit(plugin);
}
}
public static Matrix init(Matrix matrix) {
if (matrix == null) {
throw new RuntimeException("Matrix init, Matrix should not be null.");
}
synchronized (Matrix.class) {
if (sInstance == null) {
sInstance = matrix;
} else {
MatrixLog.e(TAG, "Matrix instance is already set. this invoking will be ignored");
}
}
return sInstance;
}
至此,完成了Matrix装饰类的初始化。
其余的每一个Plugin插件初始化斗差不多,就用demo里的IOPlugin
每一个Plugin像glide那样,传入一个动态参数。
在Matrix的构造方法里,plugin依次调用init方法,plugin的init方法初始化PluginCore核心类,最终plugin的start方法也是core核心类的start方法。
2.内存监控MemoryCanaryPlugin
初始化多了一个HashSet维护的activity集合
MemoryCanaryPlugin类
public void init(Application app, PluginListener listener) {
super.init(app, listener);
mCore = new MemoryCanaryCore(this);
HashSet specialActivities = mMemoryConfig.getSpecialActivities();
if (specialActivities != null) {
for (String activity : specialActivities) {
mCore.addSpecial(activity);
}
}
}
MemoryConfig类
public HashSet getSpecialActivities() {
String strActivities = mDynamicConfig.get(IDynamicConfig.ExptEnum.clicfg_matrix_memory_special_activities.name(), DEFAULT_SPECIAL_ACTIVITIES);
if (strActivities == null || "".equals(strActivities)) {
return null;
}
String[] vecActivities = strActivities.split(";");
HashSet result = new HashSet<>();
for (String activity : vecActivities) {
if ("".equals(activity)) {
continue;
}
result.add(activity);
}
return result;
}
重点关注MemoryCanaryCore类
start方法首先检测机器条件是否允许,获取内存信息,注册生命周期回调callback----添加到set里进行管理,还有组件回调---在合适的时候dumpMem信息
public void start() {
mLevel = DeviceUtil.getLevel(mContext);
if (!isApiLevelOk() || mLevel == DeviceUtil.LEVEL.LOW || mLevel == DeviceUtil.LEVEL.BAD || mLevel == DeviceUtil.LEVEL.UN_KNOW) {
mIsOpen = false;
return;
}
mIsOpen = true;
//all in kb
mTotalMemory = DeviceUtil.getTotalMemory(mContext) / 1024;
mLowMemoryThreshold = DeviceUtil.getLowMemoryThresold(mContext) / 1024;
mMemoryClass = DeviceUtil.getMemoryClass(mContext);
if (mLowMemoryThreshold >= mTotalMemory || mLowMemoryThreshold == 0) {
mIsOpen = false;
}
((Application) mContext).registerActivityLifecycleCallbacks(mActivityLifecycleCallback);
mContext.registerComponentCallbacks(mComponentCallback);
}
private final Application.ActivityLifecycleCallbacks mActivityLifecycleCallback = new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
if (!mActivityMap.containsKey(activity.getClass().hashCode())) {
mActivityMap.put(activity.getClass().hashCode(), activity.getClass().getSimpleName());
if (mSpecialActivityName.contains(activity.getClass().getSimpleName())) {
mSpecialActivity.add(activity.getClass().hashCode());
}
}
MatrixLog.d(TAG, "activity create:" + activity.getClass().getSimpleName());
}
@Override
public void onActivityStarted(final Activity activity) {
onShow(activity);
}
.....//关键代码
};
private final ComponentCallbacks2 mComponentCallback = new ComponentCallbacks2() {
@Override
public void onTrimMemory(final int i) {
switch (i) {
case TRIM_MEMORY_RUNNING_CRITICAL:
break;
case TRIM_MEMORY_COMPLETE:
break;
default:
return;
}
mHandler.post(new Runnable() {
@Override
public void run() {
detectAppMemoryInfo(mShowingActivity, true, i);
}
});
}
.....//关键代码
@Override
public void onLowMemory() {
mHandler.post(new Runnable() {
@Override
public void run() {
detectAppMemoryInfo(mShowingActivity, true, LOW_MEMORY_TRIM);
}
});
}
};
detectAppMemoryInfo这个我就不多说了
在activity生命周期的activityStart里面有个onShow方法
问题:
没有太懂,为什么对activity做了个IFragmentActivity的判断?
这个IFragmentActivity是一个Interface,也没有看见哪个activity实现了这个接口。
detectAppMemoryInfo之后,最终是调用detectAppMemoryInfoImpl
并且会触发onDetectIssue回调。
最终由pluginListener.onReportIssue(issue);把内存信息发送出去。
MemoryCanaryPlugin没有做内存泄露的检测,可能是没必要重复造轮子吧。
3.性能监控TracePlugin
这个监控应该是四个角度
TracePlugin类的四个成员变量
private FPSTracer mFPSTracer;//帧率
private EvilMethodTracer mEvilMethodTracer;//应该是耗时方法
private FrameTracer mFrameTracer;//帧数
private StartUpTracer mStartUpTracer;//启动速度
初始化
public void init(Application app, PluginListener listener) {
super.init(app, listener);
MatrixLog.i(TAG, "trace plugin init, trace config: %s", mTraceConfig.toString());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
MatrixLog.e(TAG, "[FrameBeat] API is low Build.VERSION_CODES.JELLY_BEAN(16), TracePlugin is not supported");
unSupportPlugin();
return;
}
ApplicationLifeObserver.init(app);
mFrameTracer = new FrameTracer(this);//帧数检测是默认开启的
if (mTraceConfig.isMethodTraceEnable()) {
mStartUpTracer = new StartUpTracer(this, mTraceConfig);
}
if (mTraceConfig.isFPSEnable()) {
mFPSTracer = new FPSTracer(this, mTraceConfig);
}
if (mTraceConfig.isMethodTraceEnable()) {
mEvilMethodTracer = new EvilMethodTracer(this, mTraceConfig);
}
}
ApplicationLifeObserver实现了ActivityLifecycleCallbacks接口,内部是监控activity是否在前台。
start后,重点关注FrameBeat.getInstance().onCreate();
然后先看mFPSTracer.onCreate();
public void start() {
super.start();
if (!isSupported()) {
return;
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
FrameBeat.getInstance().onCreate();
}
});
if (null != mFPSTracer) {
mFPSTracer.onCreate();
}
//....省略
}
实际上呢,这个FrameBeat就是借助了Choreographer.FrameCallback
监控相邻两次 Vsync 事件通知的时间差
(360的开源方案https://github.com/Qihoo360/ArgusAPM)
微信自己的公众号也说了
https://mp.weixin.qq.com/s/W4-1tfepKg2XMYvVn62B-Q
确实在FrameBeat类,在activity的Resume时间注册这个回调,在pause反注册,doFrame里完成事件的记录。
public void doFrame(long frameTimeNanos) {
if (isPause) {
return;
}
if (frameTimeNanos < mLastFrameNanos || mLastFrameNanos <= 0) {
mLastFrameNanos = frameTimeNanos;
if (null != mChoreographer) {
mChoreographer.postFrameCallback(this);
}
return;
}
if (null != mFrameListeners) {
for (IFrameBeatListener listener : mFrameListeners) {
listener.doFrame(mLastFrameNanos, frameTimeNanos);
}
if (null != mChoreographer) {
mChoreographer.postFrameCallback(this);
}
mLastFrameNanos = frameTimeNanos;
}
}
由IFrameBeatListener完成回调动作,BaseTracer实现了IFrameBeatListener接口,但是内部是一个空实现,最终由子类FrameTracer来实现真正的统计方法。
public void doFrame(final long lastFrameNanos, final long frameNanos) {
if (!isDrawing) {
return;
}
isDrawing = false;
final int droppedCount = (int) ((frameNanos - lastFrameNanos) / REFRESH_RATE_MS);
for (final IDoFrameListener listener : mDoFrameListenerList) {
listener.doFrameSync(lastFrameNanos, frameNanos, getScene(), droppedCount);
if (null != listener.getHandler()) {
listener.getHandler().post(new AsyncDoFrameTask(listener,
lastFrameNanos, frameNanos, getScene(), droppedCount));
}
}
}
continue...
参考链接
已经有人写了,可能我要鸽了
https://mp.weixin.qq.com/s/0EprsJ7sXKmphghMsU3aGw