在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;
}
}
- 小知识点:
-
/proc/pid/stat
:pid 进程的信息 -
/proc/pid/task/
:pid 进程中所有的 tid 线程 id -
/proc/pid/task/tid/stat
:pid 进程的 tid 线程的信息 -
/proc/pid/maps
:pid 进程的 mmap 信息 - ...