Android Matrix Resource-Canary 源码解析

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<>();//链表保存泄漏aci
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值