1.ResourcePlugin init方法里创建执行activity泄漏检测的类ActivityRefWatcher,start方法里启动检测mWatcher.start();
public class ResourcePlugin extends Plugin {
private static final String TAG = "Matrix.ResourcePlugin";
//配置类
private final ResourceConfig mConfig;
//执行activity泄漏检测的类
private ActivityRefWatcher mWatcher = null;
public ResourcePlugin(ResourceConfig config) {
mConfig = config;
}
//todo 没有用到
public static void activityLeakFixer(Application application) {
// Auto break the path from Views in their holder to gc root when activity is destroyed.
application.registerActivityLifecycleCallbacks(new ActivityLifeCycleCallbacksAdapter() {
@Override
public void onActivityDestroyed(Activity activity) {
ActivityLeakFixer.fixInputMethodManagerLeak(activity);
ActivityLeakFixer.unbindDrawables(activity);
ActivityLeakFixer.fixViewLocationHolderLeakApi28(activity);
}
});
}
public ActivityRefWatcher getWatcher() {
return mWatcher;
}
@Override
public void init(Application app, PluginListener listener) {
super.init(app, listener);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
MatrixLog.e(TAG, "API is low Build.VERSION_CODES.ICE_CREAM_SANDWICH(14), ResourcePlugin is not supported");
unSupportPlugin();
return;
}
//执行activity泄漏检测的类
mWatcher = new ActivityRefWatcher(app, this);
}
@Override
public void start() {
super.start();
if (!isSupported()) {
MatrixLog.e(TAG, "ResourcePlugin start, ResourcePlugin is not supported, just return");
return;
}
//开启检测
mWatcher.start();
}
@Override
public void stop() {
super.stop();
if (!isSupported()) {
MatrixLog.e(TAG, "ResourcePlugin stop, ResourcePlugin is not supported, just return");
return;
}
//关掉检测
mWatcher.stop();
}
@Override
public void destroy() {
super.destroy();
if (!isSupported()) {
MatrixLog.e(TAG, "ResourcePlugin destroy, ResourcePlugin is not supported, just return");
return;
}
//destroy检测
mWatcher.destroy();
}
@Override
public String getTag() {
return SharePluginInfo.TAG_PLUGIN;
}
@Override
public void onForeground(boolean isForeground) {
MatrixLog.d(TAG, "onForeground: %s", isForeground);
if (isPluginStarted() && mWatcher != null) {
mWatcher.onForeground(isForeground);
}
}
public ResourceConfig getConfig() {
return mConfig;
}
}
2.ActivityRefWatcher具体检测的类
public class DestroyedActivityInfo {
//为每个已经ondestroy的activity设置一个key
public final String mKey;
//activity的名字
public final String mActivityName;
//已经调用onDestroy方法的activity的弱引用
public final WeakReference<Activity> mActivityRef;
//强制gc多次发现这个activity泄漏的次数
public int mDetectedCount = 0;
public DestroyedActivityInfo(String key, Activity activity, String activityName) {
mKey = key;
mActivityName = activityName;
mActivityRef = new WeakReference<>(activity);
}
}
//ok - HeapDump代表
public class HeapDump implements Serializable {
//Hprof文件
private final File mHprofFile;
//DestroyedActivityInfo类中为每个已经ondestroy的activity设置的key
private final String mRefKey;
//activity名字
private final String mActivityName;
public HeapDump(File hprofFile, String refKey, String activityName) {
mHprofFile = Preconditions.checkNotNull(hprofFile, "hprofFile");
mRefKey = Preconditions.checkNotNull(refKey, "refKey");
mActivityName = Preconditions.checkNotNull(activityName, "activityName");
}
public File getHprofFile() {
return mHprofFile;
}
public String getReferenceKey() {
return mRefKey;
}
public String getActivityName() {
return mActivityName;
}
}
public final class ResourceConfig {
public static final String TAG = "Matrix.ResourceConfig";
//应用在前台时,每分钟去检测是否有泄漏
private static final long DEFAULT_DETECT_INTERVAL_MILLIS = TimeUnit.MINUTES.toMillis(1);
//应用在后台时,每20分钟检测是否有泄漏
private static final long DEFAULT_DETECT_INTERVAL_MILLIS_BG = TimeUnit.MINUTES.toMillis(20);
//检测一个activity是否泄漏,是检测了10次它还没回收,就说明它泄漏了
private static final int DEFAULT_MAX_REDETECT_TIMES = 10;
//默认的模式是MANUAL_DUMP,手动dump
private static final DumpMode DEFAULT_DUMP_HPROF_MODE = DumpMode.MANUAL_DUMP;
private final IDynamicConfig mDynamicConfig;//todo,一个动态配置类
//dump模式
private final DumpMode mDumpHprofMode;
private final boolean mDetectDebugger;//是否在debugger模式支持
private final String mTargetActivity;//查看泄漏的Activity,在ManualDumpProcessor里会用到
private ResourceConfig(IDynamicConfig dynamicConfig, DumpMode dumpHprofMode, boolean detectDebuger, String targetActivity) {
this.mDynamicConfig = dynamicConfig;
this.mDumpHprofMode = dumpHprofMode;
this.mDetectDebugger = detectDebuger;
this.mTargetActivity = targetActivity;
}
//应用在前台时,每分钟去检测是否有泄漏
public long getScanIntervalMillis() {
return mDynamicConfig.get(IDynamicConfig.ExptEnum.clicfg_matrix_resource_detect_interval_millis.name(), DEFAULT_DETECT_INTERVAL_MILLIS);
}
//应用在后台时,每20分钟检测是否有泄漏
public long getBgScanIntervalMillis() {
return mDynamicConfig.get(IDynamicConfig.ExptEnum.clicfg_matrix_resource_detect_interval_millis_bg.name(), DEFAULT_DETECT_INTERVAL_MILLIS_BG);
}
//检测10次
public int getMaxRedetectTimes() {
return mDynamicConfig.get(IDynamicConfig.ExptEnum.clicfg_matrix_resource_max_detect_times.name(), DEFAULT_MAX_REDETECT_TIMES);
}
//检测模式
public DumpMode getDumpHprofMode() {
return mDumpHprofMode;
}
//手动dump模式的时候,跳转activity
public String getTargetActivity() {
return mTargetActivity;
}
//debug模式是否可以检测
public boolean getDetectDebugger() {
return mDetectDebugger;
}
//如果跳过触发Dump Hprof,甚至可以把监测步骤在现网环境启用,以发现测试阶段难以触发的Activity泄漏
public enum DumpMode {
NO_DUMP, // report only,只上报名字
AUTO_DUMP, // auto dump hprof,
MANUAL_DUMP, // notify only
SILENCE_ANALYSE, // dump and analyse hprof when screen off
FORK_DUMP, // fork dump hprof immediately TODO
FORK_ANALYSE, // fork dump and analyse hprof immediately TODO
}
public static final class Builder {
private DumpMode mDefaultDumpHprofMode = DEFAULT_DUMP_HPROF_MODE;
private IDynamicConfig dynamicConfig;
private String mTargetActivity;
private boolean mDetectDebugger = false;
public Builder dynamicConfig(IDynamicConfig dynamicConfig) {
this.dynamicConfig = dynamicConfig;
return this;
}
public Builder setAutoDumpHprofMode(DumpMode mode) {
mDefaultDumpHprofMode = mode;
return this;
}
public Builder setDetectDebuger(boolean enabled) {
mDetectDebugger = true;
return this;
}
public Builder setManualDumpTargetActivity(String targetActivity) {
mTargetActivity = targetActivity;
return this;
}
public ResourceConfig build() {
return new ResourceConfig(dynamicConfig, mDefaultDumpHprofMode, mDetectDebugger, mTargetActivity);
}
}
}
public class SharePluginInfo {
//plugin名字
public static final String TAG_PLUGIN = "memory";
//Hprof压缩文件位置?
public static final String ISSUE_RESULT_PATH = "resultZipPath";
//dump的模式
public static final String ISSUE_DUMP_MODE = "dump_mode";
//泄漏的activity的名字
public static final String ISSUE_ACTIVITY_NAME = "activity";
//泄漏的acitivity的唯一key
public static final String ISSUE_REF_KEY = "ref_key";
//refChain gc链
public static final String ISSUE_LEAK_DETAIL = "leak_detail";
//花了多长时间,dump+分析的消耗时间
public static final String ISSUE_COST_MILLIS = "cost_millis";
//进程名字
public static final String ISSUE_LEAK_PROCESS = "leak_process";
//没用到
public static final String ISSUE_NOTIFICATION_ID = "notification_id";
public static final class IssueType {
public static final int LEAK_FOUND = 0;
public static final int ERR_FILE_NOT_FOUND = 2;
public static final int ERR_ANALYSE_OOM = 3;
}
}
/**
* ActivityRefWatcher继承于FilePublisher,可以将检测出来的泄漏activity保存到SharedPreferences里,设置了一天过期日期
*/
public class ActivityRefWatcher extends FilePublisher implements Watcher {
private static final String TAG = "Matrix.ActivityRefWatcher";
private static final int CREATED_ACTIVITY_COUNT_THRESHOLD = 1;
//文件过期时间一天,FilePublisher
private static final long FILE_CONFIG_EXPIRED_TIME_MILLIS = TimeUnit.DAYS.toMillis(1);
//为每个destory activity设置的唯一key的前缀
private static final String ACTIVITY_REFKEY_PREFIX = "MATRIX_RESCANARY_REFKEY_";
//ResourcePlugin
private final ResourcePlugin mResourcePlugin;
private final RetryableTaskExecutor mDetectExecutor;//定位泄漏的Executor,重复循环检测
private final int mMaxRedetectTimes;//几次gc之后才确定是否属于泄漏了,10次
private final long mBgScanTimes;//在后台的时候20分钟扫描一次
private final long mFgScanTimes;//在前台的时候1分钟扫描一次
//处理线程
private final HandlerThread mHandlerThread;
//延时handler
private final Handler mHandler;
//存放destory的activity的链表
private final ConcurrentLinkedQueue<DestroyedActivityInfo> mDestroyedActivityInfos;
private final BaseLeakProcessor mLeakProcessor;//检测到泄漏了,处理程序
//dump模式
private final ResourceConfig.DumpMode mDumpHprofMode;
public static class ComponentFactory {//工厂
//创建循环重复检测的执行器,传入循环时间,后台线程
protected RetryableTaskExecutor createDetectExecutor(ResourceConfig config, HandlerThread handlerThread) {
return new RetryableTaskExecutor(config.getScanIntervalMillis(), handlerThread);
}
//发生泄漏后,创建处理器
protected BaseLeakProcessor createCustomLeakProcessor(ResourceConfig.DumpMode dumpMode, ActivityRefWatcher watcher) {
return null;
}
private BaseLeakProcessor createLeakProcess(ResourceConfig.DumpMode dumpMode, ActivityRefWatcher watcher) {
BaseLeakProcessor leakProcessor = createCustomLeakProcessor(dumpMode, watcher);
if (leakProcessor != null) {
return leakProcessor;
}
//根据模式,创建处理器
switch (dumpMode) {
case AUTO_DUMP:
return new AutoDumpProcessor(watcher);
case MANUAL_DUMP:
//manual会让用户跳到一个activity里处理
return new ManualDumpProcessor(watcher, watcher.getResourcePlugin().getConfig().getTargetActivity());
case SILENCE_ANALYSE:
return new SilenceAnalyseProcessor(watcher);
case NO_DUMP:
default:
return new NoDumpProcessor(watcher);
}
}
}
public ActivityRefWatcher(Application app,
final ResourcePlugin resourcePlugin) {
this(app, resourcePlugin, new ComponentFactory());
}
private ActivityRefWatcher(Application app,
ResourcePlugin resourcePlugin,
ComponentFactory componentFactory) {
super(app, FILE_CONFIG_EXPIRED_TIME_MILLIS, resourcePlugin.getTag(), resourcePlugin);
this.mResourcePlugin = resourcePlugin;
final ResourceConfig config = resourcePlugin.getConfig();//动态配置
//todo MatrixHandlerThread使用
mHandlerThread = MatrixHandlerThread.getNewHandlerThread("matrix_res", Thread.NORM_PRIORITY); // avoid blocking default matrix thread
mHandler = new Handler(mHandlerThread.getLooper());//创建一个单独线程,调度检测任务
mDumpHprofMode = config.getDumpHprofMode();//dump模式
mBgScanTimes = config.getBgScanIntervalMillis();//后台检测时间20分钟
mFgScanTimes = config.getScanIntervalMillis();//前台检测时间1分钟
mDetectExecutor = componentFactory.createDetectExecutor(config, mHandlerThread);//工厂创建调度任务器
mMaxRedetectTimes = config.getMaxRedetectTimes();//发现几次就说明泄漏了
mLeakProcessor = componentFactory.createLeakProcess(mDumpHprofMode, this);//泄漏之后处理器
mDestroyedActivityInfos = new ConcurrentLinkedQueue<>();//链表保存泄漏acitvity结构体
}
public void onForeground(boolean isForeground) {
if (isForeground) {
MatrixLog.i(TAG, "we are in foreground, modify scan time[%sms].", mFgScanTimes);
mDetectExecutor.clearTasks();
mDetectExecutor.setDelayMillis(mFgScanTimes);
mDetectExecut