17.优化 - matrix-battery-canary 分析1

  在matrix-battery-canary模块中,没有一条清晰的主线可以走到底,它的结构类似与一个个的小功能组装起来,小功能之间互不影响。它的一些功能的话有流量监控、Wifi监控、WakeLock监控、任务监控、定位监控、设备监控等等。

  分析的话就从给定的 Simple 开始分析。

  • 1.配置
    在 Simple 的 Application 中首先对 BatteryMonitorPlugin 配置了一些参数
    public static BatteryMonitorPlugin createMonitor() {
        if (sBatteryConfig != null) {
            throw new IllegalStateException("Duplicated init!");
        }

        sBatteryConfig = new BatteryMonitorConfig.Builder()
                // Thread Activities Monitor
                .enable(JiffiesMonitorFeature.class)  // Task 1
                .enableStatPidProc(true)
                .greyJiffiesTime(3 * 1000L)
                .enableBackgroundMode(false)
                .backgroundLoopCheckTime(30 * 60 * 1000L)
                .enableForegroundMode(true)
                .foregroundLoopCheckTime(20 * 60 * 1000L)
                .setBgThreadWatchingLimit(5000)
                .setBgThreadWatchingLimit(8000)

                // App & Device Status Monitor For Better Invalid Battery Activities Configure
                .setOverHeatCount(1024)
                .enable(DeviceStatMonitorFeature.class)  // Task 2
                .enable(AppStatMonitorFeature.class)  // Task 3
                .setSceneSupplier(new Callable<String>() {
                    @Override
                    public String call() {
                        return "Current AppScene";
                    }
                })

                // AMS Activities Monitor:
                // alarm/wakelock watch
                .enableAmsHook(true)  // Task 4
                .enable(AlarmMonitorFeature.class)  // Task 5
                .enable(WakeLockMonitorFeature.class)  // Task 6
                .wakelockTimeout(2 * 60 * 1000L)
                .wakelockWarnCount(3)
                .addWakeLockWhiteList("Ignore WakeLock TAG1")
                .addWakeLockWhiteList("Ignore WakeLock TAG2")
                // scanning watch (wifi/gps/bluetooth)
                .enable(WifiMonitorFeature.class)  // Task 7
                .enable(LocationMonitorFeature.class)  // Task 8
                .enable(BlueToothMonitorFeature.class)  // Task 9
                // .enable(NotificationMonitorFeature.class)  // Task 10

                // Lab Feature:
                // network monitor
                // looper task monitor
                .enable(TrafficMonitorFeature.class)  // Task 11
                .enable(LooperTaskMonitorFeature.class)  // Task 12
                .addLooperWatchList("main")
                .useThreadClock(false)
                .enableAggressive(true)

                // Monitor Callback
                .setCallback(new BatteryStatsListener())
                .build();

        return new BatteryMonitorPlugin(sBatteryConfig);
    }

matrix-battery-canary模块功能也主要是由注释中的 Task n 组成的。

  • 2.初始化和启动
        // 实例化 BatteryMonitorPlugin
       Plugin plugin = Matrix.with().getPluginByClass(BatteryMonitorPlugin.class);
       if (!plugin.isPluginStarted()) {
           if (!BatteryEventDelegate.isInit()) {
               BatteryEventDelegate.init(this.getApplication());
           }

           MatrixLog.i(TAG, "plugin-battery start");
           // 启动子任务开始监控
           plugin.start();
       }
public class BatteryMonitorPlugin extends Plugin {
    public BatteryMonitorPlugin(BatteryMonitorConfig config) {
        // 逻辑都在 BatteryMonitorCore 中,config 就是上面的配置
        mDelegate = new BatteryMonitorCore(config);
        MatrixLog.i(TAG, "setUp battery monitor plugin with configs: " + config);
    }
    @Override
    public void init(Application app, PluginListener listener) {
        super.init(app, listener);
        if (!mDelegate.getConfig().isBuiltinForegroundNotifyEnabled) {
            AppActiveMatrixDelegate.INSTANCE.removeListener(this);
        }
    }

    @Override
    public String getTag() {
        return "BatteryMonitorPlugin";
    }

    @Override
    public void start() {
        super.start();
        // 开始监控
        mDelegate.start();
    }

    @Override
    public void stop() {
        super.stop();
        // 开始监控
        mDelegate.stop();
    }
    @Override
    public void onForeground(boolean isForeground) {
        mDelegate.onForeground(isForeground);
    }

}
public class BatteryMonitorCore {

    private static final String TAG = "Matrix.battery.BatteryMonitorCore";

    private class BackgroundLoopCheckTask implements Runnable {
        int round = 0;
        @Override
        public void run() {
            round++;
            MatrixLog.i(TAG, "#onBackgroundLoopCheck, round = " + round);
            if (!isForeground()) {
                synchronized (BatteryMonitorCore.class) {
                    for (MonitorFeature plugin : mConfig.features) {
                        plugin.onBackgroundCheck(mBgLooperMillis * round);
                    }
                }
            }
            if (!isForeground()) {
                mHandler.postDelayed(this, mBgLooperMillis);
            }
        }
    }

    @SuppressLint("VisibleForTests")
    public BatteryMonitorCore(BatteryMonitorConfig config) {
        mConfig = config;
        // 给每一个小任务配置数据
        //  config.features 即上面配置的 Task1、Task2  也就是 JiffiesMonitorFeature、DeviceStatMonitorFeature 等
        for (MonitorFeature plugin : config.features) {
            plugin.configure(this);
        }
    }

    public void start() {
        synchronized (BatteryMonitorCore.class) {
            if (!mTurnOn) {
                //  config.features 即上面配置的 Task1、Task2  也就是 JiffiesMonitorFeature、DeviceStatMonitorFeature 等
                for (MonitorFeature plugin : mConfig.features) {
                    // 开始监控
                    plugin.onTurnOn();
                }
                mTurnOn = true;
            }
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mWorkerTid = Process.myTid();
                }
            });

            if (BatteryEventDelegate.isInit()) {
                // 通过广播来监听系统的 屏幕状态(息屏、亮屏),电池状态(充电、不充电),发生状态更改时会通知观察者们
                BatteryEventDelegate.getInstance().attach(this).startListening();
            }
        }
    }

    public void stop() {
        synchronized (BatteryMonitorCore.class) {
            if (mTurnOn) {
                mHandler.removeCallbacksAndMessages(null);
                for (MonitorFeature plugin : mConfig.features) {
                    // 开始监控
                    plugin.onTurnOff();
                }
                mTurnOn = false;
            }
        }
    }

    @WorkerThread
    @Nullable
    public TaskJiffiesSnapshot configureMonitorConsuming() {
        if (Looper.myLooper() == Looper.getMainLooper() || Looper.myLooper() == mHandler.getLooper()) {
            throw new IllegalStateException("'#configureMonitorConsuming' should work within worker thread except matrix thread!");
        }

        if (mWorkerTid > 0) {
            MatrixLog.i(TAG, "#configureMonitorConsuming, tid = " + mWorkerTid);
            TaskJiffiesSnapshot snapshot = createSnapshot(mWorkerTid);  // app phone 是否在前后台   mWorkerTid 的信息(运行时间等 /proc/pid/task/tid/... )
            if (snapshot != null) {
                if (mLastInternalSnapshot != null) {
                    Delta<TaskJiffiesSnapshot> delta = snapshot.diff(mLastInternalSnapshot);
                    getConfig().callback.onReportInternalJiffies(delta);  //比较二次 snapshot 的信息,是不是在充电,前后台等信息
                }
                mLastInternalSnapshot = snapshot;
                return snapshot;
            }
        }
        return null;
    }

    public void onForeground(boolean isForeground) {
        if (!Matrix.isInstalled()) {
            MatrixLog.e(TAG, "Matrix was not installed yet, just ignore the event");
            return;
        }
        mAppForeground = isForeground;

        if (BatteryEventDelegate.isInit()) {
            BatteryEventDelegate.getInstance().onForeground(isForeground);
        }
      
        if (!isForeground) { // app 运行在后台
            // back:
            // 1. remove all checks
            mHandler.removeCallbacksAndMessages(null);

            // 2. start background jiffies check
            Message message = Message.obtain(mHandler);
            message.what = MSG_ID_JIFFIES_START;
            mHandler.sendMessageDelayed(message, mMonitorDelayMillis);

            // 3. start background loop check task
            if (mBackgroundModeEnabled) {
                if (mBgLooperTask != null) {
                    mHandler.removeCallbacks(mBgLooperTask);
                    mBgLooperTask = null;
                }
                mBgLooperTask = new BackgroundLoopCheckTask();
                // mBgLooperTask 某些 task 需要 app 在后台是也监控其数据如 AppStatMonitorFeature 、WakeLockMonitorFeature
                mHandler.postDelayed(mBgLooperTask, mBgLooperMillis);
            }

        } else if (!mHandler.hasMessages(MSG_ID_JIFFIES_START)) { // message.what = MSG_ID_JIFFIES_END 时进入,即下方的 message 没有执行完时。
            // fore:
            // 1. remove background loop task
            if (mBgLooperTask != null) {
                mHandler.removeCallbacks(mBgLooperTask);
                mBgLooperTask = null;
            }

            // 2. finish background jiffies check
            Message message = Message.obtain(mHandler);
            message.what = MSG_ID_JIFFIES_END;
            mHandler.sendMessageAtFrontOfQueue(message);

            // 3. start foreground jiffies loop check
            if (mForegroundModeEnabled && mFgLooperTask != null) {
                mHandler.removeCallbacks(mFgLooperTask);
                mFgLooperTask.lastWhat = MSG_ID_JIFFIES_START;
                mHandler.post(mFgLooperTask);
            }
        }

        for (MonitorFeature plugin : mConfig.features) {
            plugin.onForeground(isForeground);
        }
    }
    // 获取电池温度
    public int getCurrentBatteryTemperature(Context context) {
        try {
            return BatteryCanaryUtil.getBatteryTemperature(context);  //电池温度
        } catch (Throwable e) {
            MatrixLog.printErrStackTrace(TAG, e, "#currentBatteryTemperature error");
            return 0;
        }
    }


    @Nullable
    // 获取手机的设备信息
    protected TaskJiffiesSnapshot createSnapshot(int tid) {
        TaskJiffiesSnapshot snapshot = new TaskJiffiesSnapshot();
        snapshot.tid = tid;
        snapshot.appStat = BatteryCanaryUtil.getAppStat(getContext(), isForeground());  // 设备是否在前台 后台服务 后台
        snapshot.devStat = BatteryCanaryUtil.getDeviceStat(getContext());  // 设备是否在 充电 熄屏 省电模式
        try {
            Callable<String> supplier = getConfig().onSceneSupplier;
            snapshot.scene = supplier == null ? "" : supplier.call();
        } catch (Exception ignored) {
            snapshot.scene = "";
        }
         // app 进程即线程状态,通过读 /proc/pid/stat 和  /proc/pid/task/tid/stat 文件里面的信息,
         // 主要是得到 app 运行的进程、线程名,app 运行时和 app 内线程的用户时间、系统时间、等待的系统时间和用户时间
        ProcStatUtil.ProcStat stat = ProcStatUtil.of(Process.myPid(), tid); 
        if (stat == null) {
            return null;
        }
        snapshot.jiffies = DigitEntry.of(stat.getJiffies());
        snapshot.name = stat.comm;
        return snapshot;
    }
}

  • 小知识点:
  1. /proc/pid/stat :pid 进程的信息
  2. /proc/pid/task/ :pid 进程中所有的 tid 线程 id
  3. /proc/pid/task/tid/stat :pid 进程的 tid 线程的信息
  4. /proc/pid/maps:pid 进程的 mmap 信息
  5. ...
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容