IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android Matrix Resource-Canary 源码解析 -> 正文阅读

[移动开发]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<>();//链表保存泄漏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);
            mDetectExecutor.executeInBackground(mScanDestroyedActivitiesTask);
        } else {
            MatrixLog.i(TAG, "we are in background, modify scan time[%sms].", mBgScanTimes);
            mDetectExecutor.setDelayMillis(mBgScanTimes);
        }
    }

    private final Application.ActivityLifecycleCallbacks mRemovedActivityMonitor = new ActivityLifeCycleCallbacksAdapter() {

        @Override
        public void onActivityDestroyed(Activity activity) {
            //记录已被destory的Activity
            pushDestroyedActivityInfo(activity);
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    triggerGc();
                }
            }, 2000);
        }
    };

    @Override
    public void start() {
        stopDetect();
        final Application app = mResourcePlugin.getApplication();
        if (app != null) {
            //注册监听
            app.registerActivityLifecycleCallbacks(mRemovedActivityMonitor);
            //开始检测
            scheduleDetectProcedure();
            MatrixLog.i(TAG, "watcher is started.");
        }
    }

    @Override
    public void stop() {
        stopDetect();
        MatrixLog.i(TAG, "watcher is stopped.");
    }

    private void stopDetect() {
        final Application app = mResourcePlugin.getApplication();
        if (app != null) {
            //停止注册activity生命周期监听
            app.unregisterActivityLifecycleCallbacks(mRemovedActivityMonitor);
            //关掉检测
            unscheduleDetectProcedure();
        }
    }

    @Override
    public void destroy() {
        //停止检测
        mDetectExecutor.quit();
        //释放线程
        mHandlerThread.quitSafely();
        //释放处理器
        mLeakProcessor.onDestroy();
        MatrixLog.i(TAG, "watcher is destroyed.");
    }

    private void pushDestroyedActivityInfo(Activity activity) {
        final String activityName = activity.getClass().getName();
        //在NO_DUMP,AUTO_DUMP模式下,为什么?这两个模式下才执行以下逻辑,轻量级模式
        if ((mDumpHprofMode == ResourceConfig.DumpMode.NO_DUMP || mDumpHprofMode == ResourceConfig.DumpMode.AUTO_DUMP)
                && !mResourcePlugin.getConfig().getDetectDebugger()
                && isPublished(activityName)) {//该Activity确认存在泄漏,已经上报了就return
            MatrixLog.i(TAG, "activity leak with name %s had published, just ignore", activityName);
            return;
        }
        final UUID uuid = UUID.randomUUID();
        final StringBuilder keyBuilder = new StringBuilder();
        //生成Activity实例的唯一标识
        keyBuilder.append(ACTIVITY_REFKEY_PREFIX).append(activityName)
                .append('_').append(Long.toHexString(uuid.getMostSignificantBits())).append(Long.toHexString(uuid.getLeastSignificantBits()));
        final String key = keyBuilder.toString();
        //构造一个数据结构,表示一个已被destroy的Activity
        final DestroyedActivityInfo destroyedActivityInfo
                = new DestroyedActivityInfo(key, activity, activityName);
        //放入后续待检测的Activity list
        mDestroyedActivityInfos.add(destroyedActivityInfo);
        synchronized (mDestroyedActivityInfos) {
            mDestroyedActivityInfos.notifyAll();
        }
        MatrixLog.d(TAG, "mDestroyedActivityInfos add %s", activityName);
    }

    /**
     * 将mScanDestroyedActivitiesTask放到mDetectExecutor执行
     */
    private void scheduleDetectProcedure() {
        mDetectExecutor.executeInBackground(mScanDestroyedActivitiesTask);
    }

    /**
     * mDetectExecutor是一个可以重复执行的
     */
    private void unscheduleDetectProcedure() {
//        mDetectExecutor是一个可以重复执行的,清空它里边的消息
        mDetectExecutor.clearTasks();
        //清空mDestroyedActivityInfos链表
        mDestroyedActivityInfos.clear();
    }

    /**
     * 可以重复执行的任务,execute返回RETRY,handler会将其重新发送到消息队列里,在一个后台线程里调用
     */
    private final RetryableTask mScanDestroyedActivitiesTask = new RetryableTask() {

        @Override
        public Status execute() {
            // If destroyed activity list is empty, just wait to save power.
            //链表为空,说明destroy的activity为空,等待
            if (mDestroyedActivityInfos.isEmpty()) {
                MatrixLog.i(TAG, "DestroyedActivityInfo is empty! wait...");
                synchronized (mDestroyedActivityInfos) {
                    try {
                        mDestroyedActivityInfos.wait();
                    } catch (Throwable ignored) {
                        // Ignored.
                    }
                }
                MatrixLog.i(TAG, "DestroyedActivityInfo is NOT empty! resume check");
                return Status.RETRY;
            }

            // Fake leaks will be generated when debugger is attached.
            //Debug调试模式,检测可能失效,直接return
            if (Debug.isDebuggerConnected() && !mResourcePlugin.getConfig().getDetectDebugger()) {
                MatrixLog.w(TAG, "debugger is connected, to avoid fake result, detection was delayed.");
                return Status.RETRY;
            }

//            final WeakReference<Object[]> sentinelRef = new WeakReference<>(new Object[1024 * 1024]); // alloc big object
            triggerGc();
            triggerGc();
            triggerGc();
//            if (sentinelRef.get() != null) {
//                // System ignored our gc request, we will retry later.
//                MatrixLog.d(TAG, "system ignore our gc request, wait for next detection.");
//                return Status.RETRY;
//            }

            final Iterator<DestroyedActivityInfo> infoIt = mDestroyedActivityInfos.iterator();

            while (infoIt.hasNext()) {
                //从链表里循环取出已经destroy的DestroyedActivityInfo信息
                final DestroyedActivityInfo destroyedActivityInfo = infoIt.next();
                //如果NO_DUMP AUTO_DUMP为什么这两个模式?才isPublished检测?
                if ((mDumpHprofMode == ResourceConfig.DumpMode.NO_DUMP || mDumpHprofMode == ResourceConfig.DumpMode.AUTO_DUMP)
                        && !mResourcePlugin.getConfig().getDetectDebugger()
                        && isPublished(destroyedActivityInfo.mActivityName)) {//已经检查过了
                    MatrixLog.v(TAG, "activity with key [%s] was already published.", destroyedActivityInfo.mActivityName);
                    infoIt.remove();
                    continue;
                }
                triggerGc();
                //为null的画,说明回收了,将其删除
                if (destroyedActivityInfo.mActivityRef.get() == null) {
                    // The activity was recycled by a gc triggered outside.
                    MatrixLog.v(TAG, "activity with key [%s] was already recycled.", destroyedActivityInfo.mKey);
                    infoIt.remove();
                    continue;
                }
                //如果没回收,将其发现次数增加
                ++destroyedActivityInfo.mDetectedCount;
                //如果发现次数小于10次的画,检查下一个
                if (destroyedActivityInfo.mDetectedCount < mMaxRedetectTimes
                        && !mResourcePlugin.getConfig().getDetectDebugger()) {
                    // Although the sentinel tell us the activity should have been recycled,
                    // system may still ignore it, so try again until we reach max retry times.
                    MatrixLog.i(TAG, "activity with key [%s] should be recycled but actually still exists in %s times, wait for next detection to confirm.",
                            destroyedActivityInfo.mKey, destroyedActivityInfo.mDetectedCount);

                    triggerGc();
                    continue;
                }

                MatrixLog.i(TAG, "activity with key [%s] was suspected to be a leaked instance. mode[%s]", destroyedActivityInfo.mKey, mDumpHprofMode);
                //发现次数大于10次了,如果处理器为null,报空指针
                if (mLeakProcessor == null) {
                    throw new NullPointerException("LeakProcessor not found!!!");
                }

                triggerGc();
                //处理器处理泄漏的activiy
                if (mLeakProcessor.process(destroyedActivityInfo)) {
                    MatrixLog.i(TAG, "the leaked activity [%s] with key [%s] has been processed. stop polling", destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey);
                    infoIt.remove();
                }
            }

            triggerGc();
            return Status.RETRY;
        }
    };

    /**
     * 返回根据dump模式,返回不同处理器
     * @return
     */
    public BaseLeakProcessor getLeakProcessor() {
        return mLeakProcessor;
    }

    /**
     * 返回ResourcePlugin
     * @return
     */
    public ResourcePlugin getResourcePlugin() {
        return mResourcePlugin;
    }

    /**
     * 返回DestroyedActivityInfo链表
     *
     * @return
     */
    public Collection<DestroyedActivityInfo> getDestroyedActivityInfos() {
        return mDestroyedActivityInfos;
    }

    /**
     * triggerGc的时候
     */
    public void triggerGc() {
        MatrixLog.v(TAG, "triggering gc...");
        //1.调用gc
        Runtime.getRuntime().gc();
        //2.睡眠100毫秒
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            MatrixLog.printErrStackTrace(TAG, e, "");
        }
        //3.运行Finalization方法
        Runtime.getRuntime().runFinalization();
        MatrixLog.v(TAG, "gc was triggered.");
    }
}

3.FilePublisher可以将activity名字和发生泄漏的时间保存到SharedPreferences,设置了一天的过期日期

public class FilePublisher extends IssuePublisher {
    private static final String TAG = "Matrix.FilePublisher";

    private final long                     mExpiredTime;//一天过期日期
    private final SharedPreferences.Editor mEditor;
    private final HashMap<String, Long>    mPublishedMap;//activity名字和发生泄漏的时间

    private final Context mContext;


    public FilePublisher(Context context, long expire, String tag, OnIssueDetectListener issueDetectListener) {
        super(issueDetectListener);
        this.mContext = context;
        mExpiredTime = expire;//1天过期日期
        SharedPreferences sharedPreferences = context.getSharedPreferences(tag + MatrixUtil.getProcessName(context), Context.MODE_PRIVATE);
        mPublishedMap = new HashMap<>();//activity名字和发生泄漏的时间
        long current = System.currentTimeMillis();
        mEditor = sharedPreferences.edit();
        HashSet<String> spKeys = null;
        if (null != sharedPreferences.getAll()) {
            spKeys = new HashSet<>(sharedPreferences.getAll().keySet());
        }
        if (null != spKeys) {
            for (String key : spKeys) {
                long start = sharedPreferences.getLong(key, 0);
                long costTime = current - start;
                if (start <= 0 || costTime > mExpiredTime) {
                    mEditor.remove(key);//超时则删除
                } else {
                    mPublishedMap.put(key, start);//没有的话,添加到map里
                }
            }
        }
        if (null != mEditor) {
            mEditor.apply();
        }
    }

    public void markPublished(String key, boolean persist) {
        if (key == null) {
            return;
        }
        if (mPublishedMap.containsKey(key)) {//如果含有则返回
            return;
        }
        final long now = System.currentTimeMillis();
        mPublishedMap.put(key, now);
        //如果保存文件里则保存到SharedPreferences里
        if (persist) {
            SharedPreferences.Editor e = mEditor.putLong(key, now);
            if (null != e) {
                e.apply();
            }
        }
    }

    @Override
    public void markPublished(String key) {
        markPublished(key, true);
    }

    @Override
    public void unMarkPublished(String key) {
        if (key == null) {
            return;
        }
        if (!mPublishedMap.containsKey(key)) {
            return;
        }
        mPublishedMap.remove(key);
        SharedPreferences.Editor e = mEditor.remove(key);
        if (null != e) {
            e.apply();
        }
    }

    @Override
    public boolean isPublished(String key) {
        if (!mPublishedMap.containsKey(key)) {
            return false;
        }
        long start = mPublishedMap.get(key);
        //时间判断,超过1天删除,并返回false
        if (start <= 0 || (System.currentTimeMillis() - start) > mExpiredTime) {
            SharedPreferences.Editor e = mEditor.remove(key);
            if (null != e) {
                e.apply();
            }
            mPublishedMap.remove(key);
            return false;
        }
        return true;
    }

    public Context getContext() {
        return mContext;
    }
}

4.RetryableTaskExecutor再次执行某个任务的执行器,如果RetryableTask execute返回的是RETRY则重新执行,用在循环定时检测有没有内存泄漏

//再次执行某个任务的执行器
public class RetryableTaskExecutor {
    //后台handler,将task发送到后台线程执行
    private final Handler mBackgroundHandler;
    //主线程handler,将task发送到主线程执行
    private final Handler mMainHandler;
    //执行时间delay时间
    private long mDelayMillis;

    public RetryableTaskExecutor(long delayMillis, HandlerThread handleThread) {
        mBackgroundHandler = new Handler(handleThread.getLooper());
        mMainHandler = new Handler(Looper.getMainLooper());
        mDelayMillis = delayMillis;
    }

    //设置delay时间
    public void setDelayMillis(long delayed) {
        this.mDelayMillis = delayed;
    }

    //没有用
    public void executeInMainThread(final RetryableTask task) {
        postToMainThreadWithDelay(task, 0);
    }

    //发送到后台线程执行任务
    public void executeInBackground(final RetryableTask task) {
        postToBackgroundWithDelay(task, 0);
    }

    //清空任务
    public void clearTasks() {
        mBackgroundHandler.removeCallbacksAndMessages(null);
        mMainHandler.removeCallbacksAndMessages(null);
    }

    //丢弃
    public void quit() {
        clearTasks();
    }

    //没有用
    private void postToMainThreadWithDelay(final RetryableTask task, final int failedAttempts) {
        mMainHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                RetryableTask.Status status = task.execute();
                if (status == RetryableTask.Status.RETRY) {
                    postToMainThreadWithDelay(task, failedAttempts + 1);
                }
            }
        }, mDelayMillis);
    }

    /**
     * 发送任务到后台线程
     * @param task 代表任务,它的execute返回RETRY的时候,还需将其再次发送任务到后台线程,再次执行
     * @param failedAttempts 传入失败次数
     */
    private void postToBackgroundWithDelay(final RetryableTask task, final int failedAttempts) {
        mBackgroundHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                RetryableTask.Status status = task.execute();
                if (status == RetryableTask.Status.RETRY) {
                    postToBackgroundWithDelay(task, failedAttempts + 1);
                }
            }
        }, mDelayMillis);
    }

    /**
     * 代表可以执行再次执行的任务
     */
    public interface RetryableTask {
//        如果返回了RETRY,将其再次发送到线程执行
        Status execute();

        enum Status {
            DONE, RETRY
        }
    }
}

5.BaseLeakProcessor 基础处理类

public class AndroidHeapDumper {
    private static final String TAG = "Matrix.AndroidHeapDumper";

    private final Context mContext;
    //文件相关
    private final DumpStorageManager mDumpStorageManager;
    //主线程handler
    private final Handler mMainHandler;

    public AndroidHeapDumper(Context context, DumpStorageManager dumpStorageManager) {
        this(context, dumpStorageManager, new Handler(Looper.getMainLooper()));
    }

    public AndroidHeapDumper(Context context, DumpStorageManager dumpStorageManager, Handler mainHandler) {
        mContext = context;
        mDumpStorageManager = dumpStorageManager;
        mMainHandler = mainHandler;
    }

    //dump方法
    public File dumpHeap(boolean isShowToast) {
        //得到hprof文件
        final File hprofFile = mDumpStorageManager.newHprofFile();

        if (null == hprofFile) {
            MatrixLog.w(TAG, "hprof file is null.");
            return null;
        }

        final File hprofDir = hprofFile.getParentFile();
        if (hprofDir == null) {
            MatrixLog.w(TAG, "hprof file path: %s does not indicate a full path.", hprofFile.getAbsolutePath());
            return null;
        }

        if (!hprofDir.canWrite()) {
            MatrixLog.w(TAG, "hprof file path: %s cannot be written.", hprofFile.getAbsolutePath());
            return null;
        }

        //1.5G 小于1.5G 空间返回
        if (hprofDir.getFreeSpace() < 1.5 * 1024 * 1024 * 1024) {
            MatrixLog.w(TAG, "hprof file path: %s free space not enough", hprofDir.getAbsolutePath());
            return null;
        }

        //isShowToast 在AutoDumpProcessor模式会弹窗
        if (isShowToast) {
            final FutureResult<Toast> waitingForToast = new FutureResult<>();
            showToast(waitingForToast);

            if (!waitingForToast.wait(5, TimeUnit.SECONDS)) {//这里是等toast
                MatrixLog.w(TAG, "give up dumping heap, waiting for toast too long.");
                return null;
            }
            try {
                //这里是真正dump的地方
                Debug.dumpHprofData(hprofFile.getAbsolutePath());
                cancelToast(waitingForToast.get());
                return hprofFile;
            } catch (Exception e) {
                MatrixLog.printErrStackTrace(TAG, e, "failed to dump heap into file: %s.", hprofFile.getAbsolutePath());
                return null;
            }
        } else {
            try {
                //这里是真正dump的地方
                Debug.dumpHprofData(hprofFile.getAbsolutePath());
                return hprofFile;
            } catch (Exception e) {
                MatrixLog.printErrStackTrace(TAG, e, "failed to dump heap into file: %s.", hprofFile.getAbsolutePath());
                return null;
            }
        }
    }

    private void showToast(final FutureResult<Toast> waitingForToast) {
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                final Toast toast = new Toast(mContext);
                toast.setDuration(Toast.LENGTH_LONG);
                toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
                LayoutInflater inflater = LayoutInflater.from(mContext);
                toast.setView(inflater.inflate(R.layout.resource_canary_toast_wait_for_heapdump, null));
                toast.show();
                // Waiting for Idle to make sure Toast gets rendered.
                Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
                    @Override
                    public boolean queueIdle() {//等toast花了点时间
                        waitingForToast.set(toast);
                        return false;
                    }
                });
            }
        });
    }

    private void cancelToast(final Toast toast) {
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                toast.cancel();
            }
        });
    }

    public interface HeapDumpHandler {
        void process(HeapDump result);
    }
}
public class DumpStorageManager {
    private static final String TAG = "Matrix.DumpStorageManager";
    //后缀
    public static final String HPROF_EXT = ".hprof";
    //最多五个缓存的hprof
    public static final int DEFAULT_MAX_STORED_HPROF_FILECOUNT = 5;

    protected final Context mContext;
    //最多缓存的hprof数量
    protected final int mMaxStoredHprofFileCount;

    public DumpStorageManager(Context context) {
        this(context, DEFAULT_MAX_STORED_HPROF_FILECOUNT);
    }

    public DumpStorageManager(Context context, int maxStoredHprofFileCount) {
        if (maxStoredHprofFileCount <= 0) {
            throw new IllegalArgumentException("illegal max stored hprof file count: "
                    + maxStoredHprofFileCount);
        }
        mContext = context;
        mMaxStoredHprofFileCount = maxStoredHprofFileCount;
    }

    //新建一个hprof
    public File newHprofFile() {
        final File storageDir = prepareStorageDirectory();
        if (storageDir == null) {
            return null;
        }
//        进程名+进程id+时间+后缀
        final String hprofFileName = "dump"
                + "_" + MatrixUtil.getProcessName(mContext).replace(".", "_").replace(":", "_")
                + "_" + Process.myPid()
                + "_"
                + new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()).format(new Date())
                + HPROF_EXT;
        return new File(storageDir, hprofFileName);
    }

    //创建文件夹
    private File prepareStorageDirectory() {
        final File storageDir = getStorageDirectory();
        if (!storageDir.exists() && (!storageDir.mkdirs() || !storageDir.canWrite())) {
            MatrixLog.w(TAG, "failed to allocate new hprof file since path: %s is not writable.",
                    storageDir.getAbsolutePath());
            return null;
        }
        final File[] hprofFiles = storageDir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(HPROF_EXT);
            }
        });
        if (hprofFiles != null && hprofFiles.length > mMaxStoredHprofFileCount) {
            for (File file : hprofFiles) {
                if (file.exists() && !file.delete()) {
                    MatrixLog.w(TAG, "faile to delete hprof file: " + file.getAbsolutePath());
                }
            }
        }
        return storageDir;
    }

    //获取存储位置
    private File getStorageDirectory() {
        final String sdcardState = Environment.getExternalStorageState();
        File root = null;
        if (Environment.MEDIA_MOUNTED.equals(sdcardState)) {
            root = mContext.getExternalCacheDir();
        } else {
            root = mContext.getCacheDir();
        }
        final File result = new File(root, "matrix_resource");

        MatrixLog.i(TAG, "path to store hprof and result: %s", result.getAbsolutePath());

        return result;
    }
}

public abstract class BaseLeakProcessor {
    private static final String TAG = "Matrix.LeakProcessor.Base";
    //检测泄漏
    private final ActivityRefWatcher mWatcher;
    //dump文件相关
    private DumpStorageManager                mDumpStorageManager;
    //dump的类
    private AndroidHeapDumper                 mHeapDumper;
    //dump完了回调
    private AndroidHeapDumper.HeapDumpHandler mHeapDumpHandler;

    public BaseLeakProcessor(ActivityRefWatcher watcher) {
        mWatcher = watcher;
    }

    public abstract boolean process(DestroyedActivityInfo destroyedActivityInfo);

    public DumpStorageManager getDumpStorageManager() {
        if (mDumpStorageManager == null) {
            mDumpStorageManager = new DumpStorageManager(mWatcher.getContext());
        }
        return mDumpStorageManager;
    }

    public AndroidHeapDumper getHeapDumper() {
        if (mHeapDumper == null) {
            mHeapDumper = new AndroidHeapDumper(mWatcher.getContext(), getDumpStorageManager());
        }
        return mHeapDumper;
    }

    protected AndroidHeapDumper.HeapDumpHandler getHeapDumpHandler() {
        if (mHeapDumpHandler == null) {
            mHeapDumpHandler = new AndroidHeapDumper.HeapDumpHandler() {
                @Override
                public void process(HeapDump result) {
                    //裁剪Hprof并上传,process流程最终调用CanaryWorkerService进行裁剪和上报
                    CanaryWorkerService.shrinkHprofAndReport(mWatcher.getContext(), result);
                }
            };
        }

        return mHeapDumpHandler;
    }

    public ActivityRefWatcher getWatcher() {
        return mWatcher;
    }

    public void onDestroy() {
    }

    /**
     * todo
     * SilenceAnalyseProcessor 调用了
     * ManualDumpProcessor调用了
     * @param hprofFile
     * @param referenceKey
     * @return
     */
    protected ActivityLeakResult analyze(File hprofFile, String referenceKey) {
        final HeapSnapshot heapSnapshot;
        ActivityLeakResult result;
        final ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults(Build.VERSION.SDK_INT, Build.MANUFACTURER).build();
        try {
            heapSnapshot = new HeapSnapshot(hprofFile);
            //todo 这里是这个函数的主要逻辑,使用ActivityLeakAnalyzer分析heapSnapshot,返回ActivityLeakResult
            result = new ActivityLeakAnalyzer(referenceKey, excludedRefs).analyze(heapSnapshot);
        } catch (IOException e) {
            result = ActivityLeakResult.failure(e, 0);
        }
        return result;
    }

    final protected void publishIssue(int issueType, ResourceConfig.DumpMode dumpMode, String activity, String refKey, String detail, String cost) {
        Issue issue = new Issue(issueType);
        JSONObject content = new JSONObject();
        try {
            content.put(SharePluginInfo.ISSUE_DUMP_MODE, dumpMode.name());
            content.put(SharePluginInfo.ISSUE_ACTIVITY_NAME, activity);
            content.put(SharePluginInfo.ISSUE_REF_KEY, refKey);
            content.put(SharePluginInfo.ISSUE_LEAK_DETAIL, detail);
            content.put(SharePluginInfo.ISSUE_COST_MILLIS, cost);
        } catch (JSONException jsonException) {
            MatrixLog.printErrStackTrace(TAG, jsonException, "");
        }
        issue.setContent(content);
        //todo matrix lib框架的功能
        getWatcher().getResourcePlugin().onDetectIssue(issue);
    }
}

6.NoDumpProcessor 可以用于线上的只上报名字

public class NoDumpProcessor extends BaseLeakProcessor {

    private static final String TAG = "Matrix.LeakProcessor.NoDump";

    public NoDumpProcessor(ActivityRefWatcher watcher) {
        super(watcher);
    }

    @Override
    public boolean process(DestroyedActivityInfo destroyedActivityInfo) {
        // Lightweight mode, just report leaked activity name.
        MatrixLog.i(TAG, "lightweight mode, just report leaked activity name.");
        //标记泄漏了
        getWatcher().markPublished(destroyedActivityInfo.mActivityName);
        getWatcher().triggerGc();
        //上报问题
        publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.NO_DUMP, destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey, "no dump", "0");

        return true;
    }
}

7.SilenceAnalyseProcessor在熄屏的时候处理

public class SilenceAnalyseProcessor extends BaseLeakProcessor {

    private static final String TAG = "Matrix.LeakProcessor.SilenceAnalyse";

    private final BroadcastReceiver mReceiver;

    private boolean isScreenOff;
    private boolean isProcessing;

    public SilenceAnalyseProcessor(ActivityRefWatcher watcher) {
        super(watcher);
        //注册监听
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);

        mReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                //设置标记位
                if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
                    isScreenOff = true;
                    MatrixLog.i(TAG, "[ACTION_SCREEN_OFF]");
                } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
                    isScreenOff = false;
                    MatrixLog.i(TAG, "[ACTION_SCREEN_ON]");
                }
            }
        };

        try {
            watcher.getResourcePlugin().getApplication().registerReceiver(mReceiver, filter);
        } catch (Throwable e) {
            MatrixLog.printErrStackTrace(TAG, e, "");
        }
    }

    @Override
    public boolean process(DestroyedActivityInfo destroyedActivityInfo) {
        //处理方法
        return onLeak(destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey);
    }

    @Override
    public void onDestroy() {
        MatrixLog.i(TAG, "onDestroy: unregister receiver");
        //解除注册
        getWatcher().getResourcePlugin().getApplication().unregisterReceiver(mReceiver);
    }

    private boolean onLeak(final String activity, final String refString) {
        MatrixLog.i(TAG, "[onLeak] activity=%s isScreenOff=%s isProcessing=%s", activity, isScreenOff, isProcessing);
        //leak监听过了
        if (getWatcher().isPublished(activity)) {
            MatrixLog.i(TAG, "this activity has been dumped! %s", activity);
            return true;
        }

        if (!isProcessing && isScreenOff) {
            isProcessing = true;

            getWatcher().triggerGc();

            boolean res = dumpAndAnalyse(activity, refString);

            if (res) {
                //又将leak删除了,因为在silent模式下不支持isPublished,在ActivityRefWatcher里只有NO_DUMP,AUTO_DUMP才支持
                getWatcher().markPublished(activity, false);
            }

            isProcessing = false;

            return res;
        }
        return false;
    }

    // todo analyse
    private boolean dumpAndAnalyse(String activity, String refString) {

        long dumpBegin = System.currentTimeMillis();

        File file = getHeapDumper().dumpHeap(false);

        if (file == null || file.length() <= 0) {
            publishIssue(SharePluginInfo.IssueType.ERR_FILE_NOT_FOUND, activity, refString, "file is null", "0");
            MatrixLog.e(TAG, "file is null!");
            return true;
        }

        MatrixLog.i(TAG, String.format("dump cost=%sms refString=%s path=%s",
                System.currentTimeMillis() - dumpBegin, refString, file.getAbsolutePath()));

        long analyseBegin = System.currentTimeMillis();
        try {
            // todo analyse 这里分析了
            final ActivityLeakResult result = analyze(file, refString);
            MatrixLog.i(TAG, String.format("analyze cost=%sms refString=%s",
                    System.currentTimeMillis() - analyseBegin, refString));

            String refChain = result.toString();
            if (result.mLeakFound) {
                //这里分析了
                publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, activity, refString, refChain, String.valueOf(
                        System.currentTimeMillis() - dumpBegin));
                MatrixLog.i(TAG, refChain);
            } else {
                MatrixLog.i(TAG, "leak not found");
            }
        } catch (OutOfMemoryError error) {
            publishIssue(SharePluginInfo.IssueType.ERR_ANALYSE_OOM, activity, refString, "OutOfMemoryError", "0");
            MatrixLog.printErrStackTrace(TAG, error.getCause(), "");
        } finally {
            file.delete();
        }
        return true;
    }

    private void publishIssue(int issueType, String activity, String refKey, String detail, String cost) {
        publishIssue(issueType, ResourceConfig.DumpMode.SILENCE_ANALYSE, activity, refKey, detail, cost);
    }
}

8.ManualDumpProcessor跳转到一个activity处理

/**
 * X process leaked -> send notification -> main process activity
 * -> dump and analyse in X process -> show result in main process activity
 * Created by Yves on 2021/3/4
 */
public class ManualDumpProcessor extends BaseLeakProcessor {

    private static final String TAG = "Matrix.LeakProcessor.ManualDump";

    private static final int NOTIFICATION_ID = 0x110;

    private final String mTargetActivity;

    private final NotificationManager mNotificationManager;

    private final List<DestroyedActivityInfo> mLeakedActivities = new ArrayList<>();

    private boolean isMuted;

    public ManualDumpProcessor(ActivityRefWatcher watcher, String targetActivity) {
        super(watcher);
        //处理activity
        mTargetActivity = targetActivity;
        //notification
        mNotificationManager = (NotificationManager) watcher.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
        //注册BroadcastReceiver
        ManualDumpProcessorHelper.install(watcher.getContext(), this);
    }

    @Override
    public boolean process(DestroyedActivityInfo destroyedActivityInfo) {
        final Context context = getWatcher().getContext();
        //gc了以下
        getWatcher().triggerGc();
        //如果回收了返回true
        if (destroyedActivityInfo.mActivityRef.get() == null) {
            MatrixLog.v(TAG, "activity with key [%s] was already recycled.", destroyedActivityInfo.mKey);
            return true;
        }
        //保存了下泄漏的信息
        mLeakedActivities.add(destroyedActivityInfo);

        MatrixLog.i(TAG, "show notification for activity leak. %s", destroyedActivityInfo.mActivityName);
        //?todo 不知道干哈的
        if (isMuted) {
            MatrixLog.i(TAG, "is muted, won't show notification util process reboot");
            return true;
        }
        //发送通知
        //通知点击之后跳转的activity
        Intent targetIntent = new Intent();
        targetIntent.setClassName(getWatcher().getContext(), mTargetActivity);
        targetIntent.putExtra(SharePluginInfo.ISSUE_ACTIVITY_NAME, destroyedActivityInfo.mActivityName);
        targetIntent.putExtra(SharePluginInfo.ISSUE_REF_KEY, destroyedActivityInfo.mKey);
        targetIntent.putExtra(SharePluginInfo.ISSUE_LEAK_PROCESS, MatrixUtil.getProcessName(context));

        //点击之后的响应pendingintent
        PendingIntent pIntent = PendingIntent.getActivity(context, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        //title
        String dumpingHeapTitle = context.getString(R.string.resource_canary_leak_tip);
        ResourceConfig config = getWatcher().getResourcePlugin().getConfig();
        //content
        String dumpingHeapContent =
                String.format(Locale.getDefault(), "[%s] has leaked for [%s]min!!!",
                        destroyedActivityInfo.mActivityName,
                        TimeUnit.MILLISECONDS.toMinutes(
                                config.getScanIntervalMillis() * config.getMaxRedetectTimes()));

        Notification.Builder builder = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            builder = new Notification.Builder(context, getNotificationChannelIdCompat(context));
        } else {
            builder = new Notification.Builder(context);
        }
        builder.setContentTitle(dumpingHeapTitle)
                .setPriority(Notification.PRIORITY_DEFAULT)
                .setStyle(new Notification.BigTextStyle().bigText(dumpingHeapContent))
                .setContentIntent(pIntent)
                .setAutoCancel(true)
                .setSmallIcon(R.drawable.ic_launcher)
                .setWhen(System.currentTimeMillis());

        Notification notification = builder.build();
        //发送通知
        mNotificationManager.notify(
                NOTIFICATION_ID + destroyedActivityInfo.mKey.hashCode(), notification);
        //上报了问题
        publishIssue(destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey);
        MatrixLog.i(TAG, "shown notification!!!3");
        return true;
    }

    //创建通知channel
    private String getNotificationChannelIdCompat(Context context) {
        if (SDK_INT >= Build.VERSION_CODES.O) {
            String channelName = "com.tencent.matrix.resource.processor.ManualDumpProcessor";
            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationChannel notificationChannel = notificationManager.getNotificationChannel(channelName);
            if (notificationChannel == null) {
                MatrixLog.v(TAG, "create channel");
                notificationChannel = new NotificationChannel(channelName, channelName, NotificationManager.IMPORTANCE_HIGH);
                notificationManager.createNotificationChannel(notificationChannel);
            }
            return channelName;
        }
        return null;
    }

    public void setMuted(boolean mute) {
        isMuted = mute;
    }

    /**
     * run in leaked process
     *
     * @param activity
     * @param refString
     * @return ManualDumpData 包含dump文件+引用链
     */
    private ManualDumpData dumpAndAnalyse(String activity, String refString) {
        long dumpBegin = System.currentTimeMillis();

        getWatcher().triggerGc();

        File file = getHeapDumper().dumpHeap(false);
        if (file == null || file.length() <= 0) {
//            publishIssue(SharePluginInfo.IssueType.ERR_FILE_NOT_FOUND, activity, refString, "file is null", "0");
            MatrixLog.e(TAG, "file is null!");
            return null;
        }

        MatrixLog.i(TAG, String.format("dump cost=%sms refString=%s path=%s",
                System.currentTimeMillis() - dumpBegin, refString, file.getAbsolutePath()));

        long analyseBegin = System.currentTimeMillis();
        try {
            final ActivityLeakResult result = analyze(file, refString);
            MatrixLog.i(TAG, String.format("analyze cost=%sms refString=%s",
                    System.currentTimeMillis() - analyseBegin, refString));

            String refChain = result.toString();
            if (result.mLeakFound) {
//                publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, activity, refString, refChain, String.valueOf(System.currentTimeMillis() - dumpBegin));
                MatrixLog.i(TAG, "leakFound,refcChain = %s", refChain);
                return new ManualDumpData(file.getAbsolutePath(), refChain);
            } else {
                MatrixLog.i(TAG, "leak not found");
                return new ManualDumpData(file.getAbsolutePath(), null);
            }
        } catch (OutOfMemoryError error) {
//            publishIssue(SharePluginInfo.IssueType.ERR_ANALYSE_OOM, activity, refString, "OutOfMemoryError", "0");
            MatrixLog.printErrStackTrace(TAG, error.getCause(), "");
        }
        return null;
    }

    //单纯上报问题
    private void publishIssue(String activity, String refKey) {
        publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.MANUAL_DUMP, activity, refKey, "manual_dump", "0");
    }

    /**
     * multi process dump helper.
     * 多进程dump帮组类
     */
    public static class ManualDumpProcessorHelper extends BroadcastReceiver {
        //permission
        private static final String DUMP_PERMISSION_SUFFIX = ".manual.dump";

        private static final String ACTION_DUMP = "com.tencent.matrix.manual.dump";
        private static final String ACTION_RESULT = "com.tencent.matrix.manual.result";

        private static final String KEY_RESULT_PROCESS = "result_process";
        private static final String KEY_LEAK_ACTIVITY = "leak_activity";
        private static final String KEY_LEAK_PROCESS = "leak_process";
        private static final String KEY_LEAK_REFKEY = "leak_refkey";
        private static final String KEY_HPROF_PATH = "hprof_path";
        private static final String KEY_REF_CHAIN = "ref_chain";
        //是否注册了BroadcastReceiver
        private static boolean hasInstalled;

        private static ManualDumpProcessor sProcessor;
        private static IResultListener sListener; // only not null in process who called dumpAndAnalyse

        @Override
        public void onReceive(final Context context, final Intent intent) {
            if (intent == null) {
                MatrixLog.e(TAG, "intent is null");
                return;
            }

            MatrixHandlerThread.getDefaultHandler().postAtFrontOfQueue(new Runnable() {
                @Override
                public void run() {
                    if (ACTION_DUMP.equals(intent.getAction())) {
                        //进程
                        String leakProcess = intent.getStringExtra(KEY_LEAK_PROCESS);
                        String currentProcess = MatrixUtil.getProcessName(context);
                        //如果是这个进程泄漏了
                        if (!currentProcess.equals(leakProcess)) {
                            MatrixLog.v(TAG, "ACTION_DUMP: current process [%s] is NOT leaked process [%s]", currentProcess, leakProcess);
                            return;
                        }

                        // leaked process
                        MatrixLog.v(TAG, "ACTION_DUMP: current process [%s] is leaked process [%s]", currentProcess, leakProcess);

                        String leakActivity = intent.getStringExtra(KEY_LEAK_ACTIVITY);
                        String refKey = intent.getStringExtra(KEY_LEAK_REFKEY);
                        //dump信息并分析
                        ManualDumpData data = sProcessor.dumpAndAnalyse(leakActivity, refKey);
                        Intent resultIntent = new Intent(ACTION_RESULT);
                        if (data != null) {
                            resultIntent.putExtra(KEY_HPROF_PATH, data.hprofPath);
                            resultIntent.putExtra(KEY_REF_CHAIN, data.refChain);
                        }
                        String resultProcess = intent.getStringExtra(KEY_RESULT_PROCESS);
                        resultIntent.putExtra(KEY_RESULT_PROCESS, resultProcess);
                        context.sendBroadcast(resultIntent,
                                context.getPackageName() + DUMP_PERMISSION_SUFFIX);
                    } else if (ACTION_RESULT.equals(intent.getAction())) {
                        // result process
                        final String resultProcess = intent.getStringExtra(KEY_RESULT_PROCESS);
                        final String currentProcess = MatrixUtil.getProcessName(context);
                        if (!currentProcess.equals(resultProcess)) {
                            MatrixLog.v(TAG, "ACTION_RESULT: current process [%s] is NOT result process [%s]", currentProcess, resultProcess);
                            return;
                        }

                        MatrixLog.v(TAG, "ACTION_RESULT: current process [%s] is result process [%s]", currentProcess, resultProcess);

                        // generally, sListener must be NOT null
                        if (sListener == null) {
                            throw new NullPointerException("result listener is null!!!");
                        }

                        final String hprofPath = intent.getStringExtra(KEY_HPROF_PATH);
                        if (hprofPath == null) {
                            sListener.onFailed();
                            return;
                        }
                        final String refChain = intent.getStringExtra(KEY_REF_CHAIN);
                        sListener.onSuccess(hprofPath, refChain);
                        sListener = null;
                    }
                }
            });
        }

        //注册BroadcastReceiver
        private static void install(Context context, ManualDumpProcessor processor) {
            IntentFilter filter = new IntentFilter();
            filter.addAction(ACTION_DUMP);
            filter.addAction(ACTION_RESULT);
            final String dumpPermission = context.getPackageName() + DUMP_PERMISSION_SUFFIX;
            //注册BroadcastReceiver
            context.registerReceiver(new ManualDumpProcessorHelper(), filter, dumpPermission, null);
            MatrixLog.d(TAG, "[%s] DUMP_PERMISSION is %s", MatrixUtil.getProcessName(context), dumpPermission);
            hasInstalled = true;
            sProcessor = processor;
        }

        //nouse
        public static void dumpAndAnalyse(Context context, String leakProcess, String activity, String refKey, IResultListener resultListener) {
            if (!hasInstalled) {
                throw new IllegalStateException("ManualDumpProcessorHelper was not installed yet!!! maybe your target activity is not running in right process.");
            }
            final String currentProcess = MatrixUtil.getProcessName(context);
            if (currentProcess.equalsIgnoreCase(leakProcess)) {
                // dump and analyze for current process
                ManualDumpData data = sProcessor.dumpAndAnalyse(activity, refKey);
                if (data == null) {
                    resultListener.onFailed();
                } else {
                    resultListener.onSuccess(data.hprofPath, data.refChain);
                }
            } else {
                sListener = resultListener;
                MatrixLog.v(TAG, "[%s] send broadcast with permission: %s", currentProcess,
                        context.getPackageName() + DUMP_PERMISSION_SUFFIX);
                Intent intent = new Intent(ACTION_DUMP);
                intent.putExtra(KEY_LEAK_PROCESS, leakProcess);
                intent.putExtra(KEY_LEAK_ACTIVITY, activity);
                intent.putExtra(KEY_LEAK_REFKEY, refKey);
                intent.putExtra(KEY_RESULT_PROCESS, currentProcess);
                context.sendBroadcast(intent, context.getPackageName() + DUMP_PERMISSION_SUFFIX);
            }
        }
    }

    public interface IResultListener {
        void onSuccess(String hprof, String leakReference);

        void onFailed();
    }

    /**
     * hprof文件路径
     * 链
     */
    public static class ManualDumpData {
        public final String hprofPath;
        public final String refChain;

        public ManualDumpData(String hprofPath, String refChain) {
            this.hprofPath = hprofPath;
            this.refChain = refChain;
        }
    }
}

9.AutoDumpProcessor 会在本地裁剪,然后上传裁剪后的hprof压缩,上报

public class AutoDumpProcessor extends BaseLeakProcessor {

    private static final String TAG = "Matrix.LeakProcessor.AutoDump";

    public AutoDumpProcessor(ActivityRefWatcher watcher) {
        super(watcher);
    }

    @Override
    public boolean process(DestroyedActivityInfo destroyedActivityInfo) {
//        dump
        final File hprofFile = getHeapDumper().dumpHeap(true);
        if (hprofFile != null) {
//标记
            getWatcher().markPublished(destroyedActivityInfo.mActivityName);
            getWatcher().triggerGc();
            //
            final HeapDump heapDump = new HeapDump(hprofFile, destroyedActivityInfo.mKey, destroyedActivityInfo.mActivityName);
            getHeapDumpHandler().process(heapDump);
        } else {
            MatrixLog.i(TAG, "heap dump for further analyzing activity with key [%s] was failed, just ignore.",
                    destroyedActivityInfo.mKey);
        }
        return true;
    }
}

11.CanaryWorkerService裁剪

//裁剪hprof,并上报
public class CanaryWorkerService extends MatrixJobIntentService {
    private static final String TAG = "Matrix.CanaryWorkerService";

    private static final int JOB_ID = 0xFAFBFCFD;
    private static final String ACTION_SHRINK_HPROF = "com.tencent.matrix.resource.worker.action.SHRINK_HPROF";
    private static final String EXTRA_PARAM_HEAPDUMP = "com.tencent.matrix.resource.worker.param.HEAPDUMP";

    //入口
    public static void shrinkHprofAndReport(Context context, HeapDump heapDump) {
        final Intent intent = new Intent(context, CanaryWorkerService.class);
        intent.setAction(ACTION_SHRINK_HPROF);
        intent.putExtra(EXTRA_PARAM_HEAPDUMP, heapDump);
        enqueueWork(context, CanaryWorkerService.class, JOB_ID, intent);
    }

    @Override
    protected void onHandleWork(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_SHRINK_HPROF.equals(action)) {
                try {
                    intent.setExtrasClassLoader(this.getClassLoader());
                    final HeapDump heapDump = (HeapDump) intent.getSerializableExtra(EXTRA_PARAM_HEAPDUMP);
                    if (heapDump != null) {
                        //裁剪并上报
                        doShrinkHprofAndReport(heapDump);
                    } else {
                        MatrixLog.e(TAG, "failed to deserialize heap dump, give up shrinking and reporting.");
                    }
                } catch (Throwable thr) {
                    MatrixLog.printErrStackTrace(TAG, thr, "failed to deserialize heap dump, give up shrinking and reporting.");
                }
            }
        }
    }

    private void doShrinkHprofAndReport(HeapDump heapDump) {
        final File hprofDir = heapDump.getHprofFile().getParentFile();
        //裁剪之后的Hprof文件名
        final File shrinkedHProfFile = new File(hprofDir, getShrinkHprofName(heapDump.getHprofFile()));
        //压缩文件
        final File zipResFile = new File(hprofDir, getResultZipName("dump_result_" + android.os.Process.myPid()));
        final File hprofFile = heapDump.getHprofFile();
        ZipOutputStream zos = null;
        try {
            long startTime = System.currentTimeMillis();
            //执行Hprof裁剪
            new HprofBufferShrinker().shrink(hprofFile, shrinkedHProfFile);
            MatrixLog.i(TAG, "shrink hprof file %s, size: %dk to %s, size: %dk, use time:%d",
                    hprofFile.getPath(), hprofFile.length() / 1024, shrinkedHProfFile.getPath(), shrinkedHProfFile.length() / 1024, (System.currentTimeMillis() - startTime));
            //打成压缩包
            zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipResFile)));
            //记录一些设备信息
            final ZipEntry resultInfoEntry = new ZipEntry("result.info");
            //裁剪后的Hprof文件
            final ZipEntry shrinkedHProfEntry = new ZipEntry(shrinkedHProfFile.getName());

            zos.putNextEntry(resultInfoEntry);
            final PrintWriter pw = new PrintWriter(new OutputStreamWriter(zos, StandardCharsets.UTF_8));
            pw.println("# Resource Canary Result Infomation. THIS FILE IS IMPORTANT FOR THE ANALYZER !!");
            pw.println("sdkVersion=" + Build.VERSION.SDK_INT);//系统版本
            pw.println("manufacturer=" + Build.MANUFACTURER);//厂商信息
            pw.println("hprofEntry=" + shrinkedHProfEntry.getName());//裁剪后Hprof文件名
            pw.println("leakedActivityKey=" + heapDump.getReferenceKey());//泄漏Activity实例的key
            pw.flush();
            zos.closeEntry();

            zos.putNextEntry(shrinkedHProfEntry);
            copyFileToStream(shrinkedHProfFile, zos);
            zos.closeEntry();

            //原始数据删除
            shrinkedHProfFile.delete();
            hprofFile.delete();

            MatrixLog.i(TAG, "process hprof file use total time:%d", (System.currentTimeMillis() - startTime));
            //CanaryResultService执行上报逻辑
            CanaryResultService.reportHprofResult(this, zipResFile.getAbsolutePath(), heapDump.getActivityName());
        } catch (IOException e) {
            MatrixLog.printErrStackTrace(TAG, e, "");
        } finally {
            closeQuietly(zos);
        }
    }

    //返回压缩后的 _shrink.hprof
    private String getShrinkHprofName(File origHprof) {
        final String origHprofName = origHprof.getName();
        final int extPos = origHprofName.indexOf(DumpStorageManager.HPROF_EXT);
        final String namePrefix = origHprofName.substring(0, extPos);
        return namePrefix + "_shrink" + DumpStorageManager.HPROF_EXT;
    }

    //返回zip todo 会不会重复
    private String getResultZipName(String prefix) {
        StringBuilder sb = new StringBuilder();
        sb.append(prefix).append('_')
                .append(new SimpleDateFormat("yyyyMMddHHmmss", Locale.ENGLISH).format(new Date()))
                .append(".zip");
        return sb.toString();
    }
}

12.CanaryResultService发现问题了,上报

public class CanaryResultService extends MatrixJobIntentService {
    private static final String TAG = "Matrix.CanaryResultService";

    private static final int JOB_ID = 0xFAFBFCFE;
    private static final String ACTION_REPORT_HPROF_RESULT = "com.tencent.matrix.resource.result.action.REPORT_HPROF_RESULT";
    private static final String EXTRA_PARAM_RESULT_PATH = "RESULT_PATH";
    private static final String EXTRA_PARAM_ACTIVITY = "RESULT_ACTIVITY";

    //入口
    public static void reportHprofResult(Context context, String resultPath, String activityName) {
        final Intent intent = new Intent(context, CanaryResultService.class);
        intent.setAction(ACTION_REPORT_HPROF_RESULT);
        intent.putExtra(EXTRA_PARAM_RESULT_PATH, resultPath);
        intent.putExtra(EXTRA_PARAM_ACTIVITY, activityName);
        enqueueWork(context, CanaryResultService.class, JOB_ID, intent);
    }

    @Override
    protected void onHandleWork(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_REPORT_HPROF_RESULT.equals(action)) {
                final String resultPath = intent.getStringExtra(EXTRA_PARAM_RESULT_PATH);
                final String activityName = intent.getStringExtra(EXTRA_PARAM_ACTIVITY);

                if (resultPath != null && !resultPath.isEmpty()
                    && activityName != null && !activityName.isEmpty()) {
                    //上报问题
                    doReportHprofResult(resultPath, activityName);
                } else {
                    MatrixLog.e(TAG, "resultPath or activityName is null or empty, skip reporting.");
                }
            }
        }
    }

    // notice: compatible
    //上报问题
    private void doReportHprofResult(String resultPath, String activityName) {
        Issue issue = new Issue(SharePluginInfo.IssueType.LEAK_FOUND);
        final JSONObject resultJson = new JSONObject();
        try {
            resultJson.put(SharePluginInfo.ISSUE_RESULT_PATH, resultPath);
            resultJson.put(SharePluginInfo.ISSUE_ACTIVITY_NAME, activityName);
            issue.setContent(resultJson);
        } catch (Throwable thr) {
            MatrixLog.printErrStackTrace(TAG, thr, "unexpected exception, skip reporting.");
        }

        Plugin plugin =  Matrix.with().getPluginByClass(ResourcePlugin.class);
        if (plugin != null) {
            plugin.onDetectIssue(issue);
        }
    }
}

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 11:36:36  更:2021-07-24 11:37:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 6:33:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码