From c7a4a3b173925c58132717dc985c9a0c72b7883a Mon Sep 17 00:00:00 2001 From: kaedexie Date: Sat, 7 May 2022 17:52:42 +0800 Subject: [PATCH 001/263] Add appStat debug code --- .../monitor/feature/AppStatMonitorFeature.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java index e986b345e..0cb0d88a3 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java @@ -75,8 +75,11 @@ public void run() { @Override public void on() { MatrixLog.i(TAG, "floatView >> on"); - int appStat = BatteryCanaryUtil.getAppStatImmediately(mCore.getContext(), mCore.isForeground()); + boolean foreground = mCore.isForeground(); + int appStat = BatteryCanaryUtil.getAppStatImmediately(mCore.getContext(), foreground); + MatrixLog.i(TAG, "fg = " + foreground + ", currAppStat = " + appStat); if (appStat != APP_STAT_FOREGROUND && appStat != APP_STAT_FOREGROUND_SERVICE) { + MatrixLog.i(TAG, "statAppStat: " + APP_STAT_FLOAT_WINDOW); onStatAppStat(APP_STAT_FLOAT_WINDOW); } } @@ -84,8 +87,11 @@ public void on() { @Override public void off() { MatrixLog.i(TAG, "floatView >> off"); - int appStat = BatteryCanaryUtil.getAppStatImmediately(mCore.getContext(), mCore.isForeground()); + boolean foreground = mCore.isForeground(); + int appStat = BatteryCanaryUtil.getAppStatImmediately(mCore.getContext(), foreground); + MatrixLog.i(TAG, "fg = " + foreground + ", currAppStat = " + appStat); if (appStat != APP_STAT_FOREGROUND && appStat != APP_STAT_FOREGROUND_SERVICE) { + MatrixLog.i(TAG, "statAppStat: " + APP_STAT_BACKGROUND); onStatAppStat(APP_STAT_BACKGROUND); } } From d13fbb92c5c9bef87a709e3566da4198a3844cfc Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 11 May 2022 11:43:40 +0800 Subject: [PATCH 002/263] protect null aty --- .../src/main/cpp/my_functions.h | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h index 04f2d7492..d7122bf47 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h @@ -287,7 +287,11 @@ GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { EGLSurface egl_read_surface = eglGetCurrentSurface(EGL_READ); char* activity_info = static_cast(malloc(BUF_SIZE)); - strcpy(activity_info, curr_activity_info); + if (curr_activity_info != nullptr) { + strcpy(activity_info, curr_activity_info); + } else { + strcpy(activity_info, "null"); + } messages_containers-> enqueue_message((uintptr_t) egl_context, @@ -350,8 +354,11 @@ GL_APICALL void GL_APIENTRY my_glGenBuffers(GLsizei n, GLuint *buffers) { EGLSurface egl_read_surface = eglGetCurrentSurface(EGL_READ); char* activity_info = static_cast(malloc(BUF_SIZE)); - strcpy(activity_info, curr_activity_info); - + if (curr_activity_info != nullptr) { + strcpy(activity_info, curr_activity_info); + } else { + strcpy(activity_info, "null"); + } messages_containers ->enqueue_message((uintptr_t) egl_context, [n, copy_buffers, throwable, thread_id, backtracePrt, egl_context, egl_draw_surface, egl_read_surface, activity_info]() { @@ -413,7 +420,11 @@ GL_APICALL void GL_APIENTRY my_glGenFramebuffers(GLsizei n, GLuint *buffers) { EGLSurface egl_read_surface = eglGetCurrentSurface(EGL_READ); char* activity_info = static_cast(malloc(BUF_SIZE)); - strcpy(activity_info, curr_activity_info); + if (curr_activity_info != nullptr) { + strcpy(activity_info, curr_activity_info); + } else { + strcpy(activity_info, "null"); + } messages_containers ->enqueue_message((uintptr_t) egl_context, @@ -476,7 +487,11 @@ GL_APICALL void GL_APIENTRY my_glGenRenderbuffers(GLsizei n, GLuint *buffers) { EGLSurface egl_read_surface = eglGetCurrentSurface(EGL_READ); char* activity_info = static_cast(malloc(BUF_SIZE)); - strcpy(activity_info, curr_activity_info); + if (curr_activity_info != nullptr) { + strcpy(activity_info, curr_activity_info); + } else { + strcpy(activity_info, "null"); + } messages_containers ->enqueue_message((uintptr_t) egl_context, From 0b72e2e1ede912abf05c111ba849792f931bd410 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 11 May 2022 16:11:50 +0800 Subject: [PATCH 003/263] lifecycle: add lifecycle logger --- .../matrix/lifecycle/MatrixLifecycleLogger.kt | 102 ++++++++++++++++++ .../MatrixLifecycleOwnerInitializer.kt | 5 +- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/MatrixLifecycleLogger.kt diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/MatrixLifecycleLogger.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/MatrixLifecycleLogger.kt new file mode 100644 index 000000000..40b2d85ce --- /dev/null +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/MatrixLifecycleLogger.kt @@ -0,0 +1,102 @@ +package com.tencent.matrix.lifecycle + +import android.app.Application +import com.tencent.matrix.lifecycle.owners.* +import com.tencent.matrix.lifecycle.supervisor.* +import com.tencent.matrix.util.MatrixLog +import com.tencent.matrix.util.MatrixUtil + +// @formatter:off +object MatrixLifecycleLogger { + + private var application: Application? = null + private val TAG by lazy { "Matrix.lifecycle.Logger_${String.format("%-10.10s", suffix())}" } + + private fun suffix(): String { + return if (MatrixUtil.isInMainProcess(application!!)) { + "Main" + } else { + val split = MatrixUtil.getProcessName(application!!).split(":").toTypedArray() + if (split.size > 1) { + split[1].takeLast(10) + } else { + "unknown" + } + } + } + + fun init(app: Application, enable: Boolean) { + application = app + if (!enable) { + MatrixLog.i(TAG, "logger disabled") + return + } + + ProcessUIResumedStateOwner.observeForever(object : ISerialObserver { + override fun on() = MatrixLog.i(TAG, "ON_PROCESS_UI_RESUMED") + override fun off() = MatrixLog.i(TAG, "ON_PROCESS_UI_PAUSED") + }) + + ProcessUIStartedStateOwner.observeForever(object : ISerialObserver { + override fun on() = MatrixLog.i(TAG, "ON_PROCESS_UI_STARTED scene: ${ProcessUILifecycleOwner.recentScene}") + override fun off() = MatrixLog.i(TAG, "ON_PROCESS_UI_STOPPED scene: ${ProcessUILifecycleOwner.recentScene}") + }) + + ProcessExplicitBackgroundOwner.observeForever(object : ISerialObserver { + override fun on() = MatrixLog.i(TAG, "ON_PROCESS_ENTER_EXPLICIT_BACKGROUND") + override fun off() = MatrixLog.i(TAG, "ON_PROCESS_EXIT_EXPLICIT_BACKGROUND") + }) + + ProcessStagedBackgroundOwner.observeForever(object : ISerialObserver { + override fun on() = MatrixLog.i(TAG, "ON_PROCESS_ENTER_STAGED_BACKGROUND") + override fun off() = MatrixLog.i(TAG, "ON_PROCESS_EXIT_STAGED_BACKGROUND") + }) + + ProcessDeepBackgroundOwner.observeForever(object : ISerialObserver { + override fun on() = MatrixLog.i(TAG, "ON_PROCESS_ENTER_DEEP_BACKGROUND") + override fun off() = MatrixLog.i(TAG, "ON_PROCESS_EXIT_DEEP_BACKGROUND") + }) + + AppUIForegroundOwner.observeForever(object : ISerialObserver { + override fun on() = MatrixLog.i(TAG, "ON_APP_UI_ENTER_FOREGROUND scene: ${ProcessSupervisor.getRecentScene()}") + override fun off() = MatrixLog.i(TAG, "ON_APP_UI_EXIT_FOREGROUND scene: ${ProcessSupervisor.getRecentScene()}") + }) + + AppExplicitBackgroundOwner.observeForever(object : ISerialObserver { + override fun off() = MatrixLog.i(TAG, "ON_APP_EXIT_EXPLICIT_BACKGROUND") + override fun on() = MatrixLog.i(TAG, "ON_APP_ENTER_EXPLICIT_BACKGROUND") + }) + + AppStagedBackgroundOwner.observeForever(object : ISerialObserver { + override fun off() = MatrixLog.i(TAG, "ON_APP_EXIT_STAGED_BACKGROUND") + override fun on() = MatrixLog.i(TAG, "ON_APP_ENTER_STAGED_BACKGROUND") + }) + + AppDeepBackgroundOwner.observeForever(object : ISerialObserver { + override fun off() = MatrixLog.i(TAG, "ON_APP_EXIT_DEEP_BACKGROUND") + override fun on() = MatrixLog.i(TAG, "ON_APP_ENTER_DEEP_BACKGROUND") + }) + + ProcessSupervisor.addDyingListener { scene, processName, pid -> + MatrixLog.i(TAG, "Dying Listener: process $pid-$processName is dying on scene $scene") + false // NOT rescue + } + + ProcessSupervisor.addDeathListener { scene, processName, pid, isLruKill -> + MatrixLog.i( + TAG, + "Death Listener: process $pid-$processName died on scene $scene, is LRU Kill? $isLruKill" + ) + } + + ForegroundServiceLifecycleOwner.observeForever(object : ISerialObserver { + override fun on() = MatrixLog.i(TAG, "ForegroundServiceLifecycleOwner: ON") + override fun off() = MatrixLog.i(TAG, "ForegroundServiceLifecycleOwner: OFF") + }) + + OverlayWindowLifecycleOwner.observeForever(object : ISerialObserver { + override fun on() = MatrixLog.i(TAG, "OverlayWindowLifecycleOwner: ON, hasOverlay = ${OverlayWindowLifecycleOwner.hasOverlayWindow()}, hasVisible = ${OverlayWindowLifecycleOwner.hasVisibleWindow()}") + override fun off() = MatrixLog.i(TAG, "OverlayWindowLifecycleOwner: OFF, hasOverlay = ${OverlayWindowLifecycleOwner.hasOverlayWindow()}, hasVisible = ${OverlayWindowLifecycleOwner.hasVisibleWindow()}") + }) + } +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/MatrixLifecycleOwnerInitializer.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/MatrixLifecycleOwnerInitializer.kt index 09e520a67..e65de774c 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/MatrixLifecycleOwnerInitializer.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/MatrixLifecycleOwnerInitializer.kt @@ -25,7 +25,9 @@ data class MatrixLifecycleConfig( */ val enableOverlayWindowMonitor: Boolean = false, - val lifecycleThreadConfig: LifecycleThreadConfig = LifecycleThreadConfig() + val lifecycleThreadConfig: LifecycleThreadConfig = LifecycleThreadConfig(), + + val enableLifecycleLogger: Boolean = false ) /** @@ -61,6 +63,7 @@ class MatrixLifecycleOwnerInitializer { ProcessUILifecycleOwner.init(app) ForegroundServiceLifecycleOwner.init(app, config.enableFgServiceMonitor) OverlayWindowLifecycleOwner.init(config.enableOverlayWindowMonitor) + MatrixLifecycleLogger.init(app, config.enableLifecycleLogger) } @SuppressLint("PrivateApi", "DiscouragedPrivateApi") From f052b6b1bbe29587133960a6025e2dcd374b763e Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 11 May 2022 16:12:19 +0800 Subject: [PATCH 004/263] lifecycle: fix explicit bg state --- .../matrix/lifecycle/owners/ProcessBackgroundStateOwner.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/owners/ProcessBackgroundStateOwner.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/owners/ProcessBackgroundStateOwner.kt index c21c21330..dd36e4dbd 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/owners/ProcessBackgroundStateOwner.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/owners/ProcessBackgroundStateOwner.kt @@ -68,7 +68,7 @@ object ProcessExplicitBackgroundOwner : StatefulOwner(), IBackgroundStatefulOwne override fun action(): Boolean { val uiForeground by lazy { ProcessUIStartedStateOwner.active() } val fgService by lazy { ForegroundServiceLifecycleOwner.hasForegroundService() } - val visibleWindow by lazy { OverlayWindowLifecycleOwner.hasVisibleWindow() } + val visibleWindow by lazy { OverlayWindowLifecycleOwner.hasOverlayWindow() } if (uiForeground) { MatrixLog.i(TAG, "turn OFF for UI foreground") From c181484a9667132c76265c55df02bcbbdf13136a Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 11 May 2022 20:34:54 +0800 Subject: [PATCH 005/263] memory-canary: trigger gc after trim memory --- .../com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt index 9e3a36960..a76debe08 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt @@ -45,6 +45,7 @@ object TrimMemoryNotifier { } } } + Runtime.getRuntime().gc() } private fun ArrayList.systemTrim(level: Int) { @@ -55,6 +56,7 @@ object TrimMemoryNotifier { } } } + Runtime.getRuntime().gc() } fun init(config: TrimMemoryConfig) { From 91870d5dc1ad3c5eaa28e8db1ac3b3011d135c67 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 12 May 2022 13:07:30 +0800 Subject: [PATCH 006/263] Update compositor with metric & sampling impl --- .../monitor/feature/SamplerTest.java | 4 +-- .../monitor/feature/CompositeMonitors.java | 26 +++++++------------ .../monitor/feature/MonitorFeature.java | 9 ++++++- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java index dd6ffd77d..0277bc189 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java @@ -95,7 +95,7 @@ public void testSampling() throws InterruptedException { final int samplingCount = 10; final AtomicInteger counter = new AtomicInteger(0); - final MonitorFeature.Snapshot.Sampler sampler = new MonitorFeature.Snapshot.Sampler(monitor.getHandler(), new Callable() { + final MonitorFeature.Snapshot.Sampler sampler = new MonitorFeature.Snapshot.Sampler("test-1", monitor.getHandler(), new Callable() { @Override public Integer call() throws InterruptedException { int count = counter.incrementAndGet(); @@ -128,7 +128,7 @@ public Integer call() throws InterruptedException { Assert.assertEquals(55d / samplingCount, result.sampleAvg, 0.1); final AtomicInteger counterDec = new AtomicInteger(0); - final MonitorFeature.Snapshot.Sampler samplerDec = new MonitorFeature.Snapshot.Sampler(monitor.getHandler(), new Callable() { + final MonitorFeature.Snapshot.Sampler samplerDec = new MonitorFeature.Snapshot.Sampler("test-2", monitor.getHandler(), new Callable() { @Override public Integer call() throws InterruptedException { int count = counterDec.incrementAndGet(); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 2bcf1a699..986b76a08 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -295,7 +295,10 @@ public void finish() { protected void configureBgnSnapshots() { for (Class> item : mMetrics) { - statCurrSnapshot(item); + Snapshot currSnapshot = statCurrSnapshot(item); + if (currSnapshot != null) { + mBgnSnapshots.put(item, currSnapshot); + } } } @@ -352,7 +355,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas AlarmMonitorFeature feature = getFeature(AlarmMonitorFeature.class); if (feature != null) { snapshot = feature.currentAlarms(); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -360,7 +362,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas BlueToothMonitorFeature feature = getFeature(BlueToothMonitorFeature.class); if (feature != null) { snapshot = feature.currentSnapshot(); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -368,7 +369,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null) { snapshot = feature.currentCpuFreq(); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -376,7 +376,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { snapshot = feature.currentBatteryTemperature(mMonitor.getContext()); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -384,7 +383,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas JiffiesMonitorFeature feature = getFeature(JiffiesMonitorFeature.class); if (feature != null) { snapshot = feature.currentJiffiesSnapshot(); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -392,7 +390,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas LocationMonitorFeature feature = getFeature(LocationMonitorFeature.class); if (feature != null) { snapshot = feature.currentSnapshot(); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -400,7 +397,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas TrafficMonitorFeature feature = getFeature(TrafficMonitorFeature.class); if (feature != null && mMonitor != null) { snapshot = feature.currentRadioSnapshot(mMonitor.getContext()); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -408,7 +404,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas WakeLockMonitorFeature feature = getFeature(WakeLockMonitorFeature.class); if (feature != null) { snapshot = feature.currentWakeLocks(); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -416,7 +411,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas WifiMonitorFeature feature = getFeature(WifiMonitorFeature.class); if (feature != null) { snapshot = feature.currentSnapshot(); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -424,7 +418,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas CpuStatFeature feature = getFeature(CpuStatFeature.class); if (feature != null && feature.isSupported()) { snapshot = feature.currentCpuStateSnapshot(); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -432,7 +425,6 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas AppStatMonitorFeature feature = getFeature(AppStatMonitorFeature.class); if (feature != null) { snapshot = feature.currentAppStatSnapshot(); - mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } @@ -465,7 +457,7 @@ protected Snapshot.Sampler statSampler(Class> snapshotClas if (snapshotClass == DeviceStatMonitorFeature.CpuFreqSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler(mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("cpufreq", mMonitor.getHandler(), new Callable() { @Override public Number call() { DeviceStatMonitorFeature.CpuFreqSnapshot snapshot = feature.currentCpuFreq(); @@ -486,7 +478,7 @@ public int compare(DigitEntry o1, DigitEntry o2) { if (snapshotClass == DeviceStatMonitorFeature.BatteryTmpSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler(mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("batt-temp", mMonitor.getHandler(), new Callable() { @Override public Number call() { DeviceStatMonitorFeature.BatteryTmpSnapshot snapshot = feature.currentBatteryTemperature(mMonitor.getContext()); @@ -500,7 +492,7 @@ public Number call() { if (snapshotClass == DeviceStatMonitorFeature.ThermalStatSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler(mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("thermal-stat", mMonitor.getHandler(), new Callable() { @Override public Number call() { return BatteryCanaryUtil.getThermalStat(mMonitor.getContext()); @@ -515,7 +507,7 @@ public Number call() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && feature != null && mMonitor != null) { final Long interval = mSampleRegs.get(snapshotClass); if (interval != null && interval >= 1000L) { - sampler = new Snapshot.Sampler(mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("thermal-headroom", mMonitor.getHandler(), new Callable() { @Override public Number call() { return BatteryCanaryUtil.getThermalHeadroom(mMonitor.getContext(), (int) (interval / 1000L)); @@ -529,7 +521,7 @@ public Number call() { if (snapshotClass == DeviceStatMonitorFeature.ChargeWattageSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler(mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("batt-temp", mMonitor.getHandler(), new Callable() { @Override public Number call() { return BatteryCanaryUtil.getChargingWatt(mMonitor.getContext()); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index 5a5cf93ff..821a5733f 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -421,6 +421,7 @@ public static class Sampler { private static final String TAG = "Matrix.battery.Sampler"; public static final Number INVALID = Integer.MIN_VALUE; + final String mTag; final Handler mHandler; final Callable mSamplingBlock; @@ -428,6 +429,7 @@ public static class Sampler { @Override public void run() { try { + MatrixLog.i(TAG, "onSampling, count = " + mCount); Number currSample = mSamplingBlock.call(); if (currSample != INVALID) { mSampleLst = currSample.doubleValue(); @@ -467,7 +469,12 @@ public void run() { double mSampleMin = Double.MIN_VALUE; double mSampleAvg = Double.MIN_VALUE; - public Sampler(Handler handler, Callable onSampling) { + public Sampler( Handler handler, Callable onSampling) { + this("default", handler, onSampling); + } + + public Sampler(String tag, Handler handler, Callable onSampling) { + mTag = tag; mHandler = handler; mSamplingBlock = onSampling; } From 798acb33121048d93bbefbc4a38af56b2217350c Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 12 May 2022 13:10:07 +0800 Subject: [PATCH 007/263] Update appStat debug code --- .../monitor/feature/AppStatMonitorFeature.java | 6 ++++-- .../batterycanary/monitor/feature/MonitorFeature.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java index 0cb0d88a3..29f633e0e 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java @@ -77,10 +77,11 @@ public void on() { MatrixLog.i(TAG, "floatView >> on"); boolean foreground = mCore.isForeground(); int appStat = BatteryCanaryUtil.getAppStatImmediately(mCore.getContext(), foreground); - MatrixLog.i(TAG, "fg = " + foreground + ", currAppStat = " + appStat); if (appStat != APP_STAT_FOREGROUND && appStat != APP_STAT_FOREGROUND_SERVICE) { MatrixLog.i(TAG, "statAppStat: " + APP_STAT_FLOAT_WINDOW); onStatAppStat(APP_STAT_FLOAT_WINDOW); + } else { + MatrixLog.i(TAG, "skip statAppStat, fg = " + foreground + ", currAppStat = " + appStat); } } @@ -89,10 +90,11 @@ public void off() { MatrixLog.i(TAG, "floatView >> off"); boolean foreground = mCore.isForeground(); int appStat = BatteryCanaryUtil.getAppStatImmediately(mCore.getContext(), foreground); - MatrixLog.i(TAG, "fg = " + foreground + ", currAppStat = " + appStat); if (appStat != APP_STAT_FOREGROUND && appStat != APP_STAT_FOREGROUND_SERVICE) { MatrixLog.i(TAG, "statAppStat: " + APP_STAT_BACKGROUND); onStatAppStat(APP_STAT_BACKGROUND); + } else { + MatrixLog.i(TAG, "skip statAppStat, fg = " + foreground + ", currAppStat = " + appStat); } } }; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index 821a5733f..c145e19e9 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -469,7 +469,7 @@ public void run() { double mSampleMin = Double.MIN_VALUE; double mSampleAvg = Double.MIN_VALUE; - public Sampler( Handler handler, Callable onSampling) { + public Sampler(Handler handler, Callable onSampling) { this("default", handler, onSampling); } From 271064d1dc4a0bb00fbaf65e06fdca349c2acf35 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 12 May 2022 18:08:58 +0800 Subject: [PATCH 008/263] memory-canary: fix trim memory bug(might cancel task of other module) and add multiple delay time config --- .../memory/canary/trim/TrimMemoryNotifier.kt | 133 ++++++++++-------- 1 file changed, 74 insertions(+), 59 deletions(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt index a76debe08..ec2957387 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt @@ -2,12 +2,14 @@ package com.tencent.matrix.memory.canary.trim import android.content.ComponentCallbacks2 import android.content.res.Configuration +import android.os.Handler import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.OnLifecycleEvent import com.tencent.matrix.Matrix -import com.tencent.matrix.lifecycle.IStateObserver +import com.tencent.matrix.lifecycle.IBackgroundStatefulOwner +import com.tencent.matrix.lifecycle.IMatrixBackgroundCallback import com.tencent.matrix.lifecycle.owners.ProcessDeepBackgroundOwner import com.tencent.matrix.lifecycle.owners.ProcessStagedBackgroundOwner import com.tencent.matrix.lifecycle.supervisor.AppDeepBackgroundOwner @@ -24,7 +26,7 @@ interface TrimCallback { data class TrimMemoryConfig( val enable: Boolean = false, - val delayMillis: Long = TimeUnit.MINUTES.toMillis(1) + val delayMillis: ArrayList = arrayListOf(TimeUnit.MINUTES.toMillis(1)) ) /** @@ -59,17 +61,76 @@ object TrimMemoryNotifier { Runtime.getRuntime().gc() } + class TrimTask( + private val name: String, + private val backgroundOwner: IBackgroundStatefulOwner, + private val trimCallback: ArrayList, + private val config: TrimMemoryConfig, + private val immediate: Boolean + ) : Runnable { + + private val runningHandler = + Handler(MatrixHandlerThread.getDefaultHandlerThread().looper) + + @Volatile + private var delayIndex = 0 + + fun init() { + backgroundOwner.addLifecycleCallback(object : IMatrixBackgroundCallback() { + override fun onEnterBackground() { + val delay = config.delayMillis[delayIndex] + runningHandler.removeCallbacksAndMessages(null) + if (immediate) { + trimCallback.backgroundTrim() + MatrixLog.i(TAG, "[$name] trim immediately") + } + runningHandler.postDelayed(this@TrimTask, delay) + MatrixLog.i( + TAG, + "[$name] trim delay[$delayIndex/${config.delayMillis.size}] $delay" + ) + } + + override fun onExitBackground() { + runningHandler.removeCallbacks(this@TrimTask) + delayIndex = 0 + } + }) + } + + override fun run() { + MatrixLog.i( + TAG, + "[$name] trim timeout [$delayIndex/${config.delayMillis.size}] ${config.delayMillis[delayIndex]}" + ) + delayIndex++ + trimCallback.backgroundTrim() + if (delayIndex < config.delayMillis.size) { + val delay = config.delayMillis[delayIndex] + runningHandler.postDelayed(this, delay) + MatrixLog.i( + TAG, + "[$name] trim delay[$delayIndex/${config.delayMillis.size}] $delay" + ) + } + } + } + fun init(config: TrimMemoryConfig) { if (!config.enable) { return } + if (config.delayMillis.isEmpty()) { + throw IllegalArgumentException("config.delayMillis is empty") + } + if (!Matrix.isInstalled()) { MatrixLog.e(TAG, "Matrix NOT installed yet") return } - + // system trim Matrix.with().application.registerComponentCallbacks(object : ComponentCallbacks2 { override fun onLowMemory() { MatrixLog.e(TAG, "onLowMemory post") @@ -94,65 +155,19 @@ object TrimMemoryNotifier { override fun onConfigurationChanged(newConfig: Configuration) {} }) + // @formatter:off + // process staged bg trim + TrimTask("ProcessStagedBg", ProcessStagedBackgroundOwner, procTrimCallbacks, config, false).init() - val procTrimTask = Runnable { - MatrixLog.i(TAG, "trim: process staged bg timeout ${config.delayMillis}") - procTrimCallbacks.backgroundTrim() - } + // process deep bg trim + TrimTask("ProcessDeepBg", ProcessDeepBackgroundOwner, procTrimCallbacks, config, true).init() - object : IStateObserver { - val runningHandler = MatrixHandlerThread.getDefaultHandler() + // app staged bg trim + TrimTask("AppStagedBg", AppStagedBackgroundOwner, appTrimCallbacks, config, false).init() - override fun on() { - runningHandler.removeCallbacksAndMessages(null) - runningHandler.postDelayed(procTrimTask, config.delayMillis) - } - - override fun off() { - runningHandler.removeCallbacks(procTrimTask) - } - }.let { - ProcessStagedBackgroundOwner.observeForever(it) - } - - ProcessDeepBackgroundOwner.observeForever(object : IStateObserver { - override fun on() { - MatrixLog.i(TAG, "trim: process deep bg") - procTrimCallbacks.backgroundTrim() - } - - override fun off() {} - }) - - - val appTrimTask = Runnable { - MatrixLog.i(TAG, "trim: app staged bg timeout ${config.delayMillis}") - appTrimCallbacks.backgroundTrim() - } - - object : IStateObserver { - val runningHandler = MatrixHandlerThread.getDefaultHandler() - - override fun on() { - runningHandler.removeCallbacksAndMessages(null) - runningHandler.postDelayed(appTrimTask, config.delayMillis) - } - - override fun off() { - runningHandler.removeCallbacks(appTrimTask) - } - }.let { - AppStagedBackgroundOwner.observeForever(it) - } - - AppDeepBackgroundOwner.observeForever(object : IStateObserver { - override fun on() { - MatrixLog.i(TAG, "trim: app deep bg") - appTrimCallbacks.backgroundTrim() - } - - override fun off() {} - }) + // app deep bg trim + TrimTask("AppDeepBg", AppDeepBackgroundOwner, appTrimCallbacks, config, true).init() + // @formatter:on } fun addProcessBackgroundTrimCallback(callback: TrimCallback) { From 44b96f10d0831d1106071c21470b88827af7ff9f Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 13 May 2022 10:52:41 +0800 Subject: [PATCH 009/263] opengl-leak:realese unuse test_context --- .../main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp index ab5d3e160..042551161 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp @@ -560,10 +560,11 @@ Java_com_tencent_matrix_openglleak_hook_OpenGLHook_isEglContextAlive( EGL_NONE }; auto origin_context = (EGLContext) egl_context; - eglCreateContext(display, eglConfig, origin_context, attrib_ctx_list); + EGLContext test_context = eglCreateContext(display, eglConfig, origin_context, attrib_ctx_list); if (eglGetError() == EGL_BAD_CONTEXT) { return false; } + eglDestroyContext(display, test_context); return true; } From 96c52bfa124a2263af8a7c7872edc27267186032 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 13 May 2022 13:27:38 +0800 Subject: [PATCH 010/263] memory-canary: fix trim memory out of index crash --- .../com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt index ec2957387..f2b9265e3 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt @@ -78,6 +78,7 @@ object TrimMemoryNotifier { fun init() { backgroundOwner.addLifecycleCallback(object : IMatrixBackgroundCallback() { override fun onEnterBackground() { + delayIndex = 0 val delay = config.delayMillis[delayIndex] runningHandler.removeCallbacksAndMessages(null) if (immediate) { From d7f5297359582f23194e01c5740175aa838cd822 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 13 May 2022 13:46:43 +0800 Subject: [PATCH 011/263] memory-canary: fix trim memory log --- .../tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt index f2b9265e3..0d6fdd6fe 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt @@ -88,7 +88,7 @@ object TrimMemoryNotifier { runningHandler.postDelayed(this@TrimTask, delay) MatrixLog.i( TAG, - "[$name] trim delay[$delayIndex/${config.delayMillis.size}] $delay" + "[$name] trim delay[${delayIndex+1}/${config.delayMillis.size}] $delay" ) } @@ -102,7 +102,7 @@ object TrimMemoryNotifier { override fun run() { MatrixLog.i( TAG, - "[$name] trim timeout [$delayIndex/${config.delayMillis.size}] ${config.delayMillis[delayIndex]}" + "[$name] trim timeout [${delayIndex+1}/${config.delayMillis.size}] ${config.delayMillis[delayIndex]}" ) delayIndex++ trimCallback.backgroundTrim() @@ -111,7 +111,7 @@ object TrimMemoryNotifier { runningHandler.postDelayed(this, delay) MatrixLog.i( TAG, - "[$name] trim delay[$delayIndex/${config.delayMillis.size}] $delay" + "[$name] trim delay[${delayIndex+1}/${config.delayMillis.size}] $delay" ) } } From 55f5e53430472b0b39584e2eb2c25a4055960cb8 Mon Sep 17 00:00:00 2001 From: leafjia Date: Sun, 15 May 2022 23:41:26 +0800 Subject: [PATCH 012/263] Matrix Traffic Remake --- .../src/main/cpp/MatrixTraffic.cc | 103 ++++++--- .../src/main/cpp/MatrixTraffic.h | 4 +- .../src/main/cpp/TrafficCollector.cc | 200 ++++++++++++------ .../src/main/cpp/TrafficCollector.h | 15 +- .../tencent/matrix/traffic/TrafficConfig.java | 33 +-- .../tencent/matrix/traffic/TrafficPlugin.java | 70 ++++-- 6 files changed, 293 insertions(+), 132 deletions(-) diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc index 694dca159..01e9f0577 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -28,9 +28,11 @@ #include #include +#include #include #include #include +#include #include "BacktraceDefine.h" #include "Backtrace.h" @@ -44,9 +46,14 @@ using namespace MatrixTraffic; static bool HOOKED = false; static bool sDumpNativeBackTrace = false; +static map> backtraceMap; +static shared_mutex backtraceMapLock; + static struct StacktraceJNI { jclass TrafficPlugin; jmethodID TrafficPlugin_setFdStackTrace; + jmethodID TrafficPlugin_clearFdInfo; + jmethodID TrafficPlugin_printLog; } gJ; @@ -95,13 +102,10 @@ void makeNativeStack(wechat_backtrace::Backtrace* backtrace, char *&stack) { strcpy(stack, full_stack_builder.str().c_str()); } - -static char* getNativeBacktrace() { +static void saveNativeBackTrace(const char* key) { wechat_backtrace::Backtrace *backtracePrt; - wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( - 16); - + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER(16); backtracePrt = new wechat_backtrace::Backtrace; backtracePrt->max_frames = backtrace_zero.max_frames; @@ -111,11 +115,34 @@ static char* getNativeBacktrace() { wechat_backtrace::unwind_adapter(backtracePrt->frames.get(), backtracePrt->max_frames, backtracePrt->frame_size); - char* nativeStack; - makeNativeStack(backtracePrt, nativeStack); - return nativeStack; + string keyString(key); + backtraceMapLock.lock(); + backtraceMap[keyString] = static_cast>(backtracePrt); + backtraceMapLock.unlock(); +} + +static char* getNativeBacktrace(string keyString) { + if (!sDumpNativeBackTrace) { + return ""; + } + if (backtraceMap.count(keyString) > 0) { + backtraceMapLock.lock_shared(); + wechat_backtrace::Backtrace *backtracePrt = backtraceMap[keyString].get(); + backtraceMapLock.unlock_shared(); + char* nativeStack; + makeNativeStack(backtracePrt, nativeStack); + return nativeStack; + } else { + return ""; + } } +int (*original_socket)(int domain, int type, int protocol); +int my_socket(int domain, int type, int protocol) { + int ret = original_socket(domain, type, protocol); + TrafficCollector::enQueueInit(ret, domain, type); + return ret; +} int (*original_connect)(int fd, const struct sockaddr* addr, socklen_t addr_length); int my_connect(int fd, sockaddr *addr, socklen_t addr_length) { @@ -130,7 +157,6 @@ ssize_t my_read(int fd, void *buf, size_t count) { return ret; } - ssize_t (*original_recv)(int sockfd, void *buf, size_t len, int flags); ssize_t my_recv(int sockfd, void *buf, size_t len, int flags) { ssize_t ret = original_recv(sockfd, buf, len, flags); @@ -138,7 +164,6 @@ ssize_t my_recv(int sockfd, void *buf, size_t len, int flags) { return ret; } - ssize_t (*original_recvfrom)(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); ssize_t my_recvfrom(int sockfd, void *buf, size_t len, int flags, @@ -148,7 +173,6 @@ ssize_t my_recvfrom(int sockfd, void *buf, size_t len, int flags, return ret; } - ssize_t (*original_recvmsg)(int sockfd, struct msghdr *msg, int flags); ssize_t my_recvmsg(int sockfd, struct msghdr *msg, int flags) { ssize_t ret = original_recvmsg(sockfd, msg, flags); @@ -156,7 +180,6 @@ ssize_t my_recvmsg(int sockfd, struct msghdr *msg, int flags) { return ret; } - ssize_t (*original_write)(int fd, const void *buf, size_t count); ssize_t my_write(int fd, const void *buf, size_t count) { ssize_t ret = original_write(fd, buf, count); @@ -194,7 +217,7 @@ int my_close(int fd) { } static jobject nativeGetTrafficInfoMap(JNIEnv *env, jclass, jint type) { - return TrafficCollector::getTrafficInfoMap(type); + return TrafficCollector::getFdTrafficInfoMap(type); } static void nativeReleaseMatrixTraffic(JNIEnv *env, jclass) { @@ -202,26 +225,31 @@ static void nativeReleaseMatrixTraffic(JNIEnv *env, jclass) { TrafficCollector::clearTrafficInfo(); } +static jstring nativeGetNativeBackTraceByKey(JNIEnv *env, jclass, jstring key) { + const char* cKey = env->GetStringUTFChars(key, JNI_FALSE); + string keyString(cKey); + char* ret = getNativeBacktrace(keyString); + jstring jRet = env->NewStringUTF(ret); + return jRet; +} + static void nativeClearTrafficInfo(JNIEnv *env, jclass) { + backtraceMapLock.lock(); + backtraceMap.clear(); + backtraceMapLock.unlock(); TrafficCollector::clearTrafficInfo(); } -void setStackTrace(char* threadName) { +void setFdStackTraceCall(const char* key) { JNIEnv *env = JniInvocation::getEnv(); if (!env) return; - - jstring jThreadName = env->NewStringUTF(threadName); - jstring nativeBacktrace; + jstring jKey = env->NewStringUTF(key); if (sDumpNativeBackTrace) { - nativeBacktrace = env->NewStringUTF(getNativeBacktrace()); - } else { - nativeBacktrace = env->NewStringUTF(""); + saveNativeBackTrace(key); } - - env->CallStaticVoidMethod(gJ.TrafficPlugin, gJ.TrafficPlugin_setFdStackTrace, jThreadName, nativeBacktrace); - env->DeleteLocalRef(jThreadName); - env->DeleteLocalRef(nativeBacktrace); + env->CallStaticVoidMethod(gJ.TrafficPlugin, gJ.TrafficPlugin_setFdStackTrace, jKey); + env->DeleteLocalRef(jKey); } static void hookSocket(bool rxHook, bool txHook) { @@ -229,6 +257,9 @@ static void hookSocket(bool rxHook, bool txHook) { return; } + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "socket", + (void *) my_socket, (void **) (&original_socket)); + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "connect", (void *) my_connect, (void **) (&original_connect)); @@ -236,7 +267,8 @@ static void hookSocket(bool rxHook, bool txHook) { (void *) my_close, (void **) (&original_close)); if (rxHook) { - xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "read", + + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, "/data/.*", "read", (void *) my_read, (void **) (&original_read)); xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "recv", (void *) my_recv, (void **) (&original_recv)); @@ -247,7 +279,7 @@ static void hookSocket(bool rxHook, bool txHook) { } if (txHook) { - xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "write", + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, "/data/.*", "write", (void *) my_write, (void **) (&original_write)); xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "send", (void *) my_send, (void **) (&original_send)); @@ -257,12 +289,15 @@ static void hookSocket(bool rxHook, bool txHook) { (void *) my_sendmsg, (void **) (&original_sendmsg)); } + + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, "/vendor/lib.*", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libinput\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libgui\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libsensor\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libutils\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libcutils\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libtrace-canary\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libgsl\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libadbconnection_client\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libadbconnection\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libandroid_runtime\\.so$", nullptr); @@ -277,7 +312,13 @@ static void hookSocket(bool rxHook, bool txHook) { xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libsqlite\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libbase\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libartbase\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libart\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libtombstoned_client\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*liblog\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libcodec2_vndk\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libandroidfw\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libaudioclient\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libjavacrypto\\.so$", nullptr); xhook_refresh(true); HOOKED = true; @@ -291,8 +332,8 @@ static void ignoreSo(JNIEnv *env, jobjectArray ignoreSoFiles) { } } -static void nativeInitMatrixTraffic(JNIEnv *env, jclass, jboolean rxEnable, jboolean txEnable, jboolean dumpStackTrace, jboolean dumpNativeBackTrace, jboolean lookupIpAddress, jobjectArray ignoreSoFiles) { - TrafficCollector::startLoop(dumpStackTrace == JNI_TRUE, lookupIpAddress == JNI_TRUE); +static void nativeInitMatrixTraffic(JNIEnv *env, jclass, jboolean rxEnable, jboolean txEnable, jboolean dumpStackTrace, jboolean dumpNativeBackTrace, jobjectArray ignoreSoFiles) { + TrafficCollector::startLoop(dumpStackTrace == JNI_TRUE); sDumpNativeBackTrace = (dumpNativeBackTrace == JNI_TRUE); ignoreSo(env, ignoreSoFiles); hookSocket(rxEnable == JNI_TRUE, txEnable == JNI_TRUE); @@ -302,10 +343,11 @@ template static inline constexpr std::size_t NELEM(const T(&)[sz]) { return sz; } static const JNINativeMethod TRAFFIC_METHODS[] = { - {"nativeInitMatrixTraffic", "(ZZZZZ[Ljava/lang/String;)V", (void *) nativeInitMatrixTraffic}, + {"nativeInitMatrixTraffic", "(ZZZZ[Ljava/lang/String;)V", (void *) nativeInitMatrixTraffic}, {"nativeGetTrafficInfoMap", "(I)Ljava/util/HashMap;", (void *) nativeGetTrafficInfoMap}, {"nativeClearTrafficInfo", "()V", (void *) nativeClearTrafficInfo}, {"nativeReleaseMatrixTraffic", "()V", (void *) nativeReleaseMatrixTraffic}, + {"nativeGetNativeBackTraceByKey", "(Ljava/lang/String;)Ljava/lang/String;", (void *) nativeGetNativeBackTraceByKey}, }; JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { @@ -319,8 +361,9 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { if (!trafficCollectorCls) return -1; gJ.TrafficPlugin = static_cast(env->NewGlobalRef(trafficCollectorCls)); + gJ.TrafficPlugin_setFdStackTrace = - env->GetStaticMethodID(trafficCollectorCls, "setStackTrace", "(Ljava/lang/String;Ljava/lang/String;)V"); + env->GetStaticMethodID(trafficCollectorCls, "setFdStackTrace", "(Ljava/lang/String;)V"); if (env->RegisterNatives( trafficCollectorCls, TRAFFIC_METHODS, static_cast(NELEM(TRAFFIC_METHODS))) != 0) diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h index dd83748c2..c87fc2c7a 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h @@ -21,6 +21,8 @@ #ifndef MATRIX_ANDROID_MATRIXTRAFFIC_H #define MATRIX_ANDROID_MATRIXTRAFFIC_H -void setStackTrace(char* threadName); +void setFdStackTraceCall(const char* key); +void clearFdInfoCall(int fd); +void printLog(const char* log); #endif //MATRIX_ANDROID_MATRIXTRAFFIC_H diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc index d26d8a9b0..c66881e99 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc @@ -29,8 +29,10 @@ #include #include "MatrixTraffic.h" +#include #include #include +#include using namespace std; @@ -41,16 +43,19 @@ static lock_guard lock(queueMutex); static bool loopRunning = false; static bool sDumpStackTrace = false; static bool sLookupIpAddress = false; -static map fdFamilyMap; +static unordered_set activeFdSet; +static unordered_set invalidFdSet; + static blocking_queue> msgQueue; -static map rxTrafficInfoMap; -static map txTrafficInfoMap; -static mutex rxTrafficInfoMapLock; -static mutex txTrafficInfoMapLock; + +static map rxFdTrafficInfoMap; +static map txFdTrafficInfoMap; +static shared_mutex rxTrafficInfoMapLock; +static shared_mutex txTrafficInfoMapLock; static map fdThreadNameMap; static map fdIpAddressMap; -static mutex fdThreadNameMapLock; +static shared_mutex fdThreadNameMapSharedLock; static mutex fdIpAddressMapLock; string getIpAddressFromAddr(sockaddr* _addr) { @@ -86,6 +91,18 @@ string getIpAddressFromAddr(sockaddr* _addr) { return ipAddress; } +int isNetworkSocketFd(int fd) { + struct sockaddr c; + socklen_t cLen = sizeof(c); + int getSockNameRet = getsockname(fd, (struct sockaddr*) &c, &cLen); + if (getSockNameRet == 0) { + if (c.sa_family != AF_LOCAL && c.sa_family != AF_UNIX) { + return 1; + } + } + return 0; +} + void saveIpAddress(int fd, sockaddr* addr) { fdIpAddressMapLock.lock(); if (fdIpAddressMap.count(fd) == 0) { @@ -102,39 +119,50 @@ string getIpAddress(int fd) { } -string getKeyAndSaveStack(int fd) { - fdThreadNameMapLock.lock(); +string saveFdInfo(int fd) { + fdThreadNameMapSharedLock.lock_shared(); if (fdThreadNameMap.count(fd) == 0) { - string key; - if (sLookupIpAddress) { - key = getIpAddress(fd); - key.append(";"); - } + fdThreadNameMapSharedLock.unlock_shared(); auto threadName = new char[15]; prctl(PR_GET_NAME, threadName); - key.append(threadName); - fdThreadNameMap[fd] = key; - fdThreadNameMapLock.unlock(); + char key[32]; + snprintf(key, sizeof(key), "%d-%s", fd, threadName); + if (sDumpStackTrace) { - setStackTrace(key.data()); + setFdStackTraceCall(key); } + + fdThreadNameMapSharedLock.lock(); + fdThreadNameMap[fd] = key; + fdThreadNameMapSharedLock.unlock(); + return key; } else { auto key = fdThreadNameMap[fd]; - fdThreadNameMapLock.unlock(); + fdThreadNameMapSharedLock.unlock_shared(); return key; } } +void TrafficCollector::enQueueInit(int fd, int domain, int type) { + if (type == SOCK_DGRAM && domain != AF_LOCAL) { + saveFdInfo(fd); + shared_ptr msg = make_shared(MSG_TYPE_INIT, fd, 0); + } +} + void TrafficCollector::enQueueConnect(int fd, sockaddr *addr, socklen_t addr_length) { if (!loopRunning) { return; } - if (sLookupIpAddress) { - saveIpAddress(fd, addr); + + if (addr->sa_family == AF_LOCAL) { + return; } - shared_ptr msg = make_shared(MSG_TYPE_CONNECT, fd, addr->sa_family, getKeyAndSaveStack(fd), 0); + + saveFdInfo(fd); + shared_ptr msg = make_shared(MSG_TYPE_CONNECT, fd, 0); msgQueue.push(msg); queueMutex.unlock(); @@ -144,7 +172,7 @@ void TrafficCollector::enQueueClose(int fd) { if (!loopRunning) { return; } - shared_ptr msg = make_shared(MSG_TYPE_CLOSE, fd, 0, "", 0); + shared_ptr msg = make_shared(MSG_TYPE_CLOSE, fd, 0); msgQueue.push(msg); queueMutex.unlock(); } @@ -154,7 +182,8 @@ void enQueueMsg(int type, int fd, size_t len) { return; } - shared_ptr msg = make_shared(type, fd, 0, getKeyAndSaveStack(fd), len); + saveFdInfo(fd); + shared_ptr msg = make_shared(type, fd, len); msgQueue.push(msg); queueMutex.unlock(); } @@ -173,47 +202,58 @@ void TrafficCollector::enQueueRx(int type, int fd, size_t len) { enQueueMsg(type, fd, len); } -void appendRxTraffic(const string& threadName, long len) { +void appendRxTraffic(int fd, long len) { rxTrafficInfoMapLock.lock(); - rxTrafficInfoMap[threadName] += len; + rxFdTrafficInfoMap[fd] += len; rxTrafficInfoMapLock.unlock(); } -void appendTxTraffic(const string& threadName, long len) { +void appendTxTraffic(int fd, long len) { txTrafficInfoMapLock.lock(); - txTrafficInfoMap[threadName] += len; + txFdTrafficInfoMap[fd] += len; txTrafficInfoMapLock.unlock(); } + void loop() { while (loopRunning) { if (msgQueue.empty()) { queueMutex.lock(); } else { shared_ptr msg = msgQueue.front(); - if (msg->type == MSG_TYPE_CONNECT) { - fdFamilyMap[msg->fd] = msg->sa_family; - } else if (msg->type == MSG_TYPE_READ) { - if (fdFamilyMap.count(msg->fd) > 0) { - appendRxTraffic(msg->threadName, msg->len); + int fd = msg->fd; + int type = msg->type; + if (type != MSG_TYPE_INIT && type != MSG_TYPE_CLOSE) { + if (activeFdSet.count(fd) == 0 && invalidFdSet.count(fd) == 0) { + if (!isNetworkSocketFd(fd)) { + invalidFdSet.insert(fd); + fdThreadNameMapSharedLock.lock(); + fdThreadNameMap.erase(fd); + fdThreadNameMapSharedLock.unlock(); + } else { + activeFdSet.insert(fd); + } } - } else if (msg->type >= MSG_TYPE_RECV && msg->type <= MSG_TYPE_RECVMSG) { - if (fdFamilyMap[msg->fd] != AF_LOCAL) { - appendRxTraffic(msg->threadName, msg->len); + } + + if (type == MSG_TYPE_CONNECT || type == MSG_TYPE_INIT) { + activeFdSet.insert(fd); + } else if (type >= MSG_TYPE_READ && type <= MSG_TYPE_RECVMSG) { + if (activeFdSet.count(fd) > 0 && invalidFdSet.count(fd) == 0) { + appendRxTraffic(fd, msg->len); } - } else if (msg->type == MSG_TYPE_WRITE) { - if (fdFamilyMap.count(msg->fd) > 0) { - appendTxTraffic(msg->threadName, msg->len); + } else if (type >= MSG_TYPE_WRITE && type <= MSG_TYPE_SENDMSG) { + if (activeFdSet.count(fd) > 0 && invalidFdSet.count(fd) == 0) { + appendTxTraffic(fd, msg->len); } - } else if (msg->type >= MSG_TYPE_SEND && msg->type <= MSG_TYPE_SENDMSG) { - if (fdFamilyMap[msg->fd] != AF_LOCAL) { - appendTxTraffic(msg->threadName, msg->len); + } else if (type == MSG_TYPE_CLOSE) { + if (activeFdSet.count(fd) > 0) { + fdThreadNameMapSharedLock.lock(); + fdThreadNameMap.erase(fd); + fdThreadNameMapSharedLock.unlock(); + activeFdSet.erase(fd); + invalidFdSet.erase(fd); } - } else if (msg->type == MSG_TYPE_CLOSE) { - fdThreadNameMapLock.lock(); - fdThreadNameMap.erase(msg->fd); - fdThreadNameMapLock.unlock(); - fdFamilyMap.erase(msg->fd); } msgQueue.pop(); } @@ -221,9 +261,8 @@ void loop() { } -void TrafficCollector::startLoop(bool dumpStackTrace, bool lookupIpAddress) { +void TrafficCollector::startLoop(bool dumpStackTrace) { sDumpStackTrace = dumpStackTrace; - sLookupIpAddress = lookupIpAddress; loopRunning = true; thread loopThread(loop); loopThread.detach(); @@ -233,7 +272,7 @@ void TrafficCollector::stopLoop() { loopRunning = false; } -jobject TrafficCollector::getTrafficInfoMap(int type) { +jobject TrafficCollector::getFdTrafficInfoMap(int type) { JNIEnv *env = JniInvocation::getEnv(); jclass mapClass = env->FindClass("java/util/HashMap"); if(mapClass == nullptr) { @@ -245,25 +284,54 @@ jobject TrafficCollector::getTrafficInfoMap(int type) { "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); if (type == TYPE_GET_TRAFFIC_RX) { - rxTrafficInfoMapLock.lock(); - for (auto & it : rxTrafficInfoMap) { - jstring threadName = env->NewStringUTF(it.first.c_str()); + rxTrafficInfoMapLock.lock_shared(); + for (auto & it : rxFdTrafficInfoMap) { + int fd = it.first; + if (fdThreadNameMap.count(fd) == 0) { + continue; + } + fdThreadNameMapSharedLock.lock_shared(); + const char* key = fdThreadNameMap[fd].c_str(); + fdThreadNameMapSharedLock.unlock_shared(); + if (key == nullptr || strlen(key) == 0) { + continue; + } + + if (it.second <= 0) { + continue; + } + jstring jKey = env->NewStringUTF(key); jstring traffic = env->NewStringUTF(to_string(it.second).c_str()); - env->CallObjectMethod(jHashMap, mapPut, threadName, traffic); - env->DeleteLocalRef(threadName); + env->CallObjectMethod(jHashMap, mapPut, jKey, traffic); + env->DeleteLocalRef(jKey); env->DeleteLocalRef(traffic); + } - rxTrafficInfoMapLock.unlock(); + rxTrafficInfoMapLock.unlock_shared(); } else if (type == TYPE_GET_TRAFFIC_TX) { - txTrafficInfoMapLock.lock(); - for (auto & it : txTrafficInfoMap) { - jstring threadName = env->NewStringUTF(it.first.c_str()); + txTrafficInfoMapLock.lock_shared(); + for (auto & it : txFdTrafficInfoMap) { + int fd = it.first; + if (fdThreadNameMap.count(fd) == 0) { + continue; + } + fdThreadNameMapSharedLock.lock_shared(); + const char* key = fdThreadNameMap[fd].c_str(); + fdThreadNameMapSharedLock.unlock_shared(); + if (key == nullptr || strlen(key) == 0) { + continue; + } + + if (it.second <= 0) { + continue; + } + jstring jKey = env->NewStringUTF(key); jstring traffic = env->NewStringUTF(to_string(it.second).c_str()); - env->CallObjectMethod(jHashMap, mapPut, threadName, traffic); - env->DeleteLocalRef(threadName); + env->CallObjectMethod(jHashMap, mapPut, jKey, traffic); + env->DeleteLocalRef(jKey); env->DeleteLocalRef(traffic); } - txTrafficInfoMapLock.unlock(); + txTrafficInfoMapLock.unlock_shared(); } env->DeleteLocalRef(mapClass); return jHashMap; @@ -271,16 +339,18 @@ jobject TrafficCollector::getTrafficInfoMap(int type) { void TrafficCollector::clearTrafficInfo() { rxTrafficInfoMapLock.lock(); - rxTrafficInfoMap.clear(); + rxFdTrafficInfoMap.clear(); rxTrafficInfoMapLock.unlock(); txTrafficInfoMapLock.lock(); - txTrafficInfoMap.clear(); + txFdTrafficInfoMap.clear(); txTrafficInfoMapLock.unlock(); - fdThreadNameMapLock.lock(); + fdThreadNameMapSharedLock.lock(); fdThreadNameMap.clear(); - fdThreadNameMapLock.unlock(); + fdThreadNameMapSharedLock.unlock(); + + } TrafficCollector::~TrafficCollector() { diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h index 276cf0572..66377b243 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h @@ -31,6 +31,7 @@ #include #include +#define MSG_TYPE_INIT 0 #define MSG_TYPE_CONNECT 1 #define MSG_TYPE_READ 10 @@ -53,23 +54,25 @@ using namespace std; namespace MatrixTraffic { class TrafficMsg { public: - TrafficMsg(const int _type, const int _fd, sa_family_t _sa_family, string _threadName, long _len) - : type(_type), fd(_fd), sa_family(_sa_family), threadName(_threadName), len(_len) { + TrafficMsg(const int _type, const int _fd, long _len) + : type(_type), fd(_fd), len(_len) { } int type; int fd; - sa_family_t sa_family; - string threadName; +// sa_family_t sa_family; +// string threadName; long len; }; class TrafficCollector { public : - static void startLoop(bool dumpStackTrace, bool lookupIpAddress); + static void startLoop(bool dumpStackTrace); static void stopLoop(); + static void enQueueInit(int fd, int domain, int type); + static void enQueueConnect(int fd, sockaddr *addr, socklen_t __addr_length); static void enQueueClose(int fd); @@ -80,7 +83,7 @@ public : static void clearTrafficInfo(); - static jobject getTrafficInfoMap(int type); + static jobject getFdTrafficInfoMap(int type); virtual ~TrafficCollector(); }; diff --git a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java index fcf375d7c..b19f0c9e7 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java +++ b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java @@ -4,11 +4,17 @@ import java.util.List; public class TrafficConfig { + public static final int STACK_TRACE_FILTER_MODE_FULL = 0; + public static final int STACK_TRACE_FILTER_MODE_STARTS_WITH = 1; + public static final int STACK_TRACE_FILTER_MODE_PATTERN = 2; private boolean rxCollectorEnable; private boolean txCollectorEnable; private boolean dumpStackTraceEnable; private boolean dumpNativeBackTraceEnable; - private boolean lookupIpAddressEnable; + //TODO + //private boolean lookupIpAddressEnable; + private int stackTraceFilterMode = 0; + private String stackTraceFilterCore; private List ignoreSoList = new ArrayList<>(); public TrafficConfig() { @@ -20,15 +26,13 @@ public TrafficConfig(boolean rxCollectorEnable, boolean txCollectorEnable, boole this.txCollectorEnable = txCollectorEnable; this.dumpStackTraceEnable = dumpStackTraceEnable; this.dumpNativeBackTraceEnable = false; - this.lookupIpAddressEnable = false; } - public TrafficConfig(boolean rxCollectorEnable, boolean txCollectorEnable, boolean dumpStackTraceEnable, boolean dumpNativeBackTraceEnable, boolean lookupIpAddressEnable) { + public TrafficConfig(boolean rxCollectorEnable, boolean txCollectorEnable, boolean dumpStackTraceEnable, boolean dumpNativeBackTraceEnable) { this.rxCollectorEnable = rxCollectorEnable; this.txCollectorEnable = txCollectorEnable; this.dumpStackTraceEnable = dumpStackTraceEnable; this.dumpNativeBackTraceEnable = dumpNativeBackTraceEnable; - this.lookupIpAddressEnable = lookupIpAddressEnable; } public boolean isRxCollectorEnable() { @@ -61,14 +65,6 @@ public void setDumpNativeBackTrace(boolean dumpNativeBackTraceEnable) { this.dumpNativeBackTraceEnable = dumpNativeBackTraceEnable; } - public boolean willLookupIpAddress() { - return lookupIpAddressEnable; - } - - public void setLookupIpAddressEnable(boolean lookupIpAddressEnable) { - this.lookupIpAddressEnable = lookupIpAddressEnable; - } - public void addIgnoreSoFile(String soName) { ignoreSoList.add(soName); } @@ -76,4 +72,17 @@ public void addIgnoreSoFile(String soName) { public String[] getIgnoreSoFiles() { return ignoreSoList.toArray(new String[ignoreSoList.size()]); } + + public void setStackTraceFilterMode(int mode, String filterCore) { + this.stackTraceFilterMode = mode; + this.stackTraceFilterCore = filterCore; + } + + public int getStackTraceFilterMode() { + return this.stackTraceFilterMode; + } + + public String getStackTraceFilterCore() { + return this.stackTraceFilterCore; + } } diff --git a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java index c6926159f..bd9a9fde6 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java +++ b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java @@ -4,8 +4,10 @@ import com.tencent.matrix.plugin.Plugin; import com.tencent.matrix.util.MatrixLog; +import com.tencent.matrix.util.MatrixUtil; import java.util.HashMap; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class TrafficPlugin extends Plugin { @@ -15,9 +17,12 @@ public class TrafficPlugin extends Plugin { public static final int TYPE_GET_TRAFFIC_RX = 0; public static final int TYPE_GET_TRAFFIC_TX = 1; - private static final ConcurrentHashMap stackTraceMap = new ConcurrentHashMap<>(); + private static int stackTraceFilterMode = 0; + private static String stackTraceFilterCore = ""; + private static final Map hashStackTraceMap = new ConcurrentHashMap<>(); + private static final Map keyHashMap = new ConcurrentHashMap<>(); - //TODO will be done in next upgrade + //TODO //public static final int TYPE_GET_TRAFFIC_ALL = 2; static { @@ -36,7 +41,9 @@ public void start() { super.start(); MatrixLog.i(TAG, "start"); String[] ignoreSoFiles = trafficConfig.getIgnoreSoFiles(); - nativeInitMatrixTraffic(trafficConfig.isRxCollectorEnable(), trafficConfig.isTxCollectorEnable(), trafficConfig.willDumpStackTrace(), trafficConfig.willDumpNativeBackTrace(), trafficConfig.willLookupIpAddress(), ignoreSoFiles); + stackTraceFilterMode = trafficConfig.getStackTraceFilterMode(); + stackTraceFilterCore = trafficConfig.getStackTraceFilterCore(); + nativeInitMatrixTraffic(trafficConfig.isRxCollectorEnable(), trafficConfig.isTxCollectorEnable(), trafficConfig.willDumpStackTrace(), trafficConfig.willDumpNativeBackTrace(), ignoreSoFiles); } @@ -54,35 +61,62 @@ public HashMap getTrafficInfoMap(int type) { return nativeGetTrafficInfoMap(type); } - public ConcurrentHashMap getStackTraceMap() { - return stackTraceMap; + public String getStackTraceByMd5(String md5) { + return hashStackTraceMap.get(md5); + } + + public String getJavaStackTraceByKey(String key) { + String md5 = keyHashMap.get(key); + if (md5 == null || md5.isEmpty()) { + return ""; + } + return hashStackTraceMap.get(md5); + } + public String getNativeBackTraceByKey(String key) { + return nativeGetNativeBackTraceByKey(key); } public void clearTrafficInfo() { - stackTraceMap.clear(); + keyHashMap.clear(); + hashStackTraceMap.clear(); nativeClearTrafficInfo(); } - private static native void nativeInitMatrixTraffic(boolean rxEnable, boolean txEnable, boolean dumpStackTrace, boolean dumpNativeBackTrace, boolean lookupIpAddress, String[] ignoreSoFiles); + private static native void nativeInitMatrixTraffic(boolean rxEnable, boolean txEnable, boolean dumpStackTrace, boolean dumpNativeBackTrace, String[] ignoreSoFiles); private static native String nativeGetTrafficInfo(); private static native String nativeGetAllStackTraceTrafficInfo(); private static native void nativeReleaseMatrixTraffic(); private static native void nativeClearTrafficInfo(); private static native HashMap nativeGetTrafficInfoMap(int type); + private static native String nativeGetNativeBackTraceByKey(String key); @Keep - private static void setStackTrace(String threadName, String nativeBackTrace) { - MatrixLog.i(TAG, "setStackTrace, threadName = " + threadName, "nativeBackTrace = " + nativeBackTrace); - StringBuilder stackTrace = new StringBuilder(nativeBackTrace); + private static void setFdStackTrace(String key) { + StringBuilder stackTrace = new StringBuilder(); StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); - for (int line = 3; line < stackTraceElements.length; line++) { - stackTrace.append(stackTraceElements[line]).append("\n"); - } + for (int line = 0; line < stackTraceElements.length; line++) { + String stackTraceLine = stackTraceElements[line].toString(); + boolean willAppend = false; + if (stackTraceFilterMode == TrafficConfig.STACK_TRACE_FILTER_MODE_FULL) { + willAppend = true; + } else if (stackTraceFilterMode == TrafficConfig.STACK_TRACE_FILTER_MODE_STARTS_WITH) { + if (stackTraceLine.startsWith(stackTraceFilterCore)) { + willAppend = true; + } + } else if (stackTraceFilterMode == TrafficConfig.STACK_TRACE_FILTER_MODE_PATTERN) { + if (stackTraceLine.matches(stackTraceFilterCore)) { + willAppend = true; + } + } + if (willAppend) { + stackTrace.append(stackTraceLine).append("\n"); + } - stackTraceMap.put(threadName, stackTrace.toString()); - } - - public void clearStackTrace() { - stackTraceMap.clear(); + } + String md5 = MatrixUtil.getMD5String(stackTrace.toString()); + if (!hashStackTraceMap.containsKey(md5)) { + hashStackTraceMap.put(md5, stackTrace.toString()); + } + keyHashMap.put(key, md5); } } From 63e60c16ecde348850039a55552a81c279699049 Mon Sep 17 00:00:00 2001 From: leafjia Date: Sun, 15 May 2022 23:54:59 +0800 Subject: [PATCH 013/263] Add pthread key tracer --- .../matrix-trace-canary/CMakeLists.txt | 9 +- .../matrix-trace-canary/build.gradle | 3 +- .../src/main/cpp/MatrixTracer.cc | 169 ++++++++++++++++-- .../com/tencent/matrix/trace/TracePlugin.java | 12 -- .../matrix/trace/config/TraceConfig.java | 11 -- .../trace/listeners/IDefaultConfig.java | 2 - ...dPriorityTracer.java => ThreadTracer.java} | 39 +++- .../com/tencent/matrix/trace/util/Utils.java | 8 + 8 files changed, 210 insertions(+), 43 deletions(-) rename matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/{ThreadPriorityTracer.java => ThreadTracer.java} (75%) diff --git a/matrix/matrix-android/matrix-trace-canary/CMakeLists.txt b/matrix/matrix-android/matrix-trace-canary/CMakeLists.txt index a914613dc..0f74c6bf1 100644 --- a/matrix/matrix-android/matrix-trace-canary/CMakeLists.txt +++ b/matrix/matrix-android/matrix-trace-canary/CMakeLists.txt @@ -14,8 +14,14 @@ add_library(trace-canary src/main/cpp/nativehelper/managed_jnienv.cc ) -TARGET_INCLUDE_DIRECTORIES(trace-canary PRIVATE ${EXT_DEP}/include) +target_include_directories( + trace-canary + PRIVATE ${EXT_DEP}/include + PRIVATE ${EXT_DEP}/include/backtrace + PRIVATE ${EXT_DEP}/include/backtrace/common +) +TARGET_INCLUDE_DIRECTORIES(trace-canary PRIVATE ${EXT_DEP}/include) find_library( log-lib log ) @@ -25,6 +31,7 @@ target_link_libraries( trace-canary PRIVATE ${log-lib} PRIVATE ${EXT_DEP}/lib/${ANDROID_ABI}/libxhook.a PRIVATE ${EXT_DEP}/lib/${ANDROID_ABI}/libsemi_dlfcn.a + PRIVATE ${EXT_DEP}/lib/${ANDROID_ABI}/libwechatbacktrace.so ) set_target_properties(trace-canary PROPERTIES diff --git a/matrix/matrix-android/matrix-trace-canary/build.gradle b/matrix/matrix-android/matrix-trace-canary/build.gradle index d7bc40620..70adce006 100644 --- a/matrix/matrix-android/matrix-trace-canary/build.gradle +++ b/matrix/matrix-android/matrix-trace-canary/build.gradle @@ -17,7 +17,7 @@ android { cppFlags "-std=gnu++11 -frtti -fexceptions" } ndk { - abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + abiFilters "armeabi-v7a", "arm64-v8a" } } @@ -69,6 +69,7 @@ dependencies { testImplementation 'junit:junit:4.12' implementation project(':matrix-android-lib') implementation project(':matrix-android-commons') + implementation project(':matrix-backtrace') } version = rootProject.ext.VERSION_NAME diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc index f3c178618..4479cb696 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc +++ b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc @@ -31,6 +31,11 @@ #include #include #include +#include + +#include "BacktraceDefine.h" +#include "Backtrace.h" +#include "cxxabi.h" #include #include @@ -55,8 +60,10 @@ #define HOOK_CONNECT_PATH "/dev/socket/tombstoned_java_trace" #define HOOK_OPEN_PATH "/data/anr/traces.txt" #define VALIDATE_RET 50 +#define KEY_VALID_FLAG (1 << 31) -#define HOOK_REQUEST_GROUPID_THREAD_PRIO_TRACE 0x01 +#define HOOK_REQUEST_GROUPID_THREAD_PRIORITY_TRACE 0x01 +#define HOOK_REQUEST_GROUPID_THREAD_PTHREAD_KEY_TRACE 0x13 #define HOOK_REQUEST_GROUPID_TOUCH_EVENT_TRACE 0x07 #define HOOK_REQUEST_GROUPID_ANR_DUMP_TRACE 0x12 @@ -85,6 +92,7 @@ static struct StacktraceJNI { jmethodID ThreadPriorityDetective_onMainThreadPriorityModified; jmethodID ThreadPriorityDetective_onMainThreadTimerSlackModified; + jmethodID ThreadPriorityDetective_pthreadKeyCallback; jmethodID TouchEventLagTracer_onTouchEvenLag; jmethodID TouchEventLagTracer_onTouchEvenLagDumpTrace; @@ -92,7 +100,6 @@ static struct StacktraceJNI { int (*original_setpriority)(int __which, id_t __who, int __priority); int my_setpriority(int __which, id_t __who, int __priority) { - if ((__who == 0 && getpid() == gettid()) || __who == getpid()) { int priorityBefore = getpriority(__which, __who); JNIEnv *env = JniInvocation::getEnv(); @@ -224,6 +231,111 @@ ssize_t my_sendto(int sockfd, const void *buf, size_t len, int flags, return ret; } +void pthreadKeyCallback(int type, int ret, int keySeq, const char* soName, const char* backtrace) { + JNIEnv *env = JniInvocation::getEnv(); + if (!env) return; + + jstring soNameJS = env->NewStringUTF(soName); + jstring nativeBacktraceJS = env->NewStringUTF(backtrace); + + env->CallStaticVoidMethod(gJ.ThreadPriorityDetective, gJ.ThreadPriorityDetective_pthreadKeyCallback, type, ret, keySeq, soNameJS, nativeBacktraceJS); + env->DeleteLocalRef(soNameJS); + env->DeleteLocalRef(nativeBacktraceJS); +} + +void makeNativeStack(wechat_backtrace::Backtrace* backtrace, char *&stack) { + std::string caller_so_name; + std::stringstream full_stack_builder; + std::stringstream brief_stack_builder; + std::string last_so_name; + int index = 0; + auto _callback = [&](wechat_backtrace::FrameDetail it) { + std::string so_name = it.map_name; + + char *demangled_name = nullptr; + + demangled_name = abi::__cxa_demangle(it.function_name, nullptr, 0, &status); + + if (strstr(it.map_name, "libtrace-canary.so") || strstr(it.map_name, "libwechatbacktrace.so")) { + return; + } + + full_stack_builder + << "#" << std::dec << (index++) + << " pc " << std::hex << it.rel_pc << " " + << it.map_name + << " (" + << (demangled_name ? demangled_name : "null") + << ")" + << std::endl; + if (last_so_name != it.map_name) { + last_so_name = it.map_name; + brief_stack_builder << it.map_name << ";"; + } + + brief_stack_builder << std::hex << it.rel_pc << ";"; + + if (demangled_name) { + free(demangled_name); + } + }; + + wechat_backtrace::restore_frame_detail(backtrace->frames.get(), backtrace->frame_size, + _callback); + + stack = new char[full_stack_builder.str().size() + 1]; + strcpy(stack, full_stack_builder.str().c_str()); +} + +static const char* getNativeBacktrace() { + wechat_backtrace::Backtrace *backtracePrt; + + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( + 16); + + + backtracePrt = new wechat_backtrace::Backtrace; + backtracePrt->max_frames = backtrace_zero.max_frames; + backtracePrt->frame_size = backtrace_zero.frame_size; + backtracePrt->frames = backtrace_zero.frames; + + wechat_backtrace::unwind_adapter(backtracePrt->frames.get(), backtracePrt->max_frames, + backtracePrt->frame_size); + + char* nativeStack; + makeNativeStack(backtracePrt, nativeStack); + return nativeStack; +} + +int (*original_pthread_key_create)(pthread_key_t *key, void (*destructor)(void*)); +int my_pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) { + int ret = original_pthread_key_create(key, destructor); + int keySeq = *key & ~KEY_VALID_FLAG; + + void * __caller_addr = __builtin_return_address(0); + Dl_info dl_info; + dladdr(__caller_addr, &dl_info); + const char* soName = dl_info.dli_fname; + if (!strstr(soName, "libc.so")) { + pthreadKeyCallback(0, ret, keySeq, soName, getNativeBacktrace()); + } + return ret; +} + +int (*original_pthread_key_delete)(pthread_key_t key); +int my_pthread_key_delete(pthread_key_t key) { + int ret = original_pthread_key_delete(key); + int keySeq = key & ~KEY_VALID_FLAG; + void * __caller_addr = __builtin_return_address(0); + Dl_info dl_info; + dladdr(__caller_addr, &dl_info); + const char* soName = dl_info.dli_fname; + if (!strstr(soName, "libc.so")) { + pthreadKeyCallback(1, ret, keySeq, soName, getNativeBacktrace()); + } + return 0; +} + bool anrDumpCallback() { JNIEnv *env = JniInvocation::getEnv(); if (!env) return false; @@ -319,12 +431,41 @@ static void nativeFreeSignalAnrDetective(JNIEnv *env, jclass) { sAnrDumper.reset(); } -static void nativeInitMainThreadPriorityDetective(JNIEnv *env, jclass) { - xhook_grouped_register(HOOK_REQUEST_GROUPID_THREAD_PRIO_TRACE, ".*\\.so$", "setpriority", - (void *) my_setpriority, (void **) (&original_setpriority)); - xhook_grouped_register(HOOK_REQUEST_GROUPID_THREAD_PRIO_TRACE, ".*\\.so$", "prctl", - (void *) my_prctl, (void **) (&original_prctl)); - xhook_refresh(true); +static int nativeGetPthreadKeySeq(JNIEnv *env, jclass) { + pthread_key_t key; + pthread_key_create(&key, nullptr); + int key_seq = key & ~KEY_VALID_FLAG; + pthread_key_delete(key); + return key_seq; +} + +static void nativeInitThreadHook(JNIEnv *env, jclass, jint priority, jint pthreadKey) { + if (priority == 1) { + xhook_grouped_register(HOOK_REQUEST_GROUPID_THREAD_PRIORITY_TRACE, ".*\\.so$", "setpriority", + (void *) my_setpriority, (void **) (&original_setpriority)); + xhook_grouped_register(HOOK_REQUEST_GROUPID_THREAD_PRIORITY_TRACE, ".*\\.so$", "prctl", + (void *) my_prctl, (void **) (&original_prctl)); + } + + if (pthreadKey == 1) { + xhook_grouped_register(HOOK_REQUEST_GROUPID_THREAD_PTHREAD_KEY_TRACE, ".*\\.so$", "pthread_key_create", + (void *) my_pthread_key_create, (void **) (&original_pthread_key_create)); + + xhook_grouped_register(HOOK_REQUEST_GROUPID_THREAD_PTHREAD_KEY_TRACE, ".*\\.so$", "pthread_key_delete", + (void *) my_pthread_key_delete, (void **) (&original_pthread_key_delete)); + + + xhook_export_symtable_hook("libc.so", "pthread_key_create", + (void *) my_pthread_key_create, (void **) (&original_pthread_key_create)); + xhook_export_symtable_hook("libc.so", "pthread_key_delete", + (void *) my_pthread_key_delete, (void **) (&original_pthread_key_delete)); + } + + if (pthreadKey + pthreadKey > 0) { + xhook_enable_sigsegv_protection(0); + xhook_refresh(0); + } + } static void nativeInitTouchEventLagDetective(JNIEnv *env, jclass, jint threshold) { @@ -355,8 +496,8 @@ static const JNINativeMethod ANR_METHODS[] = { }; static const JNINativeMethod THREAD_PRIORITY_METHODS[] = { - {"nativeInitMainThreadPriorityDetective", "()V", (void *) nativeInitMainThreadPriorityDetective}, - + {"nativeInitThreadHook", "(II)V", (void *) nativeInitThreadHook}, + {"nativeGetPthreadKeySeq", "()I", (void *) nativeGetPthreadKeySeq}, }; static const JNINativeMethod TOUCH_EVENT_TRACE_METHODS[] = { @@ -374,6 +515,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { jclass anrDetectiveCls = env->FindClass("com/tencent/matrix/trace/tracer/SignalAnrTracer"); if (!anrDetectiveCls) return -1; + + gJ.AnrDetective = static_cast(env->NewGlobalRef(anrDetectiveCls)); gJ.AnrDetector_onANRDumped = env->GetStaticMethodID(anrDetectiveCls, "onANRDumped", "()V"); @@ -393,7 +536,7 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { env->DeleteLocalRef(anrDetectiveCls); - jclass threadPriorityDetectiveCls = env->FindClass("com/tencent/matrix/trace/tracer/ThreadPriorityTracer"); + jclass threadPriorityDetectiveCls = env->FindClass("com/tencent/matrix/trace/tracer/ThreadTracer"); jclass touchEventLagTracerCls = env->FindClass("com/tencent/matrix/trace/tracer/TouchEventLagTracer"); @@ -405,6 +548,10 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { gJ.ThreadPriorityDetective_onMainThreadPriorityModified = env->GetStaticMethodID(threadPriorityDetectiveCls, "onMainThreadPriorityModified", "(II)V"); + + gJ.ThreadPriorityDetective_pthreadKeyCallback = + env->GetStaticMethodID(threadPriorityDetectiveCls, "pthreadKeyCallback", "(IIILjava/lang/String;Ljava/lang/String;)V"); + gJ.ThreadPriorityDetective_onMainThreadTimerSlackModified = env->GetStaticMethodID(threadPriorityDetectiveCls, "onMainThreadTimerSlackModified", "(J)V"); diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/TracePlugin.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/TracePlugin.java index 319924708..500865556 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/TracePlugin.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/TracePlugin.java @@ -32,7 +32,6 @@ import com.tencent.matrix.trace.tracer.LooperAnrTracer; import com.tencent.matrix.trace.tracer.SignalAnrTracer; import com.tencent.matrix.trace.tracer.StartupTracer; -import com.tencent.matrix.trace.tracer.ThreadPriorityTracer; import com.tencent.matrix.trace.tracer.TouchEventLagTracer; import com.tencent.matrix.util.MatrixHandlerThread; import com.tencent.matrix.util.MatrixLog; @@ -51,7 +50,6 @@ public class TracePlugin extends Plugin { private SignalAnrTracer signalAnrTracer; private IdleHandlerLagTracer idleHandlerLagTracer; private TouchEventLagTracer touchEventLagTracer; - private ThreadPriorityTracer threadPriorityTracer; private static boolean supportFrameMetrics; public TracePlugin(TraceConfig config) { @@ -132,11 +130,6 @@ public void run() { } } - if (traceConfig.isMainThreadPriorityTraceEnable()) { - threadPriorityTracer = new ThreadPriorityTracer(); - threadPriorityTracer.onStartTrace(); - } - if (traceConfig.isFPSEnable()) { frameTracer.onStartTrace(); } @@ -192,11 +185,6 @@ public void run() { if (idleHandlerLagTracer != null) { idleHandlerLagTracer.onCloseTrace(); } - - if (threadPriorityTracer != null) { - threadPriorityTracer.onCloseTrace(); - } - } }; diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/config/TraceConfig.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/config/TraceConfig.java index b6aa3901b..627770c65 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/config/TraceConfig.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/config/TraceConfig.java @@ -49,7 +49,6 @@ public class TraceConfig implements IDefaultConfig { public boolean isDevEnv; public boolean defaultSignalAnrEnable; public int stackStyle = STACK_STYLE_SIMPLE; - public boolean defaultMainThreadPriorityTraceEnable; public String splashActivities; public Set splashActivitiesSet; public String anrTraceFilePath = ""; @@ -137,11 +136,6 @@ public boolean isSignalAnrTraceEnable() { return defaultSignalAnrEnable; } - @Override - public boolean isMainThreadPriorityTraceEnable() { - return defaultMainThreadPriorityTraceEnable; - } - @Override public String getAnrTraceFilePath() { return anrTraceFilePath; @@ -337,11 +331,6 @@ public Builder setTouchEventThreshold(int threshold) { return this; } - public Builder enableMainThreadPriorityTrace(boolean enable) { - config.defaultMainThreadPriorityTraceEnable = enable; - return this; - } - public Builder enableHistoryMsgRecorder(boolean enable) { config.historyMsgRecorder = enable; return this; diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/listeners/IDefaultConfig.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/listeners/IDefaultConfig.java index 00ab53187..872d2eb61 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/listeners/IDefaultConfig.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/listeners/IDefaultConfig.java @@ -36,8 +36,6 @@ public interface IDefaultConfig { boolean isSignalAnrTraceEnable(); - boolean isMainThreadPriorityTraceEnable(); - boolean isDebug(); boolean isDevEnv(); diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadPriorityTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadTracer.java similarity index 75% rename from matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadPriorityTracer.java rename to matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadTracer.java index a07041629..04a142876 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadPriorityTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadTracer.java @@ -29,10 +29,13 @@ import org.json.JSONObject; -public class ThreadPriorityTracer extends Tracer { +public class ThreadTracer extends Tracer { private static final String TAG = "ThreadPriorityTracer"; private static MainThreadPriorityModifiedListener sMainThreadPriorityModifiedListener; + private static PthreadKeyCallback sPthreadKeyCallback; + private static boolean enableThreadPriorityTracer = false; + private static boolean enablePthreadKeyTracer = false; static { System.loadLibrary("trace-canary"); @@ -41,7 +44,7 @@ public class ThreadPriorityTracer extends Tracer { @Override protected void onAlive() { super.onAlive(); - nativeInitMainThreadPriorityDetective(); + nativeInitThreadHook(enableThreadPriorityTracer ? 1 : 0, enablePthreadKeyTracer ? 1 : 0); } @Override @@ -50,10 +53,21 @@ protected void onDead() { } public void setMainThreadPriorityModifiedListener(MainThreadPriorityModifiedListener mainThreadPriorityModifiedListener) { - this.sMainThreadPriorityModifiedListener = mainThreadPriorityModifiedListener; + enableThreadPriorityTracer = true; + sMainThreadPriorityModifiedListener = mainThreadPriorityModifiedListener; } - private static native void nativeInitMainThreadPriorityDetective(); + public void setPthreadKeyCallback(PthreadKeyCallback callback) { + enablePthreadKeyTracer = true; + sPthreadKeyCallback = callback; + } + + public static int getPthreadKeySeq() { + return nativeGetPthreadKeySeq(); + } + + private static native void nativeInitThreadHook(int priority, int phreadKey); + private static native int nativeGetPthreadKeySeq(); @Keep private static void onMainThreadPriorityModified(int priorityBefore, int priorityAfter) { @@ -115,12 +129,27 @@ private static void onMainThreadTimerSlackModified(long timerSlack) { } catch (Throwable t) { MatrixLog.e(TAG, "onMainThreadPriorityModified error: %s", t.getMessage()); } + } + + @Keep + private static void pthreadKeyCallback(int type, int ret, int keySeq, String soPath, String backtrace) { + if (sPthreadKeyCallback != null) { + if (type == 0) { + sPthreadKeyCallback.onPthreadCreate(ret, keySeq, soPath, backtrace); + } else if (type == 1) { + sPthreadKeyCallback.onPthreadDelete(ret, keySeq, soPath, backtrace); + } + } } public interface MainThreadPriorityModifiedListener { void onMainThreadPriorityModified(int priorityBefore, int priorityAfter); - void onMainThreadTimerSlackModified(long timerSlack); } + + public interface PthreadKeyCallback { + void onPthreadCreate(int ret, int keyIndex, String soPath, String backtrace); + void onPthreadDelete(int ret, int keyIndex, String soPath, String backtrace); + } } diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/util/Utils.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/util/Utils.java index 1852d62b8..abda6920b 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/util/Utils.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/util/Utils.java @@ -87,6 +87,14 @@ public static String getMainThreadJavaStackTrace() { return stackTrace.toString(); } + public static String getJavaStackTrace() { + StringBuilder stackTrace = new StringBuilder(); + for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) { + stackTrace.append(stackTraceElement.toString()).append("\n"); + } + return stackTrace.toString(); + } + public static String calculateCpuUsage(long threadMs, long ms) { if (threadMs <= 0) { return ms > 1000 ? "0%" : "100%"; From ef79dfbcbd8e37b7bc9c0bd203e7d4e17e5a5930 Mon Sep 17 00:00:00 2001 From: leafjia Date: Sun, 15 May 2022 23:56:47 +0800 Subject: [PATCH 014/263] Add anrReportTimeout to avoid empty trace file --- .../matrix/trace/tracer/SignalAnrTracer.java | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/SignalAnrTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/SignalAnrTracer.java index d172e5a8b..6019c6374 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/SignalAnrTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/SignalAnrTracer.java @@ -49,13 +49,17 @@ import java.io.InputStreamReader; import java.lang.reflect.Field; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class SignalAnrTracer extends Tracer { private static final String TAG = "SignalAnrTracer"; private static final String CHECK_ANR_STATE_THREAD_NAME = "Check-ANR-State-Thread"; + private static final String ANR_DUMP_THREAD_NAME = "ANR-Dump-Thread"; private static final int CHECK_ERROR_STATE_INTERVAL = 500; private static final int ANR_DUMP_MAX_TIME = 20000; + private static long anrReportTimeout = ANR_DUMP_MAX_TIME; private static final int CHECK_ERROR_STATE_COUNT = ANR_DUMP_MAX_TIME / CHECK_ERROR_STATE_INTERVAL; private static final long FOREGROUND_MSG_THRESHOLD = -2000; @@ -114,6 +118,10 @@ public SignalAnrTracer(Application application, String anrTraceFilePath, String sApplication = application; } + public static void setAnrReportTimeout(long timeout) { + anrReportTimeout = timeout; + } + public void setSignalAnrDetectedListener(SignalAnrDetectedListener listener) { sSignalAnrDetectedListener = listener; } @@ -150,15 +158,28 @@ public void run() { @RequiresApi(api = Build.VERSION_CODES.M) @Keep private synchronized static void onANRDumped() { - onAnrDumpedTimeStamp = System.currentTimeMillis(); - MatrixLog.i(TAG, "onANRDumped"); - stackTrace = Utils.getMainThreadJavaStackTrace(); - MatrixLog.i(TAG, "onANRDumped, stackTrace = %s, duration = %d", stackTrace, (System.currentTimeMillis() - onAnrDumpedTimeStamp)); - cgroup = readCgroup(); - MatrixLog.i(TAG, "onANRDumped, read cgroup duration = %d", (System.currentTimeMillis() - onAnrDumpedTimeStamp)); - currentForeground = AppForegroundUtil.isInterestingToUser(); - MatrixLog.i(TAG, "onANRDumped, isInterestingToUser duration = %d", (System.currentTimeMillis() - onAnrDumpedTimeStamp)); - confirmRealAnr(true); + final CountDownLatch anrDumpLatch = new CountDownLatch(1); + new Thread(new Runnable() { + @Override + public void run() { + onAnrDumpedTimeStamp = System.currentTimeMillis(); + MatrixLog.i(TAG, "onANRDumped"); + stackTrace = Utils.getMainThreadJavaStackTrace(); + MatrixLog.i(TAG, "onANRDumped, stackTrace = %s, duration = %d", stackTrace, (System.currentTimeMillis() - onAnrDumpedTimeStamp)); + cgroup = readCgroup(); + MatrixLog.i(TAG, "onANRDumped, read cgroup duration = %d", (System.currentTimeMillis() - onAnrDumpedTimeStamp)); + currentForeground = AppForegroundUtil.isInterestingToUser(); + MatrixLog.i(TAG, "onANRDumped, isInterestingToUser duration = %d", (System.currentTimeMillis() - onAnrDumpedTimeStamp)); + confirmRealAnr(true); + anrDumpLatch.countDown(); + } + }, ANR_DUMP_THREAD_NAME).start(); + + try { + anrDumpLatch.await(anrReportTimeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + //empty here + } } @Keep From b60a414e4d24a93de9d3cd0fb48944350b70c8cc Mon Sep 17 00:00:00 2001 From: leafjia Date: Mon, 16 May 2022 00:06:55 +0800 Subject: [PATCH 015/263] Fix status deleted mistakenly --- .../matrix-trace-canary/src/main/cpp/MatrixTracer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc index 4479cb696..3387dce9e 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc +++ b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc @@ -253,6 +253,7 @@ void makeNativeStack(wechat_backtrace::Backtrace* backtrace, char *&stack) { std::string so_name = it.map_name; char *demangled_name = nullptr; + int status = 0; demangled_name = abi::__cxa_demangle(it.function_name, nullptr, 0, &status); From 4c197f193aac8424b965d8b5874f76b19ae82bb9 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Mon, 16 May 2022 10:44:09 +0800 Subject: [PATCH 016/263] memory-canary: fix trim memory index out of bounds error --- .../memory/canary/trim/TrimMemoryNotifier.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt index 0d6fdd6fe..160cdb94d 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt @@ -88,7 +88,7 @@ object TrimMemoryNotifier { runningHandler.postDelayed(this@TrimTask, delay) MatrixLog.i( TAG, - "[$name] trim delay[${delayIndex+1}/${config.delayMillis.size}] $delay" + "[$name] trim delay[${delayIndex + 1}/${config.delayMillis.size}] $delay" ) } @@ -100,18 +100,18 @@ object TrimMemoryNotifier { } override fun run() { - MatrixLog.i( - TAG, - "[$name] trim timeout [${delayIndex+1}/${config.delayMillis.size}] ${config.delayMillis[delayIndex]}" - ) - delayIndex++ - trimCallback.backgroundTrim() if (delayIndex < config.delayMillis.size) { + MatrixLog.i( + TAG, + "[$name] trim timeout [${delayIndex + 1}/${config.delayMillis.size}] ${config.delayMillis[delayIndex]}" + ) + delayIndex++ + trimCallback.backgroundTrim() val delay = config.delayMillis[delayIndex] runningHandler.postDelayed(this, delay) MatrixLog.i( TAG, - "[$name] trim delay[${delayIndex+1}/${config.delayMillis.size}] $delay" + "[$name] trim delay[${delayIndex + 1}/${config.delayMillis.size}] $delay" ) } } From 7283e353dc108f3fa2e5c44f7e3eb9ca6f6253ec Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 16 May 2022 11:44:03 +0800 Subject: [PATCH 017/263] Update battery util with cpu core num impl --- .../utils/BatteryCanaryUtil.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java index 8d34fa7e2..1d6df4994 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java @@ -87,6 +87,7 @@ public interface Proxy { void updateDevStat(int value); int getBatteryPercentage(Context context); int getBatteryCapacity(Context context); + int getCpuCoreNum(); final class ExpireRef { final int value; @@ -114,6 +115,7 @@ boolean isExpired() { private ExpireRef mLastDevStat; private ExpireRef mLastBattPct; private ExpireRef mLastBattCap; + private ExpireRef mLastCpuCoreNum; @Override public String getProcessName() { @@ -205,6 +207,19 @@ public int getBatteryCapacity(Context context) { mLastBattCap = new ExpireRef(val, ONE_MIN); return mLastBattCap.value; } + + @Override + public int getCpuCoreNum() { + if (mLastCpuCoreNum != null && !mLastCpuCoreNum.isExpired()) { + return mLastCpuCoreNum.value; + } + int val = getCpuCoreNumImmediately(); + if (val <= 1) { + return val; + } + mLastCpuCoreNum = new ExpireRef(val, ONE_HOR); + return mLastCpuCoreNum.value; + } }; public static void setProxy(Proxy stub) { @@ -307,8 +322,9 @@ public static String getAlarmTypeString(final int type) { } public static int[] getCpuCurrentFreq() { - int[] output = new int[getCpuCoreNum()]; - for (int i = 0; i < getCpuCoreNum(); i++) { + int cpuCoreNum = getCpuCoreNum(); + int[] output = new int[cpuCoreNum]; + for (int i = 0; i < cpuCoreNum; i++) { output[i] = 0; String path = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_freq"; String cat = cat(path); @@ -324,6 +340,10 @@ public static int[] getCpuCurrentFreq() { } public static int getCpuCoreNum() { + return sCacheStub.getCpuCoreNum(); + } + + public static int getCpuCoreNumImmediately() { try { // Get directory containing CPU info File dir = new File("/sys/devices/system/cpu/"); @@ -335,6 +355,7 @@ public boolean accept(File pathname) { } }); // Return the number of cores (virtual CPU devices) + // noinspection ConstantConditions return files.length; } catch (Exception ignored) { // Default to return 1 core From 97a53c85f92fadbc907a82dfcbf041994a932458 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Mon, 16 May 2022 14:44:43 +0800 Subject: [PATCH 018/263] memory-canary: fix trim memory index out of bounds error --- .../memory/canary/trim/TrimMemoryNotifier.kt | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt index 160cdb94d..81810e73b 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt @@ -88,7 +88,7 @@ object TrimMemoryNotifier { runningHandler.postDelayed(this@TrimTask, delay) MatrixLog.i( TAG, - "[$name] trim delay[${delayIndex + 1}/${config.delayMillis.size}] $delay" + "...[$name] trim delay[${delayIndex + 1}/${config.delayMillis.size}] $delay" ) } @@ -100,18 +100,24 @@ object TrimMemoryNotifier { } override fun run() { - if (delayIndex < config.delayMillis.size) { - MatrixLog.i( - TAG, - "[$name] trim timeout [${delayIndex + 1}/${config.delayMillis.size}] ${config.delayMillis[delayIndex]}" - ) - delayIndex++ - trimCallback.backgroundTrim() - val delay = config.delayMillis[delayIndex] + val currIndex = delayIndex + if (currIndex >= config.delayMillis.size) { + MatrixLog.e(TAG, "index[$currIndex] out of bounds[${config.delayMillis.size}]") + return + } + MatrixLog.i( + TAG, + "!!![$name] trim timeout [${currIndex + 1}/${config.delayMillis.size}] ${config.delayMillis[currIndex]}" + ) + trimCallback.backgroundTrim() + val nextIndex = currIndex + 1 + if (nextIndex < config.delayMillis.size) { + delayIndex = nextIndex + val delay = config.delayMillis[nextIndex] runningHandler.postDelayed(this, delay) MatrixLog.i( TAG, - "[$name] trim delay[${delayIndex + 1}/${config.delayMillis.size}] $delay" + "...[$name] trim delay[${nextIndex + 1}/${config.delayMillis.size}] $delay" ) } } From efe09010ae7d174772ba5e358dfdd6013a47dbab Mon Sep 17 00:00:00 2001 From: leafjia Date: Mon, 16 May 2022 16:31:20 +0800 Subject: [PATCH 019/263] Fix refresh rate is always default value --- .../java/com/tencent/matrix/trace/core/UIThreadMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/core/UIThreadMonitor.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/core/UIThreadMonitor.java index 74c9f3a4b..9233bdeb4 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/core/UIThreadMonitor.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/core/UIThreadMonitor.java @@ -135,9 +135,9 @@ public void dispatchEnd() { }); this.isInit = true; + choreographer = Choreographer.getInstance(); frameIntervalNanos = ReflectUtils.reflectObject(choreographer, "mFrameIntervalNanos", Constants.DEFAULT_FRAME_DURATION); if (!useFrameMetrics) { - choreographer = Choreographer.getInstance(); callbackQueueLock = ReflectUtils.reflectObject(choreographer, "mLock", new Object()); callbackQueues = ReflectUtils.reflectObject(choreographer, "mCallbackQueues", null); if (null != callbackQueues) { From cc701911ebbd4be6f9f0c69b0cb4da356d010259 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 17 May 2022 18:06:46 +0800 Subject: [PATCH 020/263] Update battery appStat impl --- .../feature/AppStatMonitorFeature.java | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java index 29f633e0e..93012fa30 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AppStatMonitorFeature.java @@ -13,6 +13,7 @@ import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.TimeBreaker; import com.tencent.matrix.lifecycle.IStateObserver; +import com.tencent.matrix.lifecycle.owners.ForegroundServiceLifecycleOwner; import com.tencent.matrix.lifecycle.owners.OverlayWindowLifecycleOwner; import com.tencent.matrix.util.MatrixLog; @@ -71,6 +72,34 @@ public void run() { } }; + private final IStateObserver mFgSrvObserver = new IStateObserver() { + @Override + public void on() { + MatrixLog.i(TAG, "fgSrv >> on"); + boolean foreground = mCore.isForeground(); + int appStat = BatteryCanaryUtil.getAppStatImmediately(mCore.getContext(), foreground); + if (appStat != APP_STAT_FOREGROUND) { + MatrixLog.i(TAG, "statAppStat: " + APP_STAT_FOREGROUND_SERVICE); + onStatAppStat(APP_STAT_FOREGROUND_SERVICE); + } else { + MatrixLog.i(TAG, "skip statAppStat, fg = " + foreground + ", currAppStat = " + appStat); + } + } + + @Override + public void off() { + MatrixLog.i(TAG, "fgSrv >> off"); + boolean foreground = mCore.isForeground(); + int appStat = BatteryCanaryUtil.getAppStatImmediately(mCore.getContext(), foreground); + if (appStat != APP_STAT_FOREGROUND && appStat != APP_STAT_FOREGROUND_SERVICE && appStat != APP_STAT_FLOAT_WINDOW) { + MatrixLog.i(TAG, "statAppStat: " + APP_STAT_BACKGROUND); + onStatAppStat(APP_STAT_BACKGROUND); + } else { + MatrixLog.i(TAG, "skip statAppStat, fg = " + foreground + ", currAppStat = " + appStat); + } + } + }; + private final IStateObserver mFloatViewObserver = new IStateObserver() { @Override public void on() { @@ -90,7 +119,7 @@ public void off() { MatrixLog.i(TAG, "floatView >> off"); boolean foreground = mCore.isForeground(); int appStat = BatteryCanaryUtil.getAppStatImmediately(mCore.getContext(), foreground); - if (appStat != APP_STAT_FOREGROUND && appStat != APP_STAT_FOREGROUND_SERVICE) { + if (appStat != APP_STAT_FOREGROUND && appStat != APP_STAT_FOREGROUND_SERVICE && appStat != APP_STAT_FLOAT_WINDOW) { MatrixLog.i(TAG, "statAppStat: " + APP_STAT_BACKGROUND); onStatAppStat(APP_STAT_BACKGROUND); } else { @@ -122,12 +151,14 @@ public void onTurnOn() { mSceneStampList.add(0, firstSceneStamp); } + ForegroundServiceLifecycleOwner.INSTANCE.observeForever(mFgSrvObserver); OverlayWindowLifecycleOwner.INSTANCE.observeForever(mFloatViewObserver); } @Override public void onTurnOff() { super.onTurnOff(); + ForegroundServiceLifecycleOwner.INSTANCE.removeObserver(mFgSrvObserver); OverlayWindowLifecycleOwner.INSTANCE.removeObserver(mFloatViewObserver); synchronized (TAG) { mStampList.clear(); From 0e0615e492ab593108f396e8b7f60a5db81f9f7e Mon Sep 17 00:00:00 2001 From: leafjia Date: Thu, 19 May 2022 00:13:41 +0800 Subject: [PATCH 021/263] Do NOT hook init and connect --- .../src/main/cpp/MatrixTraffic.cc | 19 ------------ .../src/main/cpp/TrafficCollector.cc | 29 ++----------------- .../src/main/cpp/TrafficCollector.h | 7 ----- 3 files changed, 2 insertions(+), 53 deletions(-) diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc index 01e9f0577..e475492cf 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -137,19 +137,6 @@ static char* getNativeBacktrace(string keyString) { } } -int (*original_socket)(int domain, int type, int protocol); -int my_socket(int domain, int type, int protocol) { - int ret = original_socket(domain, type, protocol); - TrafficCollector::enQueueInit(ret, domain, type); - return ret; -} - -int (*original_connect)(int fd, const struct sockaddr* addr, socklen_t addr_length); -int my_connect(int fd, sockaddr *addr, socklen_t addr_length) { - TrafficCollector::enQueueConnect(fd, addr, addr_length); - return original_connect(fd, addr, addr_length); -} - ssize_t (*original_read)(int fd, void *buf, size_t count); ssize_t my_read(int fd, void *buf, size_t count) { ssize_t ret = original_read(fd, buf, count); @@ -257,12 +244,6 @@ static void hookSocket(bool rxHook, bool txHook) { return; } - xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "socket", - (void *) my_socket, (void **) (&original_socket)); - - xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "connect", - (void *) my_connect, (void **) (&original_connect)); - xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "close", (void *) my_close, (void **) (&original_close)); diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc index c66881e99..d3ce5dcc0 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc @@ -145,29 +145,6 @@ string saveFdInfo(int fd) { } } -void TrafficCollector::enQueueInit(int fd, int domain, int type) { - if (type == SOCK_DGRAM && domain != AF_LOCAL) { - saveFdInfo(fd); - shared_ptr msg = make_shared(MSG_TYPE_INIT, fd, 0); - } -} - -void TrafficCollector::enQueueConnect(int fd, sockaddr *addr, socklen_t addr_length) { - if (!loopRunning) { - return; - } - - if (addr->sa_family == AF_LOCAL) { - return; - } - - saveFdInfo(fd); - shared_ptr msg = make_shared(MSG_TYPE_CONNECT, fd, 0); - - msgQueue.push(msg); - queueMutex.unlock(); -} - void TrafficCollector::enQueueClose(int fd) { if (!loopRunning) { return; @@ -223,7 +200,7 @@ void loop() { shared_ptr msg = msgQueue.front(); int fd = msg->fd; int type = msg->type; - if (type != MSG_TYPE_INIT && type != MSG_TYPE_CLOSE) { + if (type != MSG_TYPE_CLOSE) { if (activeFdSet.count(fd) == 0 && invalidFdSet.count(fd) == 0) { if (!isNetworkSocketFd(fd)) { invalidFdSet.insert(fd); @@ -236,9 +213,7 @@ void loop() { } } - if (type == MSG_TYPE_CONNECT || type == MSG_TYPE_INIT) { - activeFdSet.insert(fd); - } else if (type >= MSG_TYPE_READ && type <= MSG_TYPE_RECVMSG) { + if (type >= MSG_TYPE_READ && type <= MSG_TYPE_RECVMSG) { if (activeFdSet.count(fd) > 0 && invalidFdSet.count(fd) == 0) { appendRxTraffic(fd, msg->len); } diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h index 66377b243..e94dd7797 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h @@ -31,9 +31,6 @@ #include #include -#define MSG_TYPE_INIT 0 -#define MSG_TYPE_CONNECT 1 - #define MSG_TYPE_READ 10 #define MSG_TYPE_RECV 11 #define MSG_TYPE_RECVFROM 12 @@ -71,10 +68,6 @@ public : static void stopLoop(); - static void enQueueInit(int fd, int domain, int type); - - static void enQueueConnect(int fd, sockaddr *addr, socklen_t __addr_length); - static void enQueueClose(int fd); static void enQueueTx(int type, int fd, size_t len); From ae43252a0d7b52b25542db0c3bcc3eec6f27a131 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 19 May 2022 14:51:57 +0800 Subject: [PATCH 022/263] Fix battery canary devStat --- .../batterycanary/monitor/feature/DeviceStatMonitorFeature.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java index 370ce28ea..324958dc4 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java @@ -228,7 +228,7 @@ public boolean onStateChanged(String event) { break; case Intent.ACTION_SCREEN_ON: if (!mIsCharging) { - mListener.accept(AppStats.DEV_STAT_CHARGING); + mListener.accept(AppStats.DEV_STAT_SCREEN_ON); } break; case Intent.ACTION_SCREEN_OFF: From 1a9139b8772d8a46450f303233be97567719da36 Mon Sep 17 00:00:00 2001 From: leafjia Date: Mon, 23 May 2022 10:58:17 +0800 Subject: [PATCH 023/263] Fix memory leak --- .../matrix-traffic/src/main/cpp/MatrixTraffic.cc | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc index e475492cf..400cad799 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -66,11 +66,6 @@ void makeNativeStack(wechat_backtrace::Backtrace* backtrace, char *&stack) { auto _callback = [&](wechat_backtrace::FrameDetail it) { std::string so_name = it.map_name; - char *demangled_name = nullptr; - int status = 0; - - demangled_name = abi::__cxa_demangle(it.function_name, nullptr, 0, &status); - if (strstr(it.map_name, "libmatrix-traffic.so") || strstr(it.map_name, "libwechatbacktrace.so")) { return; } @@ -79,9 +74,6 @@ void makeNativeStack(wechat_backtrace::Backtrace* backtrace, char *&stack) { << "#" << std::dec << (index++) << " pc " << std::hex << it.rel_pc << " " << it.map_name - << " (" - << (demangled_name ? demangled_name : "null") - << ")" << std::endl; if (last_so_name != it.map_name) { last_so_name = it.map_name; @@ -89,10 +81,6 @@ void makeNativeStack(wechat_backtrace::Backtrace* backtrace, char *&stack) { } brief_stack_builder << std::hex << it.rel_pc << ";"; - - if (demangled_name) { - free(demangled_name); - } }; wechat_backtrace::restore_frame_detail(backtrace->frames.get(), backtrace->frame_size, @@ -217,6 +205,7 @@ static jstring nativeGetNativeBackTraceByKey(JNIEnv *env, jclass, jstring key) { string keyString(cKey); char* ret = getNativeBacktrace(keyString); jstring jRet = env->NewStringUTF(ret); + delete[] ret; return jRet; } From 51f1f983c590c75e89e3c62a8800d0bfcc1ff191 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 24 May 2022 20:27:25 +0800 Subject: [PATCH 024/263] Fix battery canary cpuload cfg --- .../monitor/feature/CompositeMonitors.java | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 986b76a08..f46d1d5b4 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -163,19 +163,10 @@ public int getCpuLoad() { return -1; } - Delta cpuJiffies = getDelta(CpuStatFeature.CpuStateSnapshot.class); - if (cpuJiffies == null) { - MatrixLog.w(TAG, "Configure CpuLoad by uptime"); - long appJiffiesDelta = appJiffies.dlt.totalJiffies.get(); - long cpuUptimeDelta = mAppStats.duringMillis; - float cpuLoad = cpuUptimeDelta > 0 ? (float) (appJiffiesDelta * 10) / cpuUptimeDelta : 0; - return (int) (cpuLoad * 100); - } - long appJiffiesDelta = appJiffies.dlt.totalJiffies.get(); - long cpuJiffiesDelta = cpuJiffies.dlt.totalCpuJiffies(); - float cpuLoad = cpuJiffiesDelta > 0 ? (float) appJiffiesDelta / cpuJiffiesDelta : 0; - return (int) (cpuLoad * BatteryCanaryUtil.getCpuCoreNum() * 100); + long cpuUptimeDelta = mAppStats.duringMillis; + float cpuLoad = cpuUptimeDelta > 0 ? (float) (appJiffiesDelta * 10) / cpuUptimeDelta : 0; + return (int) (cpuLoad * 100); } public > boolean isOverHeat(Class snapshotClass) { From b8e7349d6266b0b539e0b6f3c62345355c676256 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 24 May 2022 21:04:54 +0800 Subject: [PATCH 025/263] Add devCpuLoad --- .../monitor/feature/CompositeMonitors.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index f46d1d5b4..cd22a76e5 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -156,7 +156,6 @@ public int getCpuLoad() { MatrixLog.w(TAG, "AppStats should not be null to get CpuLoad"); return -1; } - Delta appJiffies = getDelta(JiffiesSnapshot.class); if (appJiffies == null) { MatrixLog.w(TAG, JiffiesSnapshot.class + " should be metrics to get CpuLoad"); @@ -169,6 +168,23 @@ public int getCpuLoad() { return (int) (cpuLoad * 100); } + public int getDevCpuLoad() { + if (mAppStats == null) { + MatrixLog.w(TAG, "AppStats should not be null to get CpuLoad"); + return -1; + } + Delta cpuJiffies = getDelta(CpuStatFeature.CpuStateSnapshot.class); + if (cpuJiffies == null) { + MatrixLog.w(TAG, "Configure CpuLoad by uptime"); + return -1; + } + + long cpuJiffiesDelta = cpuJiffies.dlt.totalCpuJiffies(); + long devJiffiesDelta = mAppStats.duringMillis; + float cpuLoad = devJiffiesDelta > 0 ? (float) (cpuJiffiesDelta * 10) / devJiffiesDelta : 0; + return (int) (cpuLoad * 100); + } + public > boolean isOverHeat(Class snapshotClass) { AppStats appStats = getAppStats(); Delta delta = getDelta(snapshotClass); From 3706138994435dce37e5ac57065fdd3a4dc381ea Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 25 May 2022 19:59:46 +0800 Subject: [PATCH 026/263] resource-canary: treat soft reference as strong reference --- .../matrix/resource/analyzer/model/AndroidExcludedRefs.java | 5 ++++- .../src/main/cpp/memory_util/excludes/excludes.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/model/AndroidExcludedRefs.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/model/AndroidExcludedRefs.java index 7efb93906..53060bd22 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/model/AndroidExcludedRefs.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/model/AndroidExcludedRefs.java @@ -684,7 +684,10 @@ void add(ExcludedRefs.Builder excluded) { @Override void add(ExcludedRefs.Builder excluded) { excluded.clazz(WeakReference.class.getName()).alwaysExclude(); - excluded.clazz(SoftReference.class.getName()).alwaysExclude(); +// we should treat soft reference as strong reference, because +// "all soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError." +// see https://developer.android.com/reference/java/lang/ref/SoftReference +// excluded.clazz(SoftReference.class.getName()).alwaysExclude(); excluded.clazz(PhantomReference.class.getName()).alwaysExclude(); excluded.clazz("java.lang.ref.Finalizer").alwaysExclude(); excluded.clazz("java.lang.ref.FinalizerReference").alwaysExclude(); diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/cpp/memory_util/excludes/excludes.cpp b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/cpp/memory_util/excludes/excludes.cpp index a18c3da4c..a6b7396e6 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/cpp/memory_util/excludes/excludes.cpp +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/cpp/memory_util/excludes/excludes.cpp @@ -931,7 +931,10 @@ bool exclude_default_references(HprofAnalyzer &analyzer) { * Non-strong references. */ analyzer.ExcludeInstanceFieldReference("java.lang.ref.WeakReference", "referent"); - analyzer.ExcludeInstanceFieldReference("java.lang.ref.SoftReference", "referent"); +// we should treat soft reference as strong reference, because +// "all soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError." +// see https://developer.android.com/reference/java/lang/ref/SoftReference +// analyzer.ExcludeInstanceFieldReference("java.lang.ref.SoftReference", "referent"); analyzer.ExcludeInstanceFieldReference("java.lang.ref.PhantomReference", "referent"); analyzer.ExcludeInstanceFieldReference("java.lang.ref.Finalizer", "prev"); analyzer.ExcludeInstanceFieldReference("java.lang.ref.Finalizer", "element"); From 7672a9d4d308e1a1633a25f6360e3b06bf6f442c Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 26 May 2022 15:14:39 +0800 Subject: [PATCH 027/263] Update battery dev cpuLoad cfg --- .../matrix/batterycanary/Examples.java | 2 +- .../monitor/feature/CompositorTest.java | 12 ++++---- .../monitor/BatteryMonitorCallback.java | 30 ++++++------------- .../monitor/feature/CompositeMonitors.java | 4 +++ 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java index 94f0700b2..cdb18bf2d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java @@ -79,7 +79,7 @@ public void exampleForCpuLoad() { compositor.finish(); int cpuLoad = compositor.getCpuLoad(); - Assert.assertTrue(cpuLoad > 0); + Assert.assertTrue("cpuLoad: " + cpuLoad, cpuLoad >= 0); } } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java index 78a7fa509..535d596cc 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java @@ -198,10 +198,10 @@ public void run() { compositeMonitor.start(); Thread.sleep(1000L); compositeMonitor.finish(); - int cpuLoad = compositeMonitor.getCpuLoad(); - Assert.assertTrue(cpuLoad >= 0 && cpuLoad <= BatteryCanaryUtil.getCpuCoreNum() * 100); + int devCpuLoad = compositeMonitor.getDevCpuLoad(); + Assert.assertTrue("devCpuLoad: " + devCpuLoad, devCpuLoad >= 0 && devCpuLoad <= BatteryCanaryUtil.getCpuCoreNum() * 100); - Assert.assertEquals(cpuLoad, cpuLoadR, 10); + Assert.assertEquals(devCpuLoad, cpuLoadR, 10); compositeMonitor = new CompositeMonitors(monitor); Assert.assertFalse(compositeMonitor.mMetrics.contains(JiffiesSnapshot.class)); @@ -214,8 +214,8 @@ public void run() { compositeMonitor.finish(); long wallTimeEnd = System.currentTimeMillis(); long upTimeEnd = SystemClock.uptimeMillis(); - cpuLoad = compositeMonitor.getCpuLoad(); - Assert.assertTrue(cpuLoad >= 0 && cpuLoad <= BatteryCanaryUtil.getCpuCoreNum() * 100); + devCpuLoad = compositeMonitor.getDevCpuLoad(); + Assert.assertTrue("devCpuLoad: " + devCpuLoad,devCpuLoad >= 0 && devCpuLoad <= BatteryCanaryUtil.getCpuCoreNum() * 100); long wallTimeDelta = wallTimeEnd - wallTimeBgn; long uptimeDelta = upTimeEnd - upTimeBgn; @@ -229,7 +229,7 @@ public void run() { cpuLoadR = (int) ((appJiffies.dlt.totalJiffies.get() / (uptimeDelta / 10f)) * 100); Assert.assertTrue("cpuLoadR: " + cpuLoadR, cpuLoadR >= 0 && cpuLoadR <= BatteryCanaryUtil.getCpuCoreNum() * 100); - Assert.assertEquals(cpuLoad, cpuLoadR, 10); + Assert.assertEquals(devCpuLoad, cpuLoadR, 10); } @Test diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java index fbcfe9502..d813f449d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java @@ -408,7 +408,7 @@ public void accept(Delta delta) { } } - protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, CompositeMonitors monitors, final Printer printer) { + protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, final CompositeMonitors monitors, final Printer printer) { if (monitors.getMonitor() == null || monitors.getAppStats() == null) { return false; } @@ -546,45 +546,33 @@ public void accept(Sampler.Result result) { if (sessionDelta.dlt instanceof CpuStateSnapshot) { //noinspection unchecked final Delta delta = (Delta) sessionDelta; + final long minute = Math.max(1, delta.during / ONE_MIN); // Cpu Usage - printer.createSubSection("cpu_load"); + printer.createSubSection("dev_cpu_load"); printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); final CpuStatFeature cpuStatFeature = monitors.getFeature(CpuStatFeature.class); if (cpuStatFeature != null) { - monitors.getDelta(JiffiesSnapshot.class, new Consumer>() { - @Override - public void accept(Delta jiffiesDelta) { - long appJiffiesDelta = jiffiesDelta.dlt.totalJiffies.get(); - long cpuJiffiesDelta = delta.dlt.totalCpuJiffies(); - float cpuLoad = (float) appJiffiesDelta / cpuJiffiesDelta; - float cpuLoadAvg = cpuLoad * cpuStatFeature.getPowerProfile().getCpuCoreNum(); - printer.writeLine("usage", (int) (cpuLoadAvg * 100) + "%"); - } - }); + printer.writeLine("usage", monitors.getDevCpuLoad() + "%"); } for (int i = 0; i < delta.dlt.cpuCoreStates.size(); i++) { ListEntry> listEntry = delta.dlt.cpuCoreStates.get(i); printer.writeLine("cpu" + i, Arrays.toString(listEntry.getList().toArray())); } - // BatterySip - if (cpuStatFeature != null) { + // Cpu BatterySip + if (cpuStatFeature != null && cpuStatFeature.isSupported()) { printer.createSubSection("cpu_sip"); // Cpu battery sip - CPU State final PowerProfile powerProfile = cpuStatFeature.getPowerProfile(); - printer.writeLine("inc_cpu_sip", String.format(Locale.US, "%.2f(mAh)", delta.dlt.configureCpuSip(powerProfile))); + printer.writeLine("inc_cpu_sip", String.format(Locale.US, "%.2f(mAh)/min", delta.dlt.configureCpuSip(powerProfile) / minute)); printer.writeLine("cur_cpu_sip", String.format(Locale.US, "%.2f(mAh)", delta.end.configureCpuSip(powerProfile))); // Cpu battery sip - Proc State monitors.getDelta(JiffiesSnapshot.class, new Consumer>() { @Override public void accept(Delta jiffiesDelta) { - double procSipDelta = delta.dlt.configureProcSip(powerProfile, jiffiesDelta.dlt.totalJiffies.get()); + double procSipBgn = delta.bgn.configureProcSip(powerProfile, jiffiesDelta.bgn.totalJiffies.get()); double procSipEnd = delta.end.configureProcSip(powerProfile, jiffiesDelta.end.totalJiffies.get()); - printer.writeLine("inc_prc_sip", String.format(Locale.US, "%.2f(mAh)", procSipDelta)); + printer.writeLine("inc_prc_sip", String.format(Locale.US, "%.2f(mAh)/min", (procSipEnd - procSipBgn) / minute)); printer.writeLine("cur_prc_sip", String.format(Locale.US, "%.2f(mAh)", procSipEnd)); - if (Double.isNaN(procSipDelta)) { - double procSipBgn = delta.bgn.configureProcSip(powerProfile, jiffiesDelta.bgn.totalJiffies.get()); - printer.writeLine("inc_prc_sipr", String.format(Locale.US, "%.2f(mAh)", procSipEnd - procSipBgn)); - } } }); } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index cd22a76e5..bd887257c 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -168,6 +168,10 @@ public int getCpuLoad() { return (int) (cpuLoad * 100); } + + /** + * Work in progress + */ public int getDevCpuLoad() { if (mAppStats == null) { MatrixLog.w(TAG, "AppStats should not be null to get CpuLoad"); From cf7f7aea27b3fb12314e6755d5a3d999c5c7de3a Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 1 Jun 2022 17:28:02 +0800 Subject: [PATCH 028/263] Update battery sampling --- .../feature/MonitorFeatureOverAllTest.java | 1 + .../monitor/feature/CompositeMonitors.java | 41 ++++++++++++++++--- .../monitor/feature/CpuStatFeature.java | 10 +++++ .../monitor/feature/MonitorFeature.java | 2 +- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java index 4fc36c443..0740c261b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java @@ -81,6 +81,7 @@ public BatteryPrinter attach(BatteryMonitorCore monitorCore) { BatteryPrinter core = super.attach(monitorCore); mCompositeMonitors.sample(DeviceStatMonitorFeature.BatteryTmpSnapshot.class, 100L); mCompositeMonitors.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 100L); + mCompositeMonitors.sample(CpuStatFeature.CpuStateSnapshot.class, 100L); return core; } }) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index bd887257c..0aa675260 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -473,6 +473,7 @@ protected Snapshot.Sampler statSampler(Class> snapshotClas public Number call() { DeviceStatMonitorFeature.CpuFreqSnapshot snapshot = feature.currentCpuFreq(); List> list = snapshot.cpuFreqs.getList(); + MatrixLog.i(TAG, "onSampling, cpufreq = " + list); Collections.sort(list, new Comparator>() { @Override public int compare(DigitEntry o1, DigitEntry o2) { @@ -493,7 +494,9 @@ public int compare(DigitEntry o1, DigitEntry o2) { @Override public Number call() { DeviceStatMonitorFeature.BatteryTmpSnapshot snapshot = feature.currentBatteryTemperature(mMonitor.getContext()); - return snapshot.temp.get(); + Integer value = snapshot.temp.get(); + MatrixLog.i(TAG, "onSampling, batt-temp = " + value); + return value; } }); mSamplers.put(snapshotClass, sampler); @@ -506,7 +509,9 @@ public Number call() { sampler = new Snapshot.Sampler("thermal-stat", mMonitor.getHandler(), new Callable() { @Override public Number call() { - return BatteryCanaryUtil.getThermalStat(mMonitor.getContext()); + int value = BatteryCanaryUtil.getThermalStat(mMonitor.getContext()); + MatrixLog.i(TAG, "onSampling, thermal-stat = " + value); + return value; } }); mSamplers.put(snapshotClass, sampler); @@ -521,7 +526,9 @@ public Number call() { sampler = new Snapshot.Sampler("thermal-headroom", mMonitor.getHandler(), new Callable() { @Override public Number call() { - return BatteryCanaryUtil.getThermalHeadroom(mMonitor.getContext(), (int) (interval / 1000L)); + float value = BatteryCanaryUtil.getThermalHeadroom(mMonitor.getContext(), (int) (interval / 1000L)); + MatrixLog.i(TAG, "onSampling, thermal-headroom = " + value); + return value; } }); mSamplers.put(snapshotClass, sampler); @@ -532,10 +539,34 @@ public Number call() { if (snapshotClass == DeviceStatMonitorFeature.ChargeWattageSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler("batt-temp", mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("batt-watt", mMonitor.getHandler(), new Callable() { + @Override + public Number call() { + int value = BatteryCanaryUtil.getChargingWatt(mMonitor.getContext()); + MatrixLog.i(TAG, "onSampling, batt-watt = " + value); + return value; + } + }); + mSamplers.put(snapshotClass, sampler); + } + return sampler; + } + if (snapshotClass == CpuStatFeature.CpuStateSnapshot.class) { + final CpuStatFeature feature = getFeature(CpuStatFeature.class); + if (feature != null && feature.isSupported() && mMonitor != null) { + sampler = new Snapshot.Sampler("cpu-stat", mMonitor.getHandler(), new Callable() { @Override public Number call() { - return BatteryCanaryUtil.getChargingWatt(mMonitor.getContext()); + CpuStatFeature.CpuStateSnapshot snapshot = feature.currentCpuStateSnapshot(); + for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { + Snapshot.Entry.ListEntry> item = snapshot.cpuCoreStates.get(i); + MatrixLog.i(TAG, "onSampling, cpuCore" + i + " = " + item.getList()); + } + for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { + Snapshot.Entry.ListEntry> item = snapshot.procCpuCoreStates.get(i); + MatrixLog.i(TAG, "onSampling, procCpuCluster" + i + " = " + item.getList()); + } + return snapshot.totalProcCpuJiffies(); } }); mSamplers.put(snapshotClass, sampler); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java index d1af3617d..2b05065bb 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java @@ -166,6 +166,16 @@ public long totalCpuJiffies() { return sum; } + public long totalProcCpuJiffies() { + long sum = 0; + for (ListEntry> cpuCoreState : procCpuCoreStates) { + for (DigitEntry item : cpuCoreState.getList()) { + sum += item.value; + } + } + return sum; + } + public double configureCpuSip(PowerProfile powerProfile) { if (!powerProfile.isSupported()) { return 0; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index c145e19e9..cbb996317 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -431,7 +431,7 @@ public void run() { try { MatrixLog.i(TAG, "onSampling, count = " + mCount); Number currSample = mSamplingBlock.call(); - if (currSample != INVALID) { + if (!currSample.equals(INVALID)) { mSampleLst = currSample.doubleValue(); mCount++; mSampleAvg = (mSampleAvg * (mCount - 1) + mSampleLst) / mCount; From 15fc74123f2fcdcf49f19323c4ede72778635fd8 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 1 Jun 2022 19:33:19 +0800 Subject: [PATCH 029/263] Add battery uid jiffies snapshot --- .../feature/MonitorFeatureOverAllTest.java | 3 + .../monitor/feature/CompositeMonitors.java | 28 ++++++++ .../feature/JiffiesMonitorFeature.java | 64 +++++++++++++++++++ .../shell/ui/TopThreadIndicator.java | 4 +- 4 files changed, 98 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java index 0740c261b..2ddb73fd4 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java @@ -82,10 +82,13 @@ public BatteryPrinter attach(BatteryMonitorCore monitorCore) { mCompositeMonitors.sample(DeviceStatMonitorFeature.BatteryTmpSnapshot.class, 100L); mCompositeMonitors.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 100L); mCompositeMonitors.sample(CpuStatFeature.CpuStateSnapshot.class, 100L); + mCompositeMonitors.sample(JiffiesMonitorFeature.UidJiffiesSnapshot.class, 100L); return core; } }) .build(); + + return new BatteryMonitorCore(config); } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 0aa675260..022365dde 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -573,6 +573,34 @@ public Number call() { } return sampler; } + if (snapshotClass == JiffiesMonitorFeature.UidJiffiesSnapshot.class) { + final JiffiesMonitorFeature feature = getFeature(JiffiesMonitorFeature.class); + if (feature != null && mMonitor != null) { + sampler = new Snapshot.Sampler("uid-jiffies", mMonitor.getHandler(), new Callable() { + JiffiesMonitorFeature.UidJiffiesSnapshot mLastSnapshot; + @Override + public Number call() { + JiffiesMonitorFeature.UidJiffiesSnapshot curr = feature.currentUidJiffiesSnapshot(); + if (mLastSnapshot != null) { + Delta delta = curr.diff(mLastSnapshot); + long minute = Math.max(1, delta.during / BatteryCanaryUtil.ONE_MIN); + long avgUidJiffies = delta.dlt.totalUidJiffies.get() / minute; + MatrixLog.i(TAG, "onSampling, avgUidJiffies = " + avgUidJiffies + ", minute = " + minute); + for (Delta item : delta.dlt.pidDeltaJiffiesList) { + long avgPidJiffies = item.dlt.totalJiffies.get() / minute; + MatrixLog.i(TAG, "onSampling, avgPidJiffies = " + avgPidJiffies + ", minute = " + minute + ", name = " + item.dlt.name); + } + return avgUidJiffies; + } else { + mLastSnapshot = curr; + } + return 0; + } + }); + mSamplers.put(snapshotClass, sampler); + } + return sampler; + } return null; } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java index 8c8d540a3..d35313baf 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java @@ -1,5 +1,6 @@ package com.tencent.matrix.batterycanary.monitor.feature; +import android.content.Context; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -10,6 +11,8 @@ import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore.Callback; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.ListEntry; +import com.tencent.matrix.batterycanary.shell.TopThreadFeature; +import com.tencent.matrix.batterycanary.shell.ui.TopThreadIndicator; import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.ProcStatUtil; import com.tencent.matrix.util.MatrixLog; @@ -27,6 +30,7 @@ import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; import androidx.annotation.WorkerThread; +import androidx.core.util.Pair; @SuppressWarnings("NotNullFieldNotInitialized") public final class JiffiesMonitorFeature extends AbsMonitorFeature { @@ -82,6 +86,11 @@ public JiffiesSnapshot currentJiffiesSnapshot(int pid) { return JiffiesSnapshot.currentJiffiesSnapshot(ProcessInfo.getProcessInfo(pid), mCore.getConfig().isStatPidProc); } + @WorkerThread + public UidJiffiesSnapshot currentUidJiffiesSnapshot() { + return UidJiffiesSnapshot.of(mCore.getContext(), mCore.getConfig().isStatPidProc); + } + @AnyThread public void currentJiffiesSnapshot(@NonNull final Callback callback) { mCore.getHandler().post(new Runnable() { @@ -458,4 +467,59 @@ private long setNext(long millis) { return millis; } } + + public static class UidJiffiesSnapshot extends Snapshot { + public static UidJiffiesSnapshot of(Context context, boolean isStatPidProc) { + UidJiffiesSnapshot curr = new UidJiffiesSnapshot(); + List> procList = TopThreadFeature.getProcList(context); + curr.pidCurrJiffiesList = new ArrayList<>(procList.size()); + long sum = 0; + for (Pair item : procList) { + //noinspection ConstantConditions + JiffiesSnapshot snapshot = JiffiesSnapshot.currentJiffiesSnapshot(ProcessInfo.getProcessInfo(item.first), isStatPidProc); + snapshot.name = TopThreadIndicator.getProcSuffix(item.second); + sum += snapshot.totalJiffies.get(); + curr.pidCurrJiffiesList.add(snapshot); + } + curr.totalUidJiffies = DigitEntry.of(sum); + return curr; + } + + public DigitEntry totalUidJiffies = DigitEntry.of(0L); + public List pidCurrJiffiesList = Collections.emptyList(); + public List> pidDeltaJiffiesList = Collections.emptyList(); + + @Override + public Delta diff(UidJiffiesSnapshot bgn) { + return new Delta(bgn, this) { + @Override + protected UidJiffiesSnapshot computeDelta() { + UidJiffiesSnapshot delta = new UidJiffiesSnapshot(); + delta.totalUidJiffies = Differ.DigitDiffer.globalDiff(bgn.totalUidJiffies, end.totalUidJiffies); + if (bgn.pidCurrJiffiesList.size() > 0) { + delta.pidDeltaJiffiesList = new ArrayList<>(); + for (JiffiesSnapshot bgn : bgn.pidCurrJiffiesList) { + for (JiffiesSnapshot end : end.pidCurrJiffiesList) { + if (bgn.pid == end.pid) { + Delta deltaPidJiffies = end.diff(bgn); + delta.pidDeltaJiffiesList.add(deltaPidJiffies); + break; + } + } + } + Collections.sort(delta.pidDeltaJiffiesList, new Comparator>() { + @Override + public int compare(Delta o1, Delta o2) { + long minus = o1.dlt.totalJiffies.get() - o2.dlt.totalJiffies.get(); + if (minus == 0) return 0; + if (minus > 0) return -1; + return 1; + } + }); + } + return delta; + } + }; + } + } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java index 6c4306625..f40cc682b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java @@ -50,6 +50,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; import androidx.annotation.UiThread; import androidx.core.util.Pair; @@ -624,7 +625,8 @@ public void run() { }); } - private static String getProcSuffix(String input) { + @RestrictTo(RestrictTo.Scope.LIBRARY) + public static String getProcSuffix(String input) { String proc = "main"; if (input.contains(":")) { proc = input.substring(input.lastIndexOf(":") + 1); From 6d6cba20ef35ae7730059d1162c4fb9c801fac2e Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 2 Jun 2022 14:47:56 +0800 Subject: [PATCH 030/263] Update uid jiffies differing --- .../feature/JiffiesMonitorFeature.java | 38 ++++++++++++++----- .../monitor/feature/MonitorFeature.java | 4 +- .../batterycanary/utils/ProcStatUtil.java | 8 ++++ 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java index d35313baf..c23ce151c 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java @@ -271,12 +271,14 @@ public static JiffiesSnapshot currentJiffiesSnapshot(ProcessInfo processInfo, bo } public int pid; + public boolean isNewAdded; public String name; public DigitEntry totalJiffies; public ListEntry threadEntries; public DigitEntry threadNum; private JiffiesSnapshot() { + isNewAdded = false; } @Override @@ -286,6 +288,7 @@ public Delta diff(JiffiesSnapshot bgn) { protected JiffiesSnapshot computeDelta() { JiffiesSnapshot delta = new JiffiesSnapshot(); delta.pid = end.pid; + delta.isNewAdded = end.isNewAdded; delta.name = end.name; delta.totalJiffies = Differ.DigitDiffer.globalDiff(bgn.totalJiffies, end.totalJiffies); delta.threadNum = Differ.DigitDiffer.globalDiff(bgn.threadNum, end.threadNum); @@ -476,10 +479,14 @@ public static UidJiffiesSnapshot of(Context context, boolean isStatPidProc) { long sum = 0; for (Pair item : procList) { //noinspection ConstantConditions - JiffiesSnapshot snapshot = JiffiesSnapshot.currentJiffiesSnapshot(ProcessInfo.getProcessInfo(item.first), isStatPidProc); - snapshot.name = TopThreadIndicator.getProcSuffix(item.second); - sum += snapshot.totalJiffies.get(); - curr.pidCurrJiffiesList.add(snapshot); + int pid = item.first; + String procName = String.valueOf(item.second); + if (ProcStatUtil.exists(pid)) { + JiffiesSnapshot snapshot = JiffiesSnapshot.currentJiffiesSnapshot(ProcessInfo.getProcessInfo(pid), isStatPidProc); + snapshot.name = TopThreadIndicator.getProcSuffix(procName); + sum += snapshot.totalJiffies.get(); + curr.pidCurrJiffiesList.add(snapshot); + } } curr.totalUidJiffies = DigitEntry.of(sum); return curr; @@ -496,17 +503,30 @@ public Delta diff(UidJiffiesSnapshot bgn) { protected UidJiffiesSnapshot computeDelta() { UidJiffiesSnapshot delta = new UidJiffiesSnapshot(); delta.totalUidJiffies = Differ.DigitDiffer.globalDiff(bgn.totalUidJiffies, end.totalUidJiffies); - if (bgn.pidCurrJiffiesList.size() > 0) { + if (end.pidCurrJiffiesList.size() > 0) { delta.pidDeltaJiffiesList = new ArrayList<>(); - for (JiffiesSnapshot bgn : bgn.pidCurrJiffiesList) { - for (JiffiesSnapshot end : end.pidCurrJiffiesList) { + for (JiffiesSnapshot end : end.pidCurrJiffiesList) { + JiffiesSnapshot last = null; + for (JiffiesSnapshot bgn : bgn.pidCurrJiffiesList) { if (bgn.pid == end.pid) { - Delta deltaPidJiffies = end.diff(bgn); - delta.pidDeltaJiffiesList.add(deltaPidJiffies); + last = bgn; break; } } + if (last == null) { + // newAdded Pid + end.isNewAdded = true; + JiffiesSnapshot empty = new JiffiesSnapshot(); + empty.pid = end.pid; + empty.name = end.name; + empty.totalJiffies = DigitEntry.of(0L); + empty.threadEntries = ListEntry.ofEmpty(); + empty.threadNum = DigitEntry.of(0); + } + Delta deltaPidJiffies = end.diff(last); + delta.pidDeltaJiffiesList.add(deltaPidJiffies); } + Collections.sort(delta.pidDeltaJiffiesList, new Comparator>() { @Override public int compare(Delta o1, Delta o2) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index cbb996317..6eeec8978 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -429,7 +429,7 @@ public static class Sampler { @Override public void run() { try { - MatrixLog.i(TAG, "onSampling, count = " + mCount); + MatrixLog.i(TAG, "onSampling" + mTag + ", count = " + mCount); Number currSample = mSamplingBlock.call(); if (!currSample.equals(INVALID)) { mSampleLst = currSample.doubleValue(); @@ -470,7 +470,7 @@ public void run() { double mSampleAvg = Double.MIN_VALUE; public Sampler(Handler handler, Callable onSampling) { - this("default", handler, onSampling); + this("dft", handler, onSampling); } public Sampler(String tag, Handler handler, Callable onSampling) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/ProcStatUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/ProcStatUtil.java index bd39ba55b..3aec48917 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/ProcStatUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/ProcStatUtil.java @@ -39,6 +39,14 @@ static byte[] getLocalBuffers() { ProcStatUtil() { } + public static boolean exists(int pid) { + return new File("/proc/" + pid + "/stat").exists(); + } + + public static boolean exists(int pid, int tid) { + return new File("/proc/" + pid + "/task/" + tid + "/stat").exists(); + } + @Nullable public static ProcStat currentPid() { return of(Process.myPid()); From 97636ca0314b1829112b665e9f7a7b7b7f70c4c1 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 2 Jun 2022 15:30:23 +0800 Subject: [PATCH 031/263] lifecycle: fix ANR caused by calling AMS --- .../owners/ForegroundServiceLifecycleOwner.kt | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/owners/ForegroundServiceLifecycleOwner.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/owners/ForegroundServiceLifecycleOwner.kt index 737403994..c74da4643 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/owners/ForegroundServiceLifecycleOwner.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/owners/ForegroundServiceLifecycleOwner.kt @@ -10,6 +10,7 @@ import android.os.Handler import android.os.Message import android.os.Process import android.util.ArrayMap +import com.tencent.matrix.lifecycle.MatrixLifecycleThread import com.tencent.matrix.lifecycle.StatefulOwner import com.tencent.matrix.util.MatrixLog import com.tencent.matrix.util.safeApply @@ -127,8 +128,10 @@ object ForegroundServiceLifecycleOwner : StatefulOwner() { } STOP_SERVICE -> { ActivityThreadmH?.post { - safeApply(TAG) { - hasForegroundService() + MatrixLifecycleThread.handler.post { + safeApply(TAG) { + hasForegroundService() + } } } } @@ -159,15 +162,17 @@ object ForegroundServiceLifecycleOwner : StatefulOwner() { } private fun checkIfAlreadyForegrounded(componentName: ComponentName) { - safeApply(TAG) { - activityManager?.getRunningServices(Int.MAX_VALUE)?.filter { - it.pid == Process.myPid() - && it.uid == Process.myUid() - && it.service == componentName - && it.foreground - }?.forEach { - MatrixLog.i(TAG, "service turned fg when create: ${it.service}") - fgServiceHandler?.onStartForeground(it.service) + MatrixLifecycleThread.handler.post { + safeApply(TAG) { + activityManager?.getRunningServices(Int.MAX_VALUE)?.filter { + it.pid == Process.myPid() + && it.uid == Process.myUid() + && it.service == componentName + && it.foreground + }?.forEach { + MatrixLog.i(TAG, "service turned fg when create: ${it.service}") + fgServiceHandler?.onStartForeground(it.service) + } } } } From 88cb37f5211f9ae0cd7b0d3366848c15de38b74c Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 2 Jun 2022 16:35:08 +0800 Subject: [PATCH 032/263] Add battery proc jiffies dead thread list --- .../monitor/feature/CompositorTest.java | 29 +++++++++++ .../feature/MonitorFeatureOverAllTest.java | 1 + .../monitor/feature/CompositeMonitors.java | 49 ++++++++++--------- .../feature/JiffiesMonitorFeature.java | 27 ++++++++++ .../monitor/feature/MonitorFeature.java | 22 +++++++-- .../matrix/batterycanary/utils/Function.java | 37 ++++++++++++++ 6 files changed, 138 insertions(+), 27 deletions(-) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/Function.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java index 535d596cc..e0d173a81 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java @@ -260,4 +260,33 @@ public void testSampling() throws InterruptedException { Assert.assertTrue(compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.BatteryTmpSnapshot.class).count > compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class).count); } + + @Test + public void testSamplingStop() throws InterruptedException { + final BatteryMonitorCore monitor = mockMonitor(); + BatteryMonitorPlugin plugin = new BatteryMonitorPlugin(monitor.getConfig()); + Matrix.with().getPlugins().add(plugin); + monitor.enableForegroundLoopCheck(true); + monitor.start(); + + long interval = 100L; + long samplingTime = 1000L; + CompositeMonitors compositeMonitor = new CompositeMonitors(monitor); + compositeMonitor.sample(DeviceStatMonitorFeature.BatteryTmpSnapshot.class, interval); + compositeMonitor.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, interval); + compositeMonitor.sample(DeviceStatMonitorFeature.ChargeWattageSnapshot.class, interval); + compositeMonitor.sample(CpuStatFeature.CpuStateSnapshot.class, interval); + compositeMonitor.sample(JiffiesMonitorFeature.UidJiffiesSnapshot.class, interval); + + compositeMonitor.start(); + Thread.sleep(samplingTime); + compositeMonitor.finish(); + + Thread.sleep(4000L); + Assert.assertEquals(samplingTime/interval, compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.BatteryTmpSnapshot.class).count, 2); + Assert.assertEquals(samplingTime/interval, compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class).count, 2); + Assert.assertEquals(samplingTime/interval, compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.ChargeWattageSnapshot.class).count, 2); + Assert.assertEquals(samplingTime/interval, compositeMonitor.getSamplingResult(CpuStatFeature.CpuStateSnapshot.class).count, 3); + Assert.assertEquals(samplingTime/interval, compositeMonitor.getSamplingResult(JiffiesMonitorFeature.UidJiffiesSnapshot.class).count, 2); + } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java index 2ddb73fd4..0f6590198 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java @@ -81,6 +81,7 @@ public BatteryPrinter attach(BatteryMonitorCore monitorCore) { BatteryPrinter core = super.attach(monitorCore); mCompositeMonitors.sample(DeviceStatMonitorFeature.BatteryTmpSnapshot.class, 100L); mCompositeMonitors.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 100L); + mCompositeMonitors.sample(DeviceStatMonitorFeature.ChargeWattageSnapshot.class, 100L); mCompositeMonitors.sample(CpuStatFeature.CpuStateSnapshot.class, 100L); mCompositeMonitors.sample(JiffiesMonitorFeature.UidJiffiesSnapshot.class, 100L); return core; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 022365dde..292f31c40 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -14,6 +14,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.Consumer; +import com.tencent.matrix.batterycanary.utils.Function; import com.tencent.matrix.util.MatrixLog; import java.util.ArrayList; @@ -22,7 +23,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; import androidx.annotation.CallSuper; import androidx.annotation.NonNull; @@ -468,12 +468,12 @@ protected Snapshot.Sampler statSampler(Class> snapshotClas if (snapshotClass == DeviceStatMonitorFeature.CpuFreqSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler("cpufreq", mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("cpufreq", mMonitor.getHandler(), new Function() { @Override - public Number call() { + public Number apply(Snapshot.Sampler sampler) { DeviceStatMonitorFeature.CpuFreqSnapshot snapshot = feature.currentCpuFreq(); List> list = snapshot.cpuFreqs.getList(); - MatrixLog.i(TAG, "onSampling, cpufreq = " + list); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + list); Collections.sort(list, new Comparator>() { @Override public int compare(DigitEntry o1, DigitEntry o2) { @@ -490,12 +490,12 @@ public int compare(DigitEntry o1, DigitEntry o2) { if (snapshotClass == DeviceStatMonitorFeature.BatteryTmpSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler("batt-temp", mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("batt-temp", mMonitor.getHandler(), new Function() { @Override - public Number call() { + public Number apply(Snapshot.Sampler sampler) { DeviceStatMonitorFeature.BatteryTmpSnapshot snapshot = feature.currentBatteryTemperature(mMonitor.getContext()); Integer value = snapshot.temp.get(); - MatrixLog.i(TAG, "onSampling, batt-temp = " + value); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); return value; } }); @@ -506,11 +506,11 @@ public Number call() { if (snapshotClass == DeviceStatMonitorFeature.ThermalStatSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler("thermal-stat", mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("thermal-stat", mMonitor.getHandler(), new Function() { @Override - public Number call() { + public Number apply(Snapshot.Sampler sampler) { int value = BatteryCanaryUtil.getThermalStat(mMonitor.getContext()); - MatrixLog.i(TAG, "onSampling, thermal-stat = " + value); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); return value; } }); @@ -523,11 +523,11 @@ public Number call() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && feature != null && mMonitor != null) { final Long interval = mSampleRegs.get(snapshotClass); if (interval != null && interval >= 1000L) { - sampler = new Snapshot.Sampler("thermal-headroom", mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("thermal-headroom", mMonitor.getHandler(), new Function() { @Override - public Number call() { + public Number apply(Snapshot.Sampler sampler) { float value = BatteryCanaryUtil.getThermalHeadroom(mMonitor.getContext(), (int) (interval / 1000L)); - MatrixLog.i(TAG, "onSampling, thermal-headroom = " + value); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); return value; } }); @@ -539,11 +539,11 @@ public Number call() { if (snapshotClass == DeviceStatMonitorFeature.ChargeWattageSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler("batt-watt", mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("batt-watt", mMonitor.getHandler(), new Function() { @Override - public Number call() { + public Number apply(Snapshot.Sampler sampler) { int value = BatteryCanaryUtil.getChargingWatt(mMonitor.getContext()); - MatrixLog.i(TAG, "onSampling, batt-watt = " + value); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); return value; } }); @@ -554,17 +554,17 @@ public Number call() { if (snapshotClass == CpuStatFeature.CpuStateSnapshot.class) { final CpuStatFeature feature = getFeature(CpuStatFeature.class); if (feature != null && feature.isSupported() && mMonitor != null) { - sampler = new Snapshot.Sampler("cpu-stat", mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("cpu-stat", mMonitor.getHandler(), new Function() { @Override - public Number call() { + public Number apply(Snapshot.Sampler sampler) { CpuStatFeature.CpuStateSnapshot snapshot = feature.currentCpuStateSnapshot(); for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { Snapshot.Entry.ListEntry> item = snapshot.cpuCoreStates.get(i); - MatrixLog.i(TAG, "onSampling, cpuCore" + i + " = " + item.getList()); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " cpuCore" + i + ", val = " + item.getList()); } for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { Snapshot.Entry.ListEntry> item = snapshot.procCpuCoreStates.get(i); - MatrixLog.i(TAG, "onSampling, procCpuCluster" + i + " = " + item.getList()); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " procCpuCluster" + i + ", val = " + item.getList()); } return snapshot.totalProcCpuJiffies(); } @@ -576,19 +576,20 @@ public Number call() { if (snapshotClass == JiffiesMonitorFeature.UidJiffiesSnapshot.class) { final JiffiesMonitorFeature feature = getFeature(JiffiesMonitorFeature.class); if (feature != null && mMonitor != null) { - sampler = new Snapshot.Sampler("uid-jiffies", mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler("uid-jiffies", mMonitor.getHandler(), new Function() { JiffiesMonitorFeature.UidJiffiesSnapshot mLastSnapshot; @Override - public Number call() { + public Number apply(Snapshot.Sampler sampler) { JiffiesMonitorFeature.UidJiffiesSnapshot curr = feature.currentUidJiffiesSnapshot(); if (mLastSnapshot != null) { Delta delta = curr.diff(mLastSnapshot); long minute = Math.max(1, delta.during / BatteryCanaryUtil.ONE_MIN); long avgUidJiffies = delta.dlt.totalUidJiffies.get() / minute; - MatrixLog.i(TAG, "onSampling, avgUidJiffies = " + avgUidJiffies + ", minute = " + minute); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgUidJiffies" + ", val = " + avgUidJiffies + ", minute = " + minute); + for (Delta item : delta.dlt.pidDeltaJiffiesList) { long avgPidJiffies = item.dlt.totalJiffies.get() / minute; - MatrixLog.i(TAG, "onSampling, avgPidJiffies = " + avgPidJiffies + ", minute = " + minute + ", name = " + item.dlt.name); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgPidJiffies" + ", val = " + avgUidJiffies + ", minute = " + minute + ", name = " + item.dlt.name); } return avgUidJiffies; } else { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java index c23ce151c..70430274a 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java @@ -276,9 +276,11 @@ public static JiffiesSnapshot currentJiffiesSnapshot(ProcessInfo processInfo, bo public DigitEntry totalJiffies; public ListEntry threadEntries; public DigitEntry threadNum; + public ListEntry deadThreadEntries; private JiffiesSnapshot() { isNewAdded = false; + deadThreadEntries = ListEntry.ofEmpty(); } @Override @@ -294,6 +296,7 @@ protected JiffiesSnapshot computeDelta() { delta.threadNum = Differ.DigitDiffer.globalDiff(bgn.threadNum, end.threadNum); delta.threadEntries = ListEntry.ofEmpty(); + // for Existing threads if (end.threadEntries.getList().size() > 0) { List deltaThreadEntries = new ArrayList<>(); for (ThreadJiffiesSnapshot endRecord : end.threadEntries.getList()) { @@ -328,6 +331,30 @@ public int compare(ThreadJiffiesSnapshot o1, ThreadJiffiesSnapshot o2) { delta.threadEntries = ListEntry.of(deltaThreadEntries); } } + + // for Dead threads + if (bgn.threadEntries.getList().size() > 0) { + List deadThreadEntries = Collections.emptyList(); + for (ThreadJiffiesSnapshot bgn : bgn.threadEntries.getList()) { + boolean isDead = true; + for (ThreadJiffiesSnapshot exist : delta.threadEntries.getList()) { + if (exist.tid == bgn.tid) { + isDead = false; + break; + } + } + if (isDead) { + if (deadThreadEntries.isEmpty()) { + deadThreadEntries = new ArrayList<>(); + } + deadThreadEntries.add(bgn); + } + } + if (!deadThreadEntries.isEmpty()) { + delta.deadThreadEntries = ListEntry.of(deadThreadEntries); + } + } + return delta; } }; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index 6eeec8978..1c4453f55 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -5,6 +5,7 @@ import android.os.SystemClock; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; +import com.tencent.matrix.batterycanary.utils.Function; import com.tencent.matrix.util.MatrixLog; import java.util.ArrayList; @@ -423,14 +424,14 @@ public static class Sampler { final String mTag; final Handler mHandler; - final Callable mSamplingBlock; + final Function mSamplingBlock; private final Runnable mSamplingTask = new Runnable() { @Override public void run() { try { MatrixLog.i(TAG, "onSampling" + mTag + ", count = " + mCount); - Number currSample = mSamplingBlock.call(); + Number currSample = mSamplingBlock.apply(Sampler.this); if (!currSample.equals(INVALID)) { mSampleLst = currSample.doubleValue(); mCount++; @@ -473,7 +474,22 @@ public Sampler(Handler handler, Callable onSampling) { this("dft", handler, onSampling); } - public Sampler(String tag, Handler handler, Callable onSampling) { + public Sampler(String tag, Handler handler, final Callable onSampling) { + mTag = tag; + mHandler = handler; + mSamplingBlock = new Function() { + @Override + public Number apply(Sampler sampler) { + try { + return onSampling.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + } + + public Sampler(String tag, Handler handler, Function onSampling) { mTag = tag; mHandler = handler; mSamplingBlock = onSampling; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/Function.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/Function.java new file mode 100644 index 000000000..0886b57dd --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/Function.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.tencent.matrix.batterycanary.utils; + +/** + * Compat version of {@link java.util.function.Function} + * + * @param the type of the input to the function + * @param the type of the result of the function + * @since 1.8 + */ +public interface Function { + R apply(T t); +} + From f81bf8f0d15143b8d26e9f4fb22d19b6c477e28f Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 2 Jun 2022 16:59:24 +0800 Subject: [PATCH 033/263] Append --- .../batterycanary/monitor/feature/MonitorFeature.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index 1c4453f55..5efe87ecd 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -495,6 +495,14 @@ public Sampler(String tag, Handler handler, Function mSamplingBlock = onSampling; } + public String getTag() { + return mTag; + } + + public int getCount() { + return mCount; + } + public void setInterval(long interval) { if (interval > 0) { mInterval = interval; From 599e1fa73bdaa132fb628289d272f05ce7e63542 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 2 Jun 2022 17:51:01 +0800 Subject: [PATCH 034/263] Update battery proc jiffies dump with remaining threads --- .../monitor/BatteryMonitorCallback.java | 33 ++++++++++++------- .../monitor/feature/CompositeMonitors.java | 6 ++-- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java index d813f449d..53d3f37c1 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java @@ -432,22 +432,31 @@ protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, final printer.writeLine("desc", "(status)name(tid)\tavg/total"); printer.writeLine("inc_thread_num", String.valueOf(delta.dlt.threadNum.get())); printer.writeLine("cur_thread_num", String.valueOf(delta.end.threadNum.get())); - for (ThreadJiffiesEntry threadJiffies : delta.dlt.threadEntries.getList().subList(0, Math.min(delta.dlt.threadEntries.getList().size(), 8))) { + int toppingCount = 8; + long remainJffies = 0; + for (int i = 0; i < delta.dlt.threadEntries.getList().size(); i++) { + ThreadJiffiesEntry threadJiffies = delta.dlt.threadEntries.getList().get(0); long entryJffies = threadJiffies.get(); - printer.append("| -> (").append(threadJiffies.isNewAdded ? "+" : "~").append("/").append(threadJiffies.stat).append(")") - .append(threadJiffies.name).append("(").append(threadJiffies.tid).append(")\t") - .append(entryJffies / minute).append("/").append(entryJffies).append("\tjiffies") - .append("\n"); - - // List threadTasks = tasks.get(threadJiffies.tid); - // if (null != threadTasks && !threadTasks.isEmpty()) { - // for (LooperTaskMonitorFeature.TaskTraceInfo task : threadTasks.subList(0, Math.min(3, threadTasks.size()))) { - // printer.append("|\t\t").append(task).append("\n"); - // } - // } + if (i < toppingCount) { + printer.append("| -> (").append(threadJiffies.isNewAdded ? "+" : "~").append("/").append(threadJiffies.stat).append(")") + .append(threadJiffies.name).append("(").append(threadJiffies.tid).append(")\t") + .append(entryJffies / minute).append("/").append(entryJffies).append("\tjiffies") + .append("\n"); + } else { + remainJffies += entryJffies; + } } printer.append("|\t\t......\n"); + if (remainJffies > 0) { + printer.append("| -> R/R)") + .append("REMAINS").append("(").append(delta.dlt.threadEntries.getList().size() - toppingCount).append(")\t") + .append(remainJffies / minute).append("/").append(remainJffies).append("\tjiffies") + .append("\n"); + } if (avgJiffies > 1000L || !delta.isValid()) { + // Proc CPU Load = avgJiffies / 6000L + // 1000L -> 16.6% + // 1200L -> 20.0% printer.append("| ").append(avgJiffies > 1000L ? " #overHeat" : "").append(!delta.isValid() ? " #invalid" : "").append("\n"); } return true; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 292f31c40..0e5ab0fc8 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -566,7 +566,7 @@ public Number apply(Snapshot.Sampler sampler) { Snapshot.Entry.ListEntry> item = snapshot.procCpuCoreStates.get(i); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " procCpuCluster" + i + ", val = " + item.getList()); } - return snapshot.totalProcCpuJiffies(); + return 0; } }); mSamplers.put(snapshotClass, sampler); @@ -585,11 +585,11 @@ public Number apply(Snapshot.Sampler sampler) { Delta delta = curr.diff(mLastSnapshot); long minute = Math.max(1, delta.during / BatteryCanaryUtil.ONE_MIN); long avgUidJiffies = delta.dlt.totalUidJiffies.get() / minute; - MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgUidJiffies" + ", val = " + avgUidJiffies + ", minute = " + minute); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgUidJiffies, val = " + avgUidJiffies + ", minute = " + minute); for (Delta item : delta.dlt.pidDeltaJiffiesList) { long avgPidJiffies = item.dlt.totalJiffies.get() / minute; - MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgPidJiffies" + ", val = " + avgUidJiffies + ", minute = " + minute + ", name = " + item.dlt.name); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgPidJiffies, val = " + avgUidJiffies + ", minute = " + minute + ", name = " + item.dlt.name); } return avgUidJiffies; } else { From ec361da25e1c8d017f53c362782330a47afd944c Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 2 Jun 2022 18:05:31 +0800 Subject: [PATCH 035/263] Add battery traffic sampling --- .../feature/MonitorFeatureOverAllTest.java | 1 + .../monitor/feature/CompositeMonitors.java | 23 +++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java index 0f6590198..80da2307f 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureOverAllTest.java @@ -84,6 +84,7 @@ public BatteryPrinter attach(BatteryMonitorCore monitorCore) { mCompositeMonitors.sample(DeviceStatMonitorFeature.ChargeWattageSnapshot.class, 100L); mCompositeMonitors.sample(CpuStatFeature.CpuStateSnapshot.class, 100L); mCompositeMonitors.sample(JiffiesMonitorFeature.UidJiffiesSnapshot.class, 100L); + mCompositeMonitors.sample(TrafficMonitorFeature.RadioStatSnapshot.class, 100L); return core; } }) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 0e5ab0fc8..374e4a196 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -586,10 +586,9 @@ public Number apply(Snapshot.Sampler sampler) { long minute = Math.max(1, delta.during / BatteryCanaryUtil.ONE_MIN); long avgUidJiffies = delta.dlt.totalUidJiffies.get() / minute; MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgUidJiffies, val = " + avgUidJiffies + ", minute = " + minute); - for (Delta item : delta.dlt.pidDeltaJiffiesList) { long avgPidJiffies = item.dlt.totalJiffies.get() / minute; - MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgPidJiffies, val = " + avgUidJiffies + ", minute = " + minute + ", name = " + item.dlt.name); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgPidJiffies, val = " + avgPidJiffies + ", minute = " + minute + ", name = " + item.dlt.name); } return avgUidJiffies; } else { @@ -602,6 +601,26 @@ public Number apply(Snapshot.Sampler sampler) { } return sampler; } + if (snapshotClass == TrafficMonitorFeature.RadioStatSnapshot.class) { + final TrafficMonitorFeature feature = getFeature(TrafficMonitorFeature.class); + if (feature != null && mMonitor != null) { + sampler = new MonitorFeature.Snapshot.Sampler("traffic", mMonitor.getHandler(), new Function() { + @Override + public Number apply(Snapshot.Sampler sampler) { + TrafficMonitorFeature.RadioStatSnapshot snapshot = feature.currentRadioSnapshot(mMonitor.getContext()); + if (snapshot != null) { + MatrixLog.i(TAG, "onSampling " + sampler.getCount() + " " + sampler.getTag() + "wifiRx, val = " + snapshot.wifiRxBytes); + MatrixLog.i(TAG, "onSampling " + sampler.getCount() + " " + sampler.getTag() + "wifiTx, val = " + snapshot.wifiTxBytes); + MatrixLog.i(TAG, "onSampling " + sampler.getCount() + " " + sampler.getTag() + "mobileRx, val = " + snapshot.mobileRxBytes); + MatrixLog.i(TAG, "onSampling " + sampler.getCount() + " " + sampler.getTag() + "mobileTx, val = " + snapshot.mobileTxBytes); + } + return 0; + } + }); + mSamplers.put(snapshotClass, sampler); + } + return sampler; + } return null; } From 22bc9a230ba09e9bec14fb52e4f5a3159a2d71b9 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 3 Jun 2022 16:26:45 +0800 Subject: [PATCH 036/263] Append --- .../batterycanary/monitor/BatteryMonitorCallback.java | 2 +- .../batterycanary/monitor/feature/CompositeMonitors.java | 9 +++++---- .../batterycanary/monitor/feature/MonitorFeature.java | 1 - 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java index 53d3f37c1..0845d75a7 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java @@ -435,7 +435,7 @@ protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, final int toppingCount = 8; long remainJffies = 0; for (int i = 0; i < delta.dlt.threadEntries.getList().size(); i++) { - ThreadJiffiesEntry threadJiffies = delta.dlt.threadEntries.getList().get(0); + ThreadJiffiesEntry threadJiffies = delta.dlt.threadEntries.getList().get(i); long entryJffies = threadJiffies.get(); if (i < toppingCount) { printer.append("| -> (").append(threadJiffies.isNewAdded ? "+" : "~").append("/").append(threadJiffies.stat).append(")") diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 374e4a196..d8ef9d9ce 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -590,6 +590,7 @@ public Number apply(Snapshot.Sampler sampler) { long avgPidJiffies = item.dlt.totalJiffies.get() / minute; MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgPidJiffies, val = " + avgPidJiffies + ", minute = " + minute + ", name = " + item.dlt.name); } + mLastSnapshot = curr; return avgUidJiffies; } else { mLastSnapshot = curr; @@ -609,10 +610,10 @@ public Number apply(Snapshot.Sampler sampler) { public Number apply(Snapshot.Sampler sampler) { TrafficMonitorFeature.RadioStatSnapshot snapshot = feature.currentRadioSnapshot(mMonitor.getContext()); if (snapshot != null) { - MatrixLog.i(TAG, "onSampling " + sampler.getCount() + " " + sampler.getTag() + "wifiRx, val = " + snapshot.wifiRxBytes); - MatrixLog.i(TAG, "onSampling " + sampler.getCount() + " " + sampler.getTag() + "wifiTx, val = " + snapshot.wifiTxBytes); - MatrixLog.i(TAG, "onSampling " + sampler.getCount() + " " + sampler.getTag() + "mobileRx, val = " + snapshot.mobileRxBytes); - MatrixLog.i(TAG, "onSampling " + sampler.getCount() + " " + sampler.getTag() + "mobileTx, val = " + snapshot.mobileTxBytes); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " wifiRx, val = " + snapshot.wifiRxBytes); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " wifiTx, val = " + snapshot.wifiTxBytes); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " mobileRx, val = " + snapshot.mobileRxBytes); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " mobileTx, val = " + snapshot.mobileTxBytes); } return 0; } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index 5efe87ecd..f9ebc3776 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -430,7 +430,6 @@ public static class Sampler { @Override public void run() { try { - MatrixLog.i(TAG, "onSampling" + mTag + ", count = " + mCount); Number currSample = mSamplingBlock.apply(Sampler.this); if (!currSample.equals(INVALID)) { mSampleLst = currSample.doubleValue(); From 5bc5a64580f2f12d00d9268bbef9396224d3055e Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 3 Jun 2022 16:27:43 +0800 Subject: [PATCH 037/263] Add debug codes --- .../batterycanary/monitor/feature/CompositeMonitors.java | 6 ++++++ .../monitor/feature/JiffiesMonitorFeature.java | 1 + 2 files changed, 7 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index d8ef9d9ce..2148fc5d3 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -82,6 +82,7 @@ public String getScope() { @CallSuper public void clear() { + MatrixLog.i(TAG, hashCode() + " #clear: " + mScope); mBgnSnapshots.clear(); mDeltas.clear(); mSamplers.clear(); @@ -91,6 +92,7 @@ public void clear() { @CallSuper public CompositeMonitors fork() { + MatrixLog.i(TAG, hashCode() + " #fork: " + mScope); CompositeMonitors that = new CompositeMonitors(mMonitor, mScope); that.mBgnMillis = this.mBgnMillis; that.mAppStats = this.mAppStats; @@ -291,6 +293,7 @@ public CompositeMonitors sample(Class> snapshotClass, long } public void start() { + MatrixLog.i(TAG, hashCode() + " #start: " + mScope); mAppStats = null; mBgnMillis = SystemClock.uptimeMillis(); configureBgnSnapshots(); @@ -298,6 +301,7 @@ public void start() { } public void finish() { + MatrixLog.i(TAG, hashCode() + " #finish: " + mScope); configureEndDeltas(); collectStacks(); configureSampleResults(); @@ -454,6 +458,7 @@ protected void configureSamplers() { protected void configureSampleResults() { for (Map.Entry>, Snapshot.Sampler> item : mSamplers.entrySet()) { + MatrixLog.i(TAG, hashCode() + " " + item.getValue().getTag() + " #pause: " + mScope); item.getValue().pause(); Snapshot.Sampler.Result result = item.getValue().getResult(); if (result != null) { @@ -473,6 +478,7 @@ protected Snapshot.Sampler statSampler(Class> snapshotClas public Number apply(Snapshot.Sampler sampler) { DeviceStatMonitorFeature.CpuFreqSnapshot snapshot = feature.currentCpuFreq(); List> list = snapshot.cpuFreqs.getList(); + MatrixLog.i(TAG, CompositeMonitors.this.hashCode() + " #onSampling: " + mScope); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + list); Collections.sort(list, new Comparator>() { @Override diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java index 70430274a..49f2090b2 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java @@ -509,6 +509,7 @@ public static UidJiffiesSnapshot of(Context context, boolean isStatPidProc) { int pid = item.first; String procName = String.valueOf(item.second); if (ProcStatUtil.exists(pid)) { + MatrixLog.i(TAG, " #exits: " + "/proc/" + pid + "/stat"); JiffiesSnapshot snapshot = JiffiesSnapshot.currentJiffiesSnapshot(ProcessInfo.getProcessInfo(pid), isStatPidProc); snapshot.name = TopThreadIndicator.getProcSuffix(procName); sum += snapshot.totalJiffies.get(); From 472053aaf5c3e9fdcb4415ebed5ac4c2a56c20c6 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Sun, 5 Jun 2022 15:20:11 +0800 Subject: [PATCH 038/263] Fix npe crash --- .../batterycanary/monitor/feature/JiffiesMonitorFeature.java | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java index 49f2090b2..ca68d54cf 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java @@ -550,6 +550,7 @@ protected UidJiffiesSnapshot computeDelta() { empty.totalJiffies = DigitEntry.of(0L); empty.threadEntries = ListEntry.ofEmpty(); empty.threadNum = DigitEntry.of(0); + last = empty; } Delta deltaPidJiffies = end.diff(last); delta.pidDeltaJiffiesList.add(deltaPidJiffies); From ff54030648953e9087b0e6b66471abb847f77515 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 2 Jun 2022 17:39:15 +0800 Subject: [PATCH 039/263] add HprofFileManager with lru --- .../matrix/resource/ResourcePlugin.java | 2 + .../resource/dumper/DumpStorageManager.java | 2 +- .../resource/dumper/HprofFileManager.kt | 114 ++++++++++++++++++ .../resource/processor/BaseLeakProcessor.java | 1 + .../processor/NativeForkAnalyzeProcessor.kt | 2 +- 5 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ResourcePlugin.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ResourcePlugin.java index da2c97ceb..3a4187dd1 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ResourcePlugin.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ResourcePlugin.java @@ -25,6 +25,7 @@ import com.tencent.matrix.plugin.PluginListener; import com.tencent.matrix.resource.config.ResourceConfig; import com.tencent.matrix.resource.config.SharePluginInfo; +import com.tencent.matrix.resource.dumper.HprofFileManager; import com.tencent.matrix.resource.processor.BaseLeakProcessor; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; import com.tencent.matrix.util.MatrixLog; @@ -68,6 +69,7 @@ public void init(Application app, PluginListener listener) { return; } mWatcher = new ActivityRefWatcher(app, this); + HprofFileManager.INSTANCE.checkExpiredFile(); } @Override diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/DumpStorageManager.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/DumpStorageManager.java index 5d0db2cc7..aae0f149d 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/DumpStorageManager.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/DumpStorageManager.java @@ -33,7 +33,7 @@ *

* This class is ported from LeakCanary. */ - +@Deprecated public class DumpStorageManager { private static final String TAG = "Matrix.DumpStorageManager"; diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt new file mode 100644 index 000000000..27fec0cd0 --- /dev/null +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt @@ -0,0 +1,114 @@ +package com.tencent.matrix.resource.dumper + +import android.os.Process +import com.tencent.matrix.Matrix +import com.tencent.matrix.util.MatrixLog +import com.tencent.matrix.util.MatrixUtil +import com.tencent.matrix.util.safeApply +import java.io.File +import java.io.FileNotFoundException +import java.text.SimpleDateFormat +import java.util.* +import java.util.concurrent.TimeUnit + +/** + * manage hprof files with LRU + */ +object HprofFileManager { + + private const val TAG = "Matrix.HprofFileManager" + + private const val MAX_FILE_COUNT = 10 + private const val MIN_FREE_SPACE = 20 * 1024 * 1024 * 1024L // 20G + + private val EXPIRED_TIME_MILLIS = TimeUnit.DAYS.toMillis(7) + + private val hprofStorageDir by lazy { File(Matrix.with().application.cacheDir.absolutePath + "/hprofs") } + + private val format by lazy { SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US) } + + fun checkExpiredFile() { + safeApply(TAG) { + val current = System.currentTimeMillis() + if (hprofStorageDir.exists() && hprofStorageDir.isDirectory) { + hprofStorageDir.listFiles { it: File -> + current - it.lastModified() > EXPIRED_TIME_MILLIS + }?.forEach { + if (it.exists()) { + it.delete() + } + } + } + } + } + + @Throws(FileNotFoundException::class) + fun prepareHprofFile(prefix: String = ""): File { + hprofStorageDir.prepare() + return File(hprofStorageDir, getHprofFileName(prefix)) + } + + fun clearAll() { + hprofStorageDir.deleteRecursively() + } + + private fun File.prepare() { + reserve() + makeSureEnoughSpace() + } + + private fun File.reserve() { + if (!exists() && (!mkdirs() || !canWrite())) { + "fialed to create new hprof file since path: $absolutePath is not writable".let { + MatrixLog.e(TAG, it) + throw FileNotFoundException(it) + } + } + } + + private fun File.makeSureEnoughSpace() { + if (!isDirectory) { + return + } + lru() + if (freeSpace < MIN_FREE_SPACE) { + listFiles()?.forEach { it.delete() } + } + if (freeSpace < MIN_FREE_SPACE) { + throw FileNotFoundException("free space less than $MIN_FREE_SPACE, skip dump hprof") + } + } + + private fun File.lru() { + if (!isDirectory) { + return + } + val files = listFiles() ?: return + files.sortBy { it.lastModified() } + files.forEach { + MatrixLog.d(TAG, "==> list sorted: ${it.absolutePath}, last mod = ${it.lastModified()}") + } + if (files.size >= MAX_FILE_COUNT) { + files.take(files.size - MAX_FILE_COUNT + 1).forEach { + it.delete() + } + } + } + + private val processSuffix by lazy { + if (MatrixUtil.isInMainProcess(Matrix.with().application)) { + "Main" + } else { + val split = + MatrixUtil.getProcessName(Matrix.with().application).split(":").toTypedArray() + if (split.size > 1) { + split[1] + } else { + "unknown" + } + } + } + + private fun getHprofFileName(prefix: String) = + "$prefix-${processSuffix}-${Process.myPid()}-${format.format(Calendar.getInstance().time)}.hprof" +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java index bcfab87de..6d4f8020c 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java @@ -44,6 +44,7 @@ public BaseLeakProcessor(ActivityRefWatcher watcher) { public abstract boolean process(DestroyedActivityInfo destroyedActivityInfo); + @Deprecated public DumpStorageManager getDumpStorageManager() { if (mDumpStorageManager == null) { mDumpStorageManager = new DumpStorageManager(mWatcher.getContext()); diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index a850925d6..0efb6bdb6 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -194,7 +194,7 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso val hprof = dumpStorageManager.newHprofFile() ?: run { publishIssue( - SharePluginInfo.IssueType.LEAK_FOUND, + SharePluginInfo.IssueType.LEAK_FOUND, // ? should be ERR_FILE_NOT_FOUND ResourceConfig.DumpMode.FORK_ANALYSE, "[unknown]", "[unknown]", "Failed to create hprof file.", "0" ) From dec9536a64f04d7bc0ac55d8eb20a9418342a3a2 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Sun, 5 Jun 2022 16:55:11 +0800 Subject: [PATCH 040/263] resource-plugin: replace DumpStorageManager with HprofFileManager --- .../matrix/resource/CanaryWorkerService.java | 5 +- .../resource/dumper/AndroidHeapDumper.java | 16 ++- .../resource/dumper/DumpStorageManager.java | 111 ------------------ .../resource/processor/BaseLeakProcessor.java | 11 +- .../processor/ForkAnalyseProcessor.java | 9 +- .../resource/processor/ForkDumpProcessor.java | 9 +- .../processor/LazyForkAnalyzeProcessor.java | 9 +- .../processor/ManualDumpProcessor.java | 9 +- .../processor/NativeForkAnalyzeProcessor.kt | 4 +- 9 files changed, 48 insertions(+), 135 deletions(-) delete mode 100644 matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/DumpStorageManager.java diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/CanaryWorkerService.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/CanaryWorkerService.java index 6322137d1..e4943e591 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/CanaryWorkerService.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/CanaryWorkerService.java @@ -25,7 +25,6 @@ import com.tencent.matrix.Matrix; import com.tencent.matrix.resource.analyzer.model.HeapDump; -import com.tencent.matrix.resource.dumper.DumpStorageManager; import com.tencent.matrix.resource.hproflib.HprofBufferShrinker; import com.tencent.matrix.util.MatrixLog; @@ -126,9 +125,9 @@ private void doShrinkHprofAndReport(HeapDump heapDump) { private String getShrinkHprofName(File origHprof) { final String origHprofName = origHprof.getName(); - final int extPos = origHprofName.indexOf(DumpStorageManager.HPROF_EXT); + final int extPos = origHprofName.indexOf(".hprof"); final String namePrefix = origHprofName.substring(0, extPos); - return namePrefix + "_shrink" + DumpStorageManager.HPROF_EXT; + return namePrefix + "_shrink.hprof"; } private String getResultZipName(String prefix) { diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/AndroidHeapDumper.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/AndroidHeapDumper.java index 920bf4580..9532af9f7 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/AndroidHeapDumper.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/AndroidHeapDumper.java @@ -30,6 +30,7 @@ import com.tencent.matrix.util.MatrixLog; import java.io.File; +import java.io.FileNotFoundException; import java.util.concurrent.TimeUnit; /** @@ -42,25 +43,28 @@ public class AndroidHeapDumper { private static final String TAG = "Matrix.AndroidHeapDumper"; private final Context mContext; - private final DumpStorageManager mDumpStorageManager; private final Handler mMainHandler; public interface HeapDumpHandler { void process(HeapDump result); } - public AndroidHeapDumper(Context context, DumpStorageManager dumpStorageManager) { - this(context, dumpStorageManager, new Handler(Looper.getMainLooper())); + public AndroidHeapDumper(Context context) { + this(context, new Handler(Looper.getMainLooper())); } - public AndroidHeapDumper(Context context, DumpStorageManager dumpStorageManager, Handler mainHandler) { + public AndroidHeapDumper(Context context, Handler mainHandler) { mContext = context; - mDumpStorageManager = dumpStorageManager; mMainHandler = mainHandler; } public File dumpHeap(boolean isShowToast) { - final File hprofFile = mDumpStorageManager.newHprofFile(); + File hprofFile = null; + try { + hprofFile = HprofFileManager.INSTANCE.prepareHprofFile(""); + } catch (FileNotFoundException e) { + MatrixLog.printErrStackTrace(TAG, e, ""); + } if (null == hprofFile) { MatrixLog.w(TAG, "hprof file is null."); diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/DumpStorageManager.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/DumpStorageManager.java deleted file mode 100644 index aae0f149d..000000000 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/DumpStorageManager.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2015 Square, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.tencent.matrix.resource.dumper; - -import android.content.Context; -import android.os.Environment; -import android.os.Process; - -import com.tencent.matrix.util.MatrixLog; -import com.tencent.matrix.util.MatrixUtil; - -import java.io.File; -import java.io.FilenameFilter; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * Created by tangyinsheng on 2017/6/2. - *

- * This class is ported from LeakCanary. - */ -@Deprecated -public class DumpStorageManager { - private static final String TAG = "Matrix.DumpStorageManager"; - - public static final String HPROF_EXT = ".hprof"; - - public static final int DEFAULT_MAX_STORED_HPROF_FILECOUNT = 5; - - protected final Context mContext; - 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; - } - - public File newHprofFile() { - final File storageDir = prepareStorageDirectory(); - if (storageDir == null) { - return null; - } - 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; - } -} diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java index 6d4f8020c..906463306 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java @@ -16,7 +16,6 @@ import com.tencent.matrix.resource.config.ResourceConfig; import com.tencent.matrix.resource.config.SharePluginInfo; import com.tencent.matrix.resource.dumper.AndroidHeapDumper; -import com.tencent.matrix.resource.dumper.DumpStorageManager; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; import com.tencent.matrix.util.MatrixLog; @@ -34,7 +33,6 @@ public abstract class BaseLeakProcessor { private final ActivityRefWatcher mWatcher; - private DumpStorageManager mDumpStorageManager; private AndroidHeapDumper mHeapDumper; private AndroidHeapDumper.HeapDumpHandler mHeapDumpHandler; @@ -45,16 +43,9 @@ public BaseLeakProcessor(ActivityRefWatcher watcher) { public abstract boolean process(DestroyedActivityInfo destroyedActivityInfo); @Deprecated - 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()); + mHeapDumper = new AndroidHeapDumper(mWatcher.getContext()); } return mHeapDumper; } diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java index 96fc07404..4aca11a21 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java @@ -7,10 +7,12 @@ import com.tencent.matrix.resource.analyzer.model.DestroyedActivityInfo; import com.tencent.matrix.resource.config.ResourceConfig; import com.tencent.matrix.resource.config.SharePluginInfo; +import com.tencent.matrix.resource.dumper.HprofFileManager; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; import com.tencent.matrix.util.MatrixLog; import java.io.File; +import java.io.FileNotFoundException; /** * HPROF file analysis processor using fork dump. @@ -57,7 +59,12 @@ private boolean dumpAndAnalyse(String activity, String key) { final long dumpStart = System.currentTimeMillis(); - final File hprof = getDumpStorageManager().newHprofFile(); + File hprof = null; + try { + hprof = HprofFileManager.INSTANCE.prepareHprofFile("FAP"); + } catch (FileNotFoundException e) { + MatrixLog.printErrStackTrace(TAG, e , ""); + } if (hprof != null) { if (!MemoryUtil.dump(hprof.getPath(), 600)) { diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java index 1b79092aa..2969889d1 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java @@ -6,10 +6,12 @@ import com.tencent.matrix.resource.analyzer.model.DestroyedActivityInfo; import com.tencent.matrix.resource.analyzer.model.HeapDump; import com.tencent.matrix.resource.config.ResourceConfig; +import com.tencent.matrix.resource.dumper.HprofFileManager; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; import com.tencent.matrix.util.MatrixLog; import java.io.File; +import java.io.FileNotFoundException; /** * HPROF file dump processor using fork dump. @@ -34,7 +36,12 @@ public boolean process(DestroyedActivityInfo destroyedActivityInfo) { final long dumpStart = System.currentTimeMillis(); - final File hprof = getDumpStorageManager().newHprofFile(); + File hprof = null; + try { + hprof = HprofFileManager.INSTANCE.prepareHprofFile("FDP"); + } catch (FileNotFoundException e) { + MatrixLog.printErrStackTrace(TAG, e , ""); + } if (hprof == null) { MatrixLog.e(TAG, "cannot create hprof file, just ignore"); diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java index 4a9265229..c088818dd 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java @@ -11,11 +11,13 @@ import com.tencent.matrix.resource.analyzer.model.DestroyedActivityInfo; import com.tencent.matrix.resource.config.ResourceConfig; import com.tencent.matrix.resource.config.SharePluginInfo; +import com.tencent.matrix.resource.dumper.HprofFileManager; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; import com.tencent.matrix.util.MatrixHandlerThread; import com.tencent.matrix.util.MatrixLog; import java.io.File; +import java.io.FileNotFoundException; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; @@ -138,7 +140,12 @@ private boolean dumpAndAnalyse(String activity, String key) { final long dumpStart = System.currentTimeMillis(); - final File hprof = getDumpStorageManager().newHprofFile(); + File hprof = null; + try { + hprof = HprofFileManager.INSTANCE.prepareHprofFile("LFAP"); + } catch (FileNotFoundException e) { + MatrixLog.printErrStackTrace(TAG, e , ""); + } if (hprof != null) { if (!MemoryUtil.dump(hprof.getPath(), 600)) { diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java index ee3d295ff..ad939f87c 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java @@ -16,12 +16,14 @@ import com.tencent.matrix.resource.analyzer.model.DestroyedActivityInfo; import com.tencent.matrix.resource.config.ResourceConfig; import com.tencent.matrix.resource.config.SharePluginInfo; +import com.tencent.matrix.resource.dumper.HprofFileManager; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; import com.tencent.matrix.util.MatrixHandlerThread; import com.tencent.matrix.util.MatrixLog; import com.tencent.matrix.util.MatrixUtil; import java.io.File; +import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -173,7 +175,12 @@ private ManualDumpData dumpAndAnalyse(String activity, String key) { getWatcher().triggerGc(); - File file = getDumpStorageManager().newHprofFile(); + File file = null; + try { + file = HprofFileManager.INSTANCE.prepareHprofFile("MDP"); + } catch (FileNotFoundException e) { + MatrixLog.printErrStackTrace(TAG, e , ""); + } final ActivityLeakResult result = MemoryUtil.dumpAndAnalyze(file.getAbsolutePath(), key, 600); if (result.mLeakFound) { final String leakChain = result.toString(); diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index 0efb6bdb6..bb1101213 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -8,9 +8,11 @@ import com.tencent.matrix.resource.MemoryUtil import com.tencent.matrix.resource.analyzer.model.DestroyedActivityInfo import com.tencent.matrix.resource.config.ResourceConfig import com.tencent.matrix.resource.config.SharePluginInfo +import com.tencent.matrix.resource.dumper.HprofFileManager import com.tencent.matrix.resource.watcher.ActivityRefWatcher import com.tencent.matrix.util.MatrixLog import com.tencent.matrix.util.MatrixUtil +import com.tencent.matrix.util.safeLetOrNull import java.io.File import java.util.* import java.util.concurrent.Executors @@ -192,7 +194,7 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso override fun process(destroyedActivityInfo: DestroyedActivityInfo): Boolean { - val hprof = dumpStorageManager.newHprofFile() ?: run { + val hprof = safeLetOrNull { HprofFileManager.prepareHprofFile("NFAP") } ?: run { publishIssue( SharePluginInfo.IssueType.LEAK_FOUND, // ? should be ERR_FILE_NOT_FOUND ResourceConfig.DumpMode.FORK_ANALYSE, From 8ca2df570d912e2dfa7d62bc046461e36cc3630e Mon Sep 17 00:00:00 2001 From: yvesluo Date: Sun, 5 Jun 2022 17:45:35 +0800 Subject: [PATCH 041/263] resource-plugin: fix duplicated analyse after OOM --- .../resource/processor/NativeForkAnalyzeProcessor.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index bb1101213..04b3e16a2 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -12,6 +12,7 @@ import com.tencent.matrix.resource.dumper.HprofFileManager import com.tencent.matrix.resource.watcher.ActivityRefWatcher import com.tencent.matrix.util.MatrixLog import com.tencent.matrix.util.MatrixUtil +import com.tencent.matrix.util.safeLet import com.tencent.matrix.util.safeLetOrNull import java.io.File import java.util.* @@ -147,7 +148,12 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso if (result.mFailure != null) { historyFailure.add(result.mFailure.toString()) retryCount++ - result = analyze(hprof, key) + val cpy = HprofFileManager.prepareHprofFile("RETRY") // prevent duplicated analyse after OOM + hprof.copyTo(cpy, true) + hprof.deleteIfExist() + safeLet({ + result = analyze(cpy, key) // if crashed, the copied file could be auto-cleared by HprofFileManager later (lru or expired) + }, success = { cpy.deleteIfExist() }, failed = { cpy.deleteIfExist() }) } if (result.mLeakFound) { watcher.markPublished(activity, false) From 748cca30408d64e50c02c2856bc2c600ffd4feb0 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Sun, 5 Jun 2022 17:55:01 +0800 Subject: [PATCH 042/263] resource-plugin: fix checkstyle --- .../tencent/matrix/resource/processor/ForkAnalyseProcessor.java | 2 +- .../tencent/matrix/resource/processor/ForkDumpProcessor.java | 2 +- .../matrix/resource/processor/LazyForkAnalyzeProcessor.java | 2 +- .../tencent/matrix/resource/processor/ManualDumpProcessor.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java index 4aca11a21..ec00fe180 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java @@ -63,7 +63,7 @@ private boolean dumpAndAnalyse(String activity, String key) { try { hprof = HprofFileManager.INSTANCE.prepareHprofFile("FAP"); } catch (FileNotFoundException e) { - MatrixLog.printErrStackTrace(TAG, e , ""); + MatrixLog.printErrStackTrace(TAG, e, ""); } if (hprof != null) { diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java index 2969889d1..f563e5c86 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java @@ -40,7 +40,7 @@ public boolean process(DestroyedActivityInfo destroyedActivityInfo) { try { hprof = HprofFileManager.INSTANCE.prepareHprofFile("FDP"); } catch (FileNotFoundException e) { - MatrixLog.printErrStackTrace(TAG, e , ""); + MatrixLog.printErrStackTrace(TAG, e, ""); } if (hprof == null) { diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java index c088818dd..c9cd1a933 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java @@ -144,7 +144,7 @@ private boolean dumpAndAnalyse(String activity, String key) { try { hprof = HprofFileManager.INSTANCE.prepareHprofFile("LFAP"); } catch (FileNotFoundException e) { - MatrixLog.printErrStackTrace(TAG, e , ""); + MatrixLog.printErrStackTrace(TAG, e, ""); } if (hprof != null) { diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java index ad939f87c..0dc94475e 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java @@ -179,7 +179,7 @@ private ManualDumpData dumpAndAnalyse(String activity, String key) { try { file = HprofFileManager.INSTANCE.prepareHprofFile("MDP"); } catch (FileNotFoundException e) { - MatrixLog.printErrStackTrace(TAG, e , ""); + MatrixLog.printErrStackTrace(TAG, e, ""); } final ActivityLeakResult result = MemoryUtil.dumpAndAnalyze(file.getAbsolutePath(), key, 600); if (result.mLeakFound) { From baeec940001674de26c32a0ced574dad3fa84690 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 6 Jun 2022 22:05:42 +0800 Subject: [PATCH 043/263] Add battery currency snapshot --- .../batterycanary/utils/CanaryUtilsTest.java | 15 +++++ .../monitor/feature/CompositeMonitors.java | 16 +++++ .../feature/DeviceStatMonitorFeature.java | 23 +++++++ .../utils/BatteryCanaryUtil.java | 60 +++++++++++++------ 4 files changed, 96 insertions(+), 18 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java index 704399d8e..311966a13 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java @@ -246,6 +246,21 @@ public void testGetBatteryCapacity() throws Exception { Assert.assertEquals(capacity3, capacity4, 1000d); } + @Test + public void testGetBatteryCurrent() { + BatteryManager batteryManager = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE); + long avgCurrent = 0, currentNow = 0; + avgCurrent = batteryManager.getLongProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE); + currentNow = batteryManager.getLongProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW); + Log.d(TAG, "BATTERY_PROPERTY_CURRENT_AVERAGE = " + avgCurrent + "microA"); + Log.d(TAG, "BATTERY_PROPERTY_CURRENT_NOW = " + currentNow + "microA"); + Assert.assertNotEquals(0, avgCurrent); + Assert.assertNotEquals(0, currentNow); + + long value = BatteryCanaryUtil.getBatteryCurrencyImmediately(mContext); + Assert.assertNotEquals(0, value); + } + @Test public void testCheckIfLowBattery() { Intent intent = BatteryCanaryUtil.getBatteryStickyIntent(mContext); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 2148fc5d3..139fc69a1 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -628,6 +628,22 @@ public Number apply(Snapshot.Sampler sampler) { } return sampler; } + if (snapshotClass == DeviceStatMonitorFeature.BatteryCurrentSnapshot.class) { + final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); + if (feature != null && mMonitor != null) { + sampler = new MonitorFeature.Snapshot.Sampler("batt-curr", mMonitor.getHandler(), new Function() { + @Override + public Number apply(Snapshot.Sampler sampler) { + DeviceStatMonitorFeature.BatteryCurrentSnapshot snapshot = feature.currentBatteryCurrency(mMonitor.getContext()); + Long value = snapshot.stat.get(); + MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); + return value; + } + }); + mSamplers.put(snapshotClass, sampler); + } + return sampler; + } return null; } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java index 324958dc4..03a691ad3 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java @@ -186,6 +186,12 @@ public ChargeWattageSnapshot currentChargeWattage(Context context) { return snapshot; } + public BatteryCurrentSnapshot currentBatteryCurrency(Context context) { + BatteryCurrentSnapshot snapshot = new BatteryCurrentSnapshot(); + snapshot.stat = Snapshot.Entry.DigitEntry.of(BatteryCanaryUtil.getBatteryCurrency(context)); + return snapshot; + } + static final class DevStatListener { Consumer mListener = new Consumer() { @@ -346,6 +352,23 @@ protected ChargeWattageSnapshot computeDelta() { } }; } + + } + + public static class BatteryCurrentSnapshot extends Snapshot { + public Entry.DigitEntry stat; + + @Override + public Delta diff(BatteryCurrentSnapshot bgn) { + return new Delta(bgn, this) { + @Override + protected BatteryCurrentSnapshot computeDelta() { + BatteryCurrentSnapshot delta = new BatteryCurrentSnapshot(); + delta.stat = DigitDiffer.globalDiff(bgn.stat, end.stat); + return delta; + } + }; + } } public static final class DevStatSnapshot extends Snapshot { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java index 1d6df4994..72183ddc7 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java @@ -87,14 +87,15 @@ public interface Proxy { void updateDevStat(int value); int getBatteryPercentage(Context context); int getBatteryCapacity(Context context); + long getBatteryCurrency(Context context); int getCpuCoreNum(); - final class ExpireRef { - final int value; + final class ExpireRef { + final T value; final long aliveMillis; final long lastMillis; - ExpireRef(int value, long aliveMillis) { + ExpireRef(T value, long aliveMillis) { this.value = value; this.aliveMillis = aliveMillis; this.lastMillis = SystemClock.uptimeMillis(); @@ -110,12 +111,13 @@ boolean isExpired() { static Proxy sCacheStub = new Proxy() { private String mProcessName; private String mPackageName; - private ExpireRef mBatteryTemp; - private ExpireRef mLastAppStat; - private ExpireRef mLastDevStat; - private ExpireRef mLastBattPct; - private ExpireRef mLastBattCap; - private ExpireRef mLastCpuCoreNum; + private ExpireRef mBatteryTemp; + private ExpireRef mLastAppStat; + private ExpireRef mLastDevStat; + private ExpireRef mLastBattPct; + private ExpireRef mLastBattCap; + private ExpireRef mLastBattCur; + private ExpireRef mLastCpuCoreNum; @Override public String getProcessName() { @@ -149,7 +151,7 @@ public int getBatteryTemperature(Context context) { return mBatteryTemp.value; } int tmp = getBatteryTemperatureImmediately(context); - mBatteryTemp = new ExpireRef(tmp, DEFAULT_AMS_CACHE_MILLIS); + mBatteryTemp = new ExpireRef<>(tmp, DEFAULT_AMS_CACHE_MILLIS); return mBatteryTemp.value; } @@ -160,7 +162,7 @@ public int getAppStat(Context context, boolean isForeground) { return mLastAppStat.value; } int value = getAppStatImmediately(context, false); - mLastAppStat = new ExpireRef(value, DEFAULT_AMS_CACHE_MILLIS); + mLastAppStat = new ExpireRef<>(value, DEFAULT_AMS_CACHE_MILLIS); return mLastAppStat.value; } @@ -170,21 +172,21 @@ public int getDevStat(Context context) { return mLastDevStat.value; } int value = getDeviceStatImmediately(context); - mLastDevStat = new ExpireRef(value, DEFAULT_AMS_CACHE_MILLIS); + mLastDevStat = new ExpireRef<>(value, DEFAULT_AMS_CACHE_MILLIS); return mLastDevStat.value; } @Override public void updateAppStat(int value) { synchronized (this) { - mLastAppStat = new ExpireRef(value, DEFAULT_AMS_CACHE_MILLIS); + mLastAppStat = new ExpireRef<>(value, DEFAULT_AMS_CACHE_MILLIS); } } @Override public void updateDevStat(int value) { synchronized (this) { - mLastDevStat = new ExpireRef(value, DEFAULT_AMS_CACHE_MILLIS); + mLastDevStat = new ExpireRef<>(value, DEFAULT_AMS_CACHE_MILLIS); } } @@ -194,7 +196,7 @@ public int getBatteryPercentage(Context context) { return mLastBattPct.value; } int val = getBatteryPercentageImmediately(context); - mLastBattPct = new ExpireRef(val, ONE_MIN); + mLastBattPct = new ExpireRef<>(val, ONE_MIN); return mLastBattPct.value; } @@ -204,10 +206,20 @@ public int getBatteryCapacity(Context context) { return mLastBattCap.value; } int val = getBatteryCapacityImmediately(context); - mLastBattCap = new ExpireRef(val, ONE_MIN); + mLastBattCap = new ExpireRef<>(val, ONE_MIN); return mLastBattCap.value; } + @Override + public long getBatteryCurrency(Context context) { + if (mLastBattCur != null && !mLastBattCur.isExpired()) { + return mLastBattCur.value; + } + long val = getBatteryCurrencyImmediately(context); + mLastBattCur = new ExpireRef<>(val, ONE_MIN); + return mLastBattCur.value; + } + @Override public int getCpuCoreNum() { if (mLastCpuCoreNum != null && !mLastCpuCoreNum.isExpired()) { @@ -217,7 +229,7 @@ public int getCpuCoreNum() { if (val <= 1) { return val; } - mLastCpuCoreNum = new ExpireRef(val, ONE_HOR); + mLastCpuCoreNum = new ExpireRef<>(val, ONE_HOR); return mLastCpuCoreNum.value; } }; @@ -623,7 +635,7 @@ public static int getBatteryPercentageImmediately(Context context) { public static int getBatteryCapacity(Context context) { return sCacheStub.getBatteryCapacity(context); - }; + } @SuppressWarnings("ConstantConditions") @SuppressLint("PrivateApi") @@ -659,6 +671,18 @@ public static int getBatteryCapacityImmediately(Context context) { return -1; } + public static long getBatteryCurrency(Context context) { + return sCacheStub.getBatteryCurrency(context); + } + + public static long getBatteryCurrencyImmediately(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + BatteryManager mBatteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE); + return mBatteryManager.getLongProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW); + } + return -1; + } + public static boolean hasForegroundService(Context context) { try { ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE); From 6fa1983d23b93c03eb03eae9defd4338613b67e1 Mon Sep 17 00:00:00 2001 From: leafjia Date: Tue, 7 Jun 2022 01:33:45 +0800 Subject: [PATCH 044/263] Fix thread hook wrong switch --- .../matrix-trace-canary/src/main/cpp/MatrixTracer.cc | 8 ++------ .../com/tencent/matrix/trace/tracer/ThreadTracer.java | 4 +++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc index 3387dce9e..17f263e4a 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc +++ b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc @@ -455,18 +455,14 @@ static void nativeInitThreadHook(JNIEnv *env, jclass, jint priority, jint pthrea xhook_grouped_register(HOOK_REQUEST_GROUPID_THREAD_PTHREAD_KEY_TRACE, ".*\\.so$", "pthread_key_delete", (void *) my_pthread_key_delete, (void **) (&original_pthread_key_delete)); - xhook_export_symtable_hook("libc.so", "pthread_key_create", (void *) my_pthread_key_create, (void **) (&original_pthread_key_create)); xhook_export_symtable_hook("libc.so", "pthread_key_delete", (void *) my_pthread_key_delete, (void **) (&original_pthread_key_delete)); } - if (pthreadKey + pthreadKey > 0) { - xhook_enable_sigsegv_protection(0); - xhook_refresh(0); - } - + xhook_enable_sigsegv_protection(0); + xhook_refresh(0); } static void nativeInitTouchEventLagDetective(JNIEnv *env, jclass, jint threshold) { diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadTracer.java index 04a142876..5b31de460 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadTracer.java @@ -44,7 +44,9 @@ public class ThreadTracer extends Tracer { @Override protected void onAlive() { super.onAlive(); - nativeInitThreadHook(enableThreadPriorityTracer ? 1 : 0, enablePthreadKeyTracer ? 1 : 0); + if (enableThreadPriorityTracer || enablePthreadKeyTracer) { + nativeInitThreadHook(enableThreadPriorityTracer ? 1 : 0, enablePthreadKeyTracer ? 1 : 0); + } } @Override From b751aa0a55b13e878f4c9cf2d87dd7af15d45135 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 7 Jun 2022 12:17:19 +0800 Subject: [PATCH 045/263] resource-plugin: fix report msg --- .../matrix/resource/processor/NativeForkAnalyzeProcessor.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index 04b3e16a2..b62dabb1d 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -202,9 +202,9 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso val hprof = safeLetOrNull { HprofFileManager.prepareHprofFile("NFAP") } ?: run { publishIssue( - SharePluginInfo.IssueType.LEAK_FOUND, // ? should be ERR_FILE_NOT_FOUND + SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.FORK_ANALYSE, - "[unknown]", "[unknown]", "Failed to create hprof file.", "0" + destroyedActivityInfo.mActivityName, "[unknown]", "Failed to create hprof file.", "0" ) return true } From cc97ae1d91697b916152ba56c524649952da48ae Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 7 Jun 2022 12:35:25 +0800 Subject: [PATCH 046/263] resource-plugin: skip free space check cause res plugin would delete hprof soon --- .../resource/dumper/AndroidHeapDumper.java | 2 +- .../resource/dumper/HprofFileManager.kt | 19 ++++++++++--------- .../processor/ForkAnalyseProcessor.java | 2 +- .../resource/processor/ForkDumpProcessor.java | 2 +- .../processor/LazyForkAnalyzeProcessor.java | 2 +- .../processor/ManualDumpProcessor.java | 2 +- .../processor/NativeForkAnalyzeProcessor.kt | 17 ++++++++++------- 7 files changed, 25 insertions(+), 21 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/AndroidHeapDumper.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/AndroidHeapDumper.java index 9532af9f7..52e7f9eb5 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/AndroidHeapDumper.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/AndroidHeapDumper.java @@ -61,7 +61,7 @@ public AndroidHeapDumper(Context context, Handler mainHandler) { public File dumpHeap(boolean isShowToast) { File hprofFile = null; try { - hprofFile = HprofFileManager.INSTANCE.prepareHprofFile(""); + hprofFile = HprofFileManager.INSTANCE.prepareHprofFile("", false); } catch (FileNotFoundException e) { MatrixLog.printErrStackTrace(TAG, e, ""); } diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt index 27fec0cd0..d4a811fca 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt @@ -19,7 +19,8 @@ object HprofFileManager { private const val TAG = "Matrix.HprofFileManager" private const val MAX_FILE_COUNT = 10 - private const val MIN_FREE_SPACE = 20 * 1024 * 1024 * 1024L // 20G + private const val CLEAN_THRESHOLD = 12 * 1024 * 1024 * 1024L // 12G + private const val MIN_FREE_SPACE = 1024 * 1024 * 1024L // 1G private val EXPIRED_TIME_MILLIS = TimeUnit.DAYS.toMillis(7) @@ -43,8 +44,8 @@ object HprofFileManager { } @Throws(FileNotFoundException::class) - fun prepareHprofFile(prefix: String = ""): File { - hprofStorageDir.prepare() + fun prepareHprofFile(prefix: String = "", deleteSoon: Boolean = false): File { + hprofStorageDir.prepare(deleteSoon) return File(hprofStorageDir, getHprofFileName(prefix)) } @@ -52,9 +53,9 @@ object HprofFileManager { hprofStorageDir.deleteRecursively() } - private fun File.prepare() { + private fun File.prepare(deleteSoon: Boolean) { reserve() - makeSureEnoughSpace() + makeSureEnoughSpace(deleteSoon) } private fun File.reserve() { @@ -66,16 +67,16 @@ object HprofFileManager { } } - private fun File.makeSureEnoughSpace() { + private fun File.makeSureEnoughSpace(deleteSoon: Boolean) { if (!isDirectory) { return } lru() - if (freeSpace < MIN_FREE_SPACE) { + if (freeSpace < CLEAN_THRESHOLD) { listFiles()?.forEach { it.delete() } } - if (freeSpace < MIN_FREE_SPACE) { - throw FileNotFoundException("free space less than $MIN_FREE_SPACE, skip dump hprof") + if (freeSpace < if (deleteSoon) MIN_FREE_SPACE else CLEAN_THRESHOLD) { + throw FileNotFoundException("free space($freeSpace) less than $CLEAN_THRESHOLD, skip dump hprof") } } diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java index ec00fe180..2d5fada37 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java @@ -61,7 +61,7 @@ private boolean dumpAndAnalyse(String activity, String key) { File hprof = null; try { - hprof = HprofFileManager.INSTANCE.prepareHprofFile("FAP"); + hprof = HprofFileManager.INSTANCE.prepareHprofFile("FAP", true); } catch (FileNotFoundException e) { MatrixLog.printErrStackTrace(TAG, e, ""); } diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java index f563e5c86..cfda36b88 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java @@ -38,7 +38,7 @@ public boolean process(DestroyedActivityInfo destroyedActivityInfo) { File hprof = null; try { - hprof = HprofFileManager.INSTANCE.prepareHprofFile("FDP"); + hprof = HprofFileManager.INSTANCE.prepareHprofFile("FDP", true); } catch (FileNotFoundException e) { MatrixLog.printErrStackTrace(TAG, e, ""); } diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java index c9cd1a933..3f115a2cd 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java @@ -142,7 +142,7 @@ private boolean dumpAndAnalyse(String activity, String key) { File hprof = null; try { - hprof = HprofFileManager.INSTANCE.prepareHprofFile("LFAP"); + hprof = HprofFileManager.INSTANCE.prepareHprofFile("LFAP", true); } catch (FileNotFoundException e) { MatrixLog.printErrStackTrace(TAG, e, ""); } diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java index 0dc94475e..8e69322e3 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java @@ -177,7 +177,7 @@ private ManualDumpData dumpAndAnalyse(String activity, String key) { File file = null; try { - file = HprofFileManager.INSTANCE.prepareHprofFile("MDP"); + file = HprofFileManager.INSTANCE.prepareHprofFile("MDP", false); } catch (FileNotFoundException e) { MatrixLog.printErrStackTrace(TAG, e, ""); } diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index b62dabb1d..1dcb4695d 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -148,12 +148,15 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso if (result.mFailure != null) { historyFailure.add(result.mFailure.toString()) retryCount++ - val cpy = HprofFileManager.prepareHprofFile("RETRY") // prevent duplicated analyse after OOM - hprof.copyTo(cpy, true) - hprof.deleteIfExist() - safeLet({ - result = analyze(cpy, key) // if crashed, the copied file could be auto-cleared by HprofFileManager later (lru or expired) - }, success = { cpy.deleteIfExist() }, failed = { cpy.deleteIfExist() }) + safeLetOrNull(TAG) { + HprofFileManager.prepareHprofFile("RETRY", false) // prevent duplicated analyse after OOM + }?.let { cpy -> + hprof.copyTo(cpy, true) + hprof.deleteIfExist() + safeLet({ + result = analyze(cpy, key) // if crashed, the copied file could be auto-cleared by HprofFileManager later (lru or expired) + }, success = { cpy.deleteIfExist() }, failed = { cpy.deleteIfExist() }) + } } if (result.mLeakFound) { watcher.markPublished(activity, false) @@ -200,7 +203,7 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso override fun process(destroyedActivityInfo: DestroyedActivityInfo): Boolean { - val hprof = safeLetOrNull { HprofFileManager.prepareHprofFile("NFAP") } ?: run { + val hprof = safeLetOrNull { HprofFileManager.prepareHprofFile("NFAP", true) } ?: run { publishIssue( SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.FORK_ANALYSE, From 1cd5d51c2ccc2fc335b1f640e4ba5ff893830a5f Mon Sep 17 00:00:00 2001 From: leafjia Date: Tue, 7 Jun 2022 15:33:42 +0800 Subject: [PATCH 047/263] Return empty string if dumpStackTrace is disabled --- .../main/java/com/tencent/matrix/traffic/TrafficPlugin.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java index bd9a9fde6..340e694ea 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java +++ b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java @@ -66,6 +66,9 @@ public String getStackTraceByMd5(String md5) { } public String getJavaStackTraceByKey(String key) { + if (!trafficConfig.willDumpStackTrace()) { + return ""; + } String md5 = keyHashMap.get(key); if (md5 == null || md5.isEmpty()) { return ""; @@ -73,6 +76,9 @@ public String getJavaStackTraceByKey(String key) { return hashStackTraceMap.get(md5); } public String getNativeBackTraceByKey(String key) { + if (!trafficConfig.willDumpNativeBackTrace()) { + return ""; + } return nativeGetNativeBackTraceByKey(key); } From f2c87d4e0d907343130e403464bbcbd8d83ae40c Mon Sep 17 00:00:00 2001 From: leafjia Date: Tue, 7 Jun 2022 15:59:30 +0800 Subject: [PATCH 048/263] Fix build error --- .../tencent/matrix/MatrixApplication.java | 3 +-- .../matrix/traffic/TestTrafficActivity.java | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java index 3b157ce84..23219cd2a 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java @@ -182,7 +182,6 @@ private TracePlugin configureTracePlugin(DynamicConfigImplDemo dynamicConfig) { .enableAnrTrace(traceEnable) .enableStartup(traceEnable) .enableIdleHandlerTrace(traceEnable) // Introduced in Matrix 2.0 - .enableMainThreadPriorityTrace(true) // Introduced in Matrix 2.0 .enableSignalAnrTrace(signalAnrTraceEnable) // Introduced in Matrix 2.0 .anrTracePath(anrTraceFile.getAbsolutePath()) .printTracePath(printTraceFile.getAbsolutePath()) @@ -261,7 +260,7 @@ private BatteryMonitorPlugin configureBatteryCanary(Context context) { } private MatrixLifecycleConfig configureMatrixLifecycle() { - return new MatrixLifecycleConfig(new SupervisorConfig(true, true, new ArrayList()), true, true, new LifecycleThreadConfig()); + return new MatrixLifecycleConfig(new SupervisorConfig(true, true, new ArrayList()), true, true, new LifecycleThreadConfig(), true); } public static Context getContext() { diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/traffic/TestTrafficActivity.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/traffic/TestTrafficActivity.java index 1e9b551e6..c05094b09 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/traffic/TestTrafficActivity.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/traffic/TestTrafficActivity.java @@ -31,6 +31,8 @@ public class TestTrafficActivity extends Activity { TrafficPlugin trafficPlugin; boolean downloading = false; long totalTraffic = 0; + private String stackTrace; + private boolean dumpedStackTrace; @Override protected void onCreate(Bundle savedInstanceState) { @@ -57,28 +59,31 @@ public void run() { } void startTrafficCollector() { + new Thread(new Runnable() { @Override public void run() { while (downloading) { HashMap trafficInfo = trafficPlugin.getTrafficInfoMap(TrafficPlugin.TYPE_GET_TRAFFIC_RX); - Map stackTraceMap = trafficPlugin.getStackTraceMap(); for (Map.Entry entry : trafficInfo.entrySet()) { - final String threadName = entry.getKey(); + final String key = entry.getKey(); long traffic = Long.parseLong(entry.getValue()); - final String stack = stackTraceMap.get(threadName); + if (!dumpedStackTrace) { + stackTrace = trafficPlugin.getNativeBackTraceByKey(key) + trafficPlugin.getJavaStackTraceByKey(key); + dumpedStackTrace = true; + } totalTraffic += traffic; runOnUiThread(new Runnable() { @Override public void run() { threadTextView.setText("Total Traffic : " + totalTraffic + " Bytes"); - totalTrafficTextView.setText("Thread Name : " + threadName); - stackTextView.setText("Stack Trace: " + stack); + totalTrafficTextView.setText("key Name : " + key); + stackTextView.setText("Stack Trace: " + stackTrace); } }); - trafficPlugin.clearTrafficInfo(); } + trafficPlugin.clearTrafficInfo(); try { Thread.sleep(1000); @@ -92,7 +97,7 @@ public void run() { void initTraffic() { - TrafficConfig trafficConfig = new TrafficConfig(true, true, true); + TrafficConfig trafficConfig = new TrafficConfig(true, true, true, true); //trafficConfig.addIgnoreSoFile("libmmkv.so");// whitelist trafficPlugin = new TrafficPlugin(trafficConfig); trafficPlugin.init(getApplication(), new PluginListener() { From 0fbc24ff38f43873667af0bdbe0361446236d8fe Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 8 Jun 2022 13:05:51 +0800 Subject: [PATCH 049/263] resource-canary: add log --- .../matrix/resource/processor/NativeForkAnalyzeProcessor.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index 1dcb4695d..c837adab2 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -217,7 +217,9 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso watcher.triggerGc() + MatrixLog.i(TAG, "fork dump and analyse") val result = MemoryUtil.dumpAndAnalyze(hprof.absolutePath, key, timeout = 600) + MatrixLog.i(TAG, "fork dump and analyse done") if (result.mFailure != null) { // Copies file to retry repository and analyzes it again when the screen is locked. MatrixLog.i(TAG, "Process failed, move into retry repository.") From dc029c5006d29a7c4e7c9f3f0432be3689d857dc Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 8 Jun 2022 14:46:25 +0800 Subject: [PATCH 050/263] resource-canary: report no_dump type for analyse_modes --- .../matrix/resource/processor/ForkAnalyseProcessor.java | 2 ++ .../tencent/matrix/resource/processor/ForkDumpProcessor.java | 3 +++ .../matrix/resource/processor/LazyForkAnalyzeProcessor.java | 2 ++ .../matrix/resource/processor/NativeForkAnalyzeProcessor.kt | 1 + .../matrix/resource/processor/SilenceAnalyseProcessor.java | 1 + 5 files changed, 9 insertions(+) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java index 2d5fada37..69afce5f5 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java @@ -30,6 +30,8 @@ public ForkAnalyseProcessor(ActivityRefWatcher watcher) { @Override public boolean process(DestroyedActivityInfo destroyedActivityInfo) { + publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.NO_DUMP, destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey, "no dump", "0"); + if (Build.VERSION.SDK_INT > ResourceConfig.FORK_DUMP_SUPPORTED_API_GUARD) { MatrixLog.e(TAG, "cannot fork-dump with unsupported API version " + Build.VERSION.SDK_INT); publishIssue( diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java index cfda36b88..d498a1514 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java @@ -6,6 +6,7 @@ import com.tencent.matrix.resource.analyzer.model.DestroyedActivityInfo; import com.tencent.matrix.resource.analyzer.model.HeapDump; import com.tencent.matrix.resource.config.ResourceConfig; +import com.tencent.matrix.resource.config.SharePluginInfo; import com.tencent.matrix.resource.dumper.HprofFileManager; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; import com.tencent.matrix.util.MatrixLog; @@ -29,6 +30,8 @@ public ForkDumpProcessor(ActivityRefWatcher watcher) { @Override public boolean process(DestroyedActivityInfo destroyedActivityInfo) { + publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.NO_DUMP, destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey, "no dump", "0"); + if (Build.VERSION.SDK_INT > ResourceConfig.FORK_DUMP_SUPPORTED_API_GUARD) { MatrixLog.e(TAG, "unsupported API version " + Build.VERSION.SDK_INT); return false; diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java index 3f115a2cd..fd23bd76a 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/LazyForkAnalyzeProcessor.java @@ -113,6 +113,8 @@ public void onDestroy() { @Override public boolean process(DestroyedActivityInfo destroyedActivityInfo) { + publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.NO_DUMP, destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey, "no dump", "0"); + if (Build.VERSION.SDK_INT > ResourceConfig.FORK_DUMP_SUPPORTED_API_GUARD) { MatrixLog.e(TAG, "cannot fork-dump with unsupported API version " + Build.VERSION.SDK_INT); publishIssue( diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index c837adab2..31a8378c1 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -202,6 +202,7 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso } override fun process(destroyedActivityInfo: DestroyedActivityInfo): Boolean { + publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.NO_DUMP, destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey, "no dump", "0") val hprof = safeLetOrNull { HprofFileManager.prepareHprofFile("NFAP", true) } ?: run { publishIssue( diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/SilenceAnalyseProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/SilenceAnalyseProcessor.java index 3362abbc3..446bc5f05 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/SilenceAnalyseProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/SilenceAnalyseProcessor.java @@ -55,6 +55,7 @@ public void onReceive(Context context, Intent intent) { @Override public boolean process(DestroyedActivityInfo destroyedActivityInfo) { + publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.NO_DUMP, destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey, "no dump", "0"); return onLeak(destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey); } From 0f62320992193f2557dfb3f4269a9dc7afa263da Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 8 Jun 2022 14:55:56 +0800 Subject: [PATCH 051/263] resource-canary: run fallback retry-task in detector thread to prevent parallel analyzing --- .../resource/processor/NativeForkAnalyzeProcessor.kt | 9 ++------- .../matrix/resource/watcher/ActivityRefWatcher.java | 4 ++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index 31a8378c1..a1ebe8d70 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -108,12 +108,6 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso private const val RETRY_THREAD_NAME = "matrix_res_native_analyze_retry" private const val RETRY_REPO_NAME = "matrix_res_process_retry" - - private val retryExecutor by lazy { - Executors.newSingleThreadExecutor { - Thread(it, RETRY_THREAD_NAME) - } - } } private val retryRepo: RetryRepository? by lazy { @@ -137,7 +131,8 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso private val screenStateReceiver by lazy { return@lazy object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { - retryExecutor.execute { + // run in detector thread to prevent parallel analyzing + watcher.detectHandler.post { retryRepo?.process { hprof, activity, key, failure -> MatrixLog.i(TAG, "Found record ${activity}(${hprof.name}).") val historyFailure = mutableListOf().apply { diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/watcher/ActivityRefWatcher.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/watcher/ActivityRefWatcher.java index d9d55cfaf..ba6b53845 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/watcher/ActivityRefWatcher.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/watcher/ActivityRefWatcher.java @@ -312,6 +312,10 @@ public ResourcePlugin getResourcePlugin() { return mResourcePlugin; } + public Handler getDetectHandler() { + return mHandler; + } + public Collection getDestroyedActivityInfos() { return mDestroyedActivityInfos; } From 84ccdb57479f21aba864294467b24074504b9765 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 8 Jun 2022 15:06:11 +0800 Subject: [PATCH 052/263] resource-canary: delete key file with hprof file --- .../resource/processor/NativeForkAnalyzeProcessor.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index a1ebe8d70..bf0d4b730 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -75,7 +75,7 @@ private class RetryRepository(private val dir: File) { } } - fun process(action: (File, String, String, String) -> Unit) { + fun process(action: (File, File, String, String, String) -> Unit) { val hprofs = synchronized(accessLock) { hprofDir.listFiles() ?: emptyArray() } @@ -86,7 +86,7 @@ private class RetryRepository(private val dir: File) { val (activity, key, failure) = keyFile.bufferedReader().use { Triple(it.readLine(), it.readLine(), it.readLine()) } - action.invoke(hprofFile, activity, key, failure) + action.invoke(hprofFile, keyFile, activity, key, failure) } } catch (throwable: Throwable) { MatrixLog.printErrStackTrace( @@ -133,7 +133,9 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso override fun onReceive(context: Context?, intent: Intent?) { // run in detector thread to prevent parallel analyzing watcher.detectHandler.post { - retryRepo?.process { hprof, activity, key, failure -> + // fixme : should separate native analyse and java analyse into smaller parts. + // It is possible to unlock screen and turn foreground when analyzing + retryRepo?.process { hprof, keyFile, activity, key, failure -> MatrixLog.i(TAG, "Found record ${activity}(${hprof.name}).") val historyFailure = mutableListOf().apply { add(failure) @@ -148,6 +150,7 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso }?.let { cpy -> hprof.copyTo(cpy, true) hprof.deleteIfExist() + keyFile.deleteIfExist() safeLet({ result = analyze(cpy, key) // if crashed, the copied file could be auto-cleared by HprofFileManager later (lru or expired) }, success = { cpy.deleteIfExist() }, failed = { cpy.deleteIfExist() }) From 534496eba460d1752447804e27d264e74ab56c82 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 8 Jun 2022 15:08:28 +0800 Subject: [PATCH 053/263] resource-canary: remove useless imports --- .../matrix/resource/processor/NativeForkAnalyzeProcessor.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index bf0d4b730..120258753 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -16,7 +16,6 @@ import com.tencent.matrix.util.safeLet import com.tencent.matrix.util.safeLetOrNull import java.io.File import java.util.* -import java.util.concurrent.Executors private fun File.deleteIfExist() { if (exists()) delete() From 904f090a6dd479feebae845acdd104ddb41293a1 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 8 Jun 2022 15:09:51 +0800 Subject: [PATCH 054/263] resource-canary: remove useless code --- .../matrix/resource/processor/NativeForkAnalyzeProcessor.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index 120258753..7939fe492 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -103,9 +103,6 @@ private class RetryRepository(private val dir: File) { class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcessor(watcher) { companion object { - - private const val RETRY_THREAD_NAME = "matrix_res_native_analyze_retry" - private const val RETRY_REPO_NAME = "matrix_res_process_retry" } From fbda2ef7b5048689a40a9ac0057b3373ccf67c70 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 8 Jun 2022 19:41:57 +0800 Subject: [PATCH 055/263] Update composite monitors with task collecting --- .../feature/MonitorFeatureLooperTest.java | 6 +- .../feature/AbsTaskMonitorFeature.java | 16 +++- .../monitor/feature/CompositeMonitors.java | 88 ++++++++++++++++--- 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureLooperTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureLooperTest.java index a934a231a..5a042ba92 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureLooperTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeatureLooperTest.java @@ -341,7 +341,7 @@ public void run() { Assert.assertEquals(1, feature.mDeltaList.size()); Assert.assertTrue(feature.mDeltaList.get(0).dlt.name.contains(MonitorFeatureLooperTest.class.getName() + "$")); - List> deltas = feature.currentJiffies(); + List> deltas = feature.currentJiffies(0); Assert.assertEquals(1, deltas.size()); Assert.assertEquals(feature.mDeltaList, deltas); @@ -416,7 +416,7 @@ public void run() { Assert.assertEquals(1, feature.mDeltaList.size()); Assert.assertTrue(feature.mDeltaList.get(0).dlt.name.contains(MonitorFeatureLooperTest.class.getName() + "$")); - List> deltas = feature.currentJiffies(); + List> deltas = feature.currentJiffies(0); Assert.assertEquals(1, deltas.size()); Assert.assertEquals(feature.mDeltaList, deltas); @@ -545,7 +545,7 @@ public void run() { Assert.assertEquals(1, feature.mDeltaList.size()); Assert.assertTrue(feature.mDeltaList.get(0).dlt.name.contains(MonitorFeatureLooperTest.class.getName() + "$")); - List> deltas = feature.currentJiffies(); + List> deltas = feature.currentJiffies(0); Assert.assertEquals(1, deltas.size()); Assert.assertEquals(feature.mDeltaList, deltas); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AbsTaskMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AbsTaskMonitorFeature.java index 5536cada5..91bb65579 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AbsTaskMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/AbsTaskMonitorFeature.java @@ -104,7 +104,7 @@ public void onTurnOff() { } } - public List> currentJiffies() { + public List> currentJiffies(long windowMsFromNow) { // Report unfinished task: // Maybe cause duplicated reporting // for (TaskJiffiesSnapshot bgn : mTaskJiffiesTrace.values()) { @@ -116,7 +116,17 @@ public List> currentJiffies() { ArrayList> list; synchronized (mDeltaList) { - list = new ArrayList<>(mDeltaList); + if (windowMsFromNow <= 0) { + list = new ArrayList<>(mDeltaList); + } else { + list = new ArrayList<>(); + long bgnMillis = SystemClock.uptimeMillis() - windowMsFromNow; + for (Delta item : mDeltaList) { + if (item.bgn.time >= bgnMillis) { + list.add(item); + } + } + } } // Sorting by jiffies dec @@ -408,7 +418,7 @@ protected void onCoolingDown() { // task jiffies list overheat if (mDeltaList.size() > mOverHeatCount) { MatrixLog.w(TAG, "cooling task jiffies list, before = " + mDeltaList.size()); - List> deltas = currentJiffies(); + List> deltas = currentJiffies(0); clearFinishedJiffies(); MatrixLog.w(TAG, "cooling task jiffies list, after = " + mDeltaList.size()); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 139fc69a1..24857fb36 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -7,6 +7,7 @@ import com.tencent.matrix.batterycanary.monitor.AppStats; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; +import com.tencent.matrix.batterycanary.monitor.feature.AbsTaskMonitorFeature.TaskJiffiesSnapshot; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.JiffiesSnapshot; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.JiffiesSnapshot.ThreadJiffiesEntry; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot; @@ -21,6 +22,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -51,7 +53,8 @@ public class CompositeMonitors { protected final Map>, Snapshot.Sampler.Result> mSampleResults = new HashMap<>(); // Task Tracing - protected final Map, List>> mTaskDeltas = new HashMap<>(); + protected final Map, List>> mTaskDeltas = new HashMap<>(); + protected final Map>> mTaskDeltasCollect = new HashMap<>(); // Extra Info protected final Bundle mExtras = new Bundle(); @@ -88,6 +91,7 @@ public void clear() { mSamplers.clear(); mSampleResults.clear(); mTaskDeltas.clear(); + mTaskDeltasCollect.clear(); } @CallSuper @@ -647,34 +651,83 @@ public Number apply(Snapshot.Sampler sampler) { return null; } - public void configureTaskDeltas(final Class featClass) { - AbsTaskMonitorFeature taskFeat = getFeature(featClass); - if (taskFeat != null) { - List> deltas = taskFeat.currentJiffies(); - taskFeat.clearFinishedJiffies(); - putTaskDeltas(featClass, deltas); + protected void configureTaskDeltas(final Class featClass) { + if (mAppStats != null) { + AbsTaskMonitorFeature taskFeat = getFeature(featClass); + if (taskFeat != null) { + List> deltas = taskFeat.currentJiffies(mAppStats.duringMillis); + // No longer clear here + // Clear at BG Scope or OverHeat + // taskFeat.clearFinishedJiffies(); + putTaskDeltas(featClass, deltas); + } + } + } + + protected void collectTaskDeltas() { + if (!mTaskDeltas.isEmpty()) { + for (List> taskDeltaList : mTaskDeltas.values()) { + for (Delta taskDelta : taskDeltaList) { + // FIXME: better windowMillis cfg of Task and AppStats + if (taskDelta.bgn.time >= mBgnMillis) { + List> collectTaskList = mTaskDeltasCollect.get(taskDelta.dlt.name); + if (collectTaskList == null) { + collectTaskList = new ArrayList<>(); + mTaskDeltasCollect.put(taskDelta.dlt.name, collectTaskList); + } + collectTaskList.add(taskDelta); + } + } + } } } - public void putTaskDeltas(Class key, List> deltas) { + public void putTaskDeltas(Class key, List> deltas) { mTaskDeltas.put(key, deltas); } - public List> getTaskDeltas(Class key) { - List> deltas = mTaskDeltas.get(key); + public List> getTaskDeltas(Class key) { + List> deltas = mTaskDeltas.get(key); if (deltas == null) { return Collections.emptyList(); } return deltas; } - public void getTaskDeltas(Class key, Consumer>> block) { - List> deltas = mTaskDeltas.get(key); + public void getTaskDeltas(Class key, Consumer>> block) { + List> deltas = mTaskDeltas.get(key); if (deltas != null) { block.accept(deltas); } } + public Map>> getCollectedTaskDeltas() { + if (mTaskDeltasCollect.size() <= 1) { + return mTaskDeltasCollect; + } + // Sorting by jiffies sum + return sortMapByValue(mTaskDeltasCollect, new Comparator>>>() { + @Override + public int compare(Map.Entry>> o1, Map.Entry>> o2) { + long sumLeft = 0, sumRight = 0; + for (Delta item : o1.getValue()) { + sumLeft += item.dlt.jiffies.get(); + } + for (Delta item : o2.getValue()) { + sumRight += item.dlt.jiffies.get(); + } + long minus = sumLeft - sumRight; + if (minus == 0) return 0; + if (minus > 0) return -1; + return 1; + } + }); + } + + public void getCollectedTaskDeltas(Consumer>>> block) { + block.accept(getCollectedTaskDeltas()); + } + public Map getStacks() { return mStacks; } @@ -699,4 +752,15 @@ public String toString() { ", Extras =" + mExtras + "\n" + '}'; } + + static Map sortMapByValue(Map map, Comparator> comparator) { + List> list = new ArrayList<>(map.entrySet()); + Collections.sort(list, comparator); + + Map result = new LinkedHashMap<>(); + for (Map.Entry entry : list) { + result.put(entry.getKey(), entry.getValue()); + } + return result; + } } From d4f9504b364faed4bdd3a414806dc478adf3d99b Mon Sep 17 00:00:00 2001 From: leafjia Date: Thu, 9 Jun 2022 12:52:21 +0800 Subject: [PATCH 056/263] Fix delete static mem --- .../matrix-traffic/src/main/cpp/MatrixTraffic.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc index 400cad799..af90a9101 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -110,9 +110,6 @@ static void saveNativeBackTrace(const char* key) { } static char* getNativeBacktrace(string keyString) { - if (!sDumpNativeBackTrace) { - return ""; - } if (backtraceMap.count(keyString) > 0) { backtraceMapLock.lock_shared(); wechat_backtrace::Backtrace *backtracePrt = backtraceMap[keyString].get(); @@ -121,7 +118,7 @@ static char* getNativeBacktrace(string keyString) { makeNativeStack(backtracePrt, nativeStack); return nativeStack; } else { - return ""; + return new char; } } From e9da383f44a6826afaec5bee18a74597cadc2f75 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 9 Jun 2022 14:19:55 +0800 Subject: [PATCH 057/263] Update task deltas collecting cfg --- .../monitor/feature/CompositeMonitors.java | 35 ++++++++++--------- .../feature/LooperTaskMonitorFeature.java | 5 +++ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 24857fb36..02cdaf8ef 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -29,6 +29,7 @@ import androidx.annotation.CallSuper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.util.Pair; /** * @author Kaede @@ -54,7 +55,7 @@ public class CompositeMonitors { // Task Tracing protected final Map, List>> mTaskDeltas = new HashMap<>(); - protected final Map>> mTaskDeltasCollect = new HashMap<>(); + protected final Map, Delta>>> mTaskDeltasCollect = new HashMap<>(); // Extra Info protected final Bundle mExtras = new Bundle(); @@ -666,16 +667,17 @@ protected void configureTaskDeltas(final Class protected void collectTaskDeltas() { if (!mTaskDeltas.isEmpty()) { - for (List> taskDeltaList : mTaskDeltas.values()) { - for (Delta taskDelta : taskDeltaList) { + for (Map.Entry, List>> entry : mTaskDeltas.entrySet()) { + Class key = entry.getKey(); + for (Delta taskDelta : entry.getValue()) { // FIXME: better windowMillis cfg of Task and AppStats if (taskDelta.bgn.time >= mBgnMillis) { - List> collectTaskList = mTaskDeltasCollect.get(taskDelta.dlt.name); - if (collectTaskList == null) { - collectTaskList = new ArrayList<>(); - mTaskDeltasCollect.put(taskDelta.dlt.name, collectTaskList); + List, Delta>> pairList = mTaskDeltasCollect.get(taskDelta.dlt.name); + if (pairList == null) { + pairList = new ArrayList<>(); + mTaskDeltasCollect.put(taskDelta.dlt.name, pairList); } - collectTaskList.add(taskDelta); + pairList.add(new Pair, Delta>(key, taskDelta)); } } } @@ -701,20 +703,21 @@ public void getTaskDeltas(Class key, Consumer>> getCollectedTaskDeltas() { + public Map, Delta>>> getCollectedTaskDeltas() { if (mTaskDeltasCollect.size() <= 1) { return mTaskDeltasCollect; } // Sorting by jiffies sum - return sortMapByValue(mTaskDeltasCollect, new Comparator>>>() { + return sortMapByValue(mTaskDeltasCollect, new Comparator, Delta>>>>() { + @SuppressWarnings("ConstantConditions") @Override - public int compare(Map.Entry>> o1, Map.Entry>> o2) { + public int compare(Map.Entry, Delta>>> o1, Map.Entry, Delta>>> o2) { long sumLeft = 0, sumRight = 0; - for (Delta item : o1.getValue()) { - sumLeft += item.dlt.jiffies.get(); + for (Pair, Delta> item : o1.getValue()) { + sumLeft += item.second.dlt.jiffies.get(); } - for (Delta item : o2.getValue()) { - sumRight += item.dlt.jiffies.get(); + for (Pair, Delta> item : o2.getValue()) { + sumRight += item.second.dlt.jiffies.get(); } long minus = sumLeft - sumRight; if (minus == 0) return 0; @@ -724,7 +727,7 @@ public int compare(Map.Entry>> o1, Map.E }); } - public void getCollectedTaskDeltas(Consumer>>> block) { + public void getCollectedTaskDeltas(Consumer, Delta>>>> block) { block.accept(getCollectedTaskDeltas()); } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java index 73693817f..520e7bc92 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java @@ -310,6 +310,11 @@ protected void onConcurrentOverHeat(String key, int concurrentCount, long during protected void onParseTaskJiffiesFail(String key, int pid, int tid) { } + @Override + protected boolean shouldTraceTask(Snapshot.Delta delta) { + return true; + } + @Deprecated public static class TaskTraceInfo { From e62ef90d7d964f7452dad3018e63c7ad91509e3a Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 10 Jun 2022 13:57:00 +0800 Subject: [PATCH 058/263] Update cfg for release --- .../batterycanary/monitor/feature/JiffiesMonitorFeature.java | 5 ++++- .../monitor/feature/LooperTaskMonitorFeature.java | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java index 94135889c..e6d0f2dda 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java @@ -505,16 +505,19 @@ public static UidJiffiesSnapshot of(Context context, boolean isStatPidProc) { List> procList = TopThreadFeature.getProcList(context); curr.pidCurrJiffiesList = new ArrayList<>(procList.size()); long sum = 0; + MatrixLog.i(TAG, "currProcList: " + procList); for (Pair item : procList) { //noinspection ConstantConditions int pid = item.first; String procName = String.valueOf(item.second); if (ProcStatUtil.exists(pid)) { - MatrixLog.i(TAG, " #exits: " + "/proc/" + pid + "/stat"); + MatrixLog.i(TAG, " exits: " + pid); JiffiesSnapshot snapshot = JiffiesSnapshot.currentJiffiesSnapshot(ProcessInfo.getProcessInfo(pid), isStatPidProc); snapshot.name = TopThreadIndicator.getProcSuffix(procName); sum += snapshot.totalJiffies.get(); curr.pidCurrJiffiesList.add(snapshot); + } else { + MatrixLog.i(TAG, " not exits: " + pid); } } curr.totalUidJiffies = DigitEntry.of(sum); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java index 520e7bc92..9babfccb9 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java @@ -6,7 +6,9 @@ import android.os.Process; import android.text.TextUtils; +import com.tencent.matrix.batterycanary.BuildConfig; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; +import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.trace.core.LooperMonitor; import com.tencent.matrix.util.MatrixLog; @@ -312,7 +314,7 @@ protected void onParseTaskJiffiesFail(String key, int pid, int tid) { @Override protected boolean shouldTraceTask(Snapshot.Delta delta) { - return true; + return BuildConfig.DEBUG || delta.during > 10L; } From ad957cc7e1f335e2c15712b4cfb4776ef3d4dde8 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 10 Jun 2022 14:08:03 +0800 Subject: [PATCH 059/263] Append --- .../batterycanary/monitor/feature/LooperTaskMonitorFeature.java | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java index 9babfccb9..3310ae40c 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/LooperTaskMonitorFeature.java @@ -8,7 +8,6 @@ import com.tencent.matrix.batterycanary.BuildConfig; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; -import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.trace.core.LooperMonitor; import com.tencent.matrix.util.MatrixLog; From c401d3e857a7aa411cb62cbe0cf5da6ef7061056 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 10 Jun 2022 15:46:18 +0800 Subject: [PATCH 060/263] sample: fix hooks sample unwind mode --- .../main/java/sample/tencent/matrix/hooks/TestHooksActivity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java index 2e83fceb8..1838530b4 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java @@ -82,7 +82,6 @@ public void onReport(ReportEvent type, Object... args) { WeChatBacktrace.instance() .configure(getApplication()) .setBacktraceMode(WeChatBacktrace.Mode.Fp) - .setQuickenAlwaysOn() .commit(); } else { WeChatBacktrace.instance() From 7ef5d00a7734e75ccde1a2289cb1464c0e9f3b3a Mon Sep 17 00:00:00 2001 From: yvesluo Date: Mon, 13 Jun 2022 15:48:25 +0800 Subject: [PATCH 061/263] resource-plugin: fix manual dump NPE --- .../matrix/resource/processor/ManualDumpProcessor.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java index 8e69322e3..b325d960e 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java @@ -181,6 +181,12 @@ private ManualDumpData dumpAndAnalyse(String activity, String key) { } catch (FileNotFoundException e) { MatrixLog.printErrStackTrace(TAG, e, ""); } + + if (file == null) { + MatrixLog.e(TAG, "prepare hprof file failed, see log above"); + return null; + } + final ActivityLeakResult result = MemoryUtil.dumpAndAnalyze(file.getAbsolutePath(), key, 600); if (result.mLeakFound) { final String leakChain = result.toString(); From 2533eb17eedc44bdf440f58674088aacee5d7b36 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 14 Jun 2022 17:48:02 +0800 Subject: [PATCH 062/263] Add battery proc file test --- .../utils/ProcStatUtilsTest.java | 180 +++++++++++++++++- .../utils/TemperatureUtilsTest.java | 16 ++ 2 files changed, 193 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/ProcStatUtilsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/ProcStatUtilsTest.java index 47047667b..0f5deae15 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/ProcStatUtilsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/ProcStatUtilsTest.java @@ -24,12 +24,9 @@ import android.os.Process; import android.os.SystemClock; import android.text.TextUtils; -import android.util.Pair; import android.util.SparseArray; import com.tencent.matrix.batterycanary.TestUtils; -import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature; -import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; import com.tencent.matrix.util.MatrixLog; import org.junit.After; @@ -41,6 +38,7 @@ import java.io.BufferedReader; import java.io.File; +import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -51,10 +49,15 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import androidx.arch.core.util.Function; +import androidx.core.util.Consumer; +import androidx.core.util.Pair; +import androidx.core.util.Supplier; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; @@ -94,6 +97,165 @@ public void testGetCurrentMethodName() { Assert.assertEquals("testGetCurrentMethodName", ste[2].getMethodName()); } + @Test + public void testGetRootProcStat() { + List names = Arrays.asList( + "asound", + "ath_pktlog", + "bldrlog", + "buddyinfo", + "bus", + "cgroups", + "cld", + "cmdline", + "config.gz", + "consoles", + "crypto", + "debugdriver", + "driver", + "dynamic_debug", + "device-tree", + "devices", + "diskstats", + "execdomains", + "fs", + "fts", + "fb", + "filesystems", + "interrupts", + "iomem", + "ioports", + "irq", + "kallsyms", + "key-users", + "keys", + "kmsg", + "kpagecount", + "kpageflags", + "loadavg", + "locks", + "misc", + "modules", + "net", + "pressure", + "pagetypeinfo", + "partitions", + "sched_debug", + "slabinfo", + "sysrq-trigger", + "schedstat", + "softirqs", + "stat", + "swaps", + "sysrq-trigger", + "scsi", + "sys", + "tty", + "timer_list", + "uid", + "uid_concurrent_active_time", + "uid_concurrent_policy_time", + "uid_cputime", + "uid_io", + "uid_procstat", + "uid_time_in_state", + "uptime", + "version", + "vmallocinfo", + "vmstat", + "zoneinfo" + ); + + final Function inWhiteList = new Function() { + @Override + public Boolean apply(File input) { + for (String item : Arrays.asList( + "/proc/sys/kernel/perf_", + "/proc/sys/kernel/random/" + )) { + if (input.getAbsolutePath().startsWith(item)) { + return true; + } + } + return false; + } + }; + + final Consumer fileConsumer = new Consumer() { + @Override + public void accept(File file) { + if (file.canRead()) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + if (files != null && files.length > 0) { + for (File item : files) { + this.accept(item); + } + } + } else { + try (InputStream is = new FileInputStream(file)) { + Collection cat = IOUtil.readLines(is); + if (!inWhiteList.apply(file)) { + Assert.assertNull("Should be null-content: " + file.getAbsolutePath(), cat); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + } + }; + for (String item : names) { + File file = new File("proc/" + item); + Assert.assertTrue("shoud exits: " + item, file.exists()); + fileConsumer.accept(file); + } + } + + @Test + public void testGetReadableRootProcStat() { + List names = Arrays.asList( + "cpuinfo", + "meminfo", + "mounts", + "sys/kernel" + ); + + final Function>, Pair>> func = new Function>, Pair>>() { + @SuppressWarnings("ConstantConditions") + @Override + public Pair> apply(Pair> input) { + if (input.first.canRead()) { + if (input.first.isDirectory()) { + File[] files = input.first.listFiles(); + if (files != null && files.length > 0) { + for (File item : files) { + this.apply(new Pair<>(item, input.second)); + } + } + } else { + try (InputStream is = new FileInputStream(input.first)) { + Collection cat = IOUtil.readLines(is); + Assert.assertNotNull("Should not be empty: " + input.first.getAbsolutePath(), cat); + input.second.add(cat.toArray(new String[0])); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + return input; + } + }; + + for (String item : names) { + File file = new File("proc/" + item); + Assert.assertTrue("shoud exits: " + item, file.exists()); + Assert.assertTrue("shoud readable: " + item, file.canRead()); + Pair> ret = func.apply(new Pair>(file, new ArrayList())); + Assert.assertNotEquals("shoud not empty: " + item, 0, ret.second.size()); + } + } + @Test public void testGetThreadJiffies() { ProcStatUtil.ProcStat stat = ProcStatUtil.current(); @@ -188,6 +350,18 @@ public void testGetCpuLoad() { public void testGetProcStat() { String cat = BatteryCanaryUtil.cat("/proc/stat"); Assert.assertTrue(TextUtils.isEmpty(cat)); + + File file = new File("/proc"); + File[] files = file.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isFile(); + } + }); + for (File item : files) { + cat = BatteryCanaryUtil.cat("/proc/stat"); + Assert.assertTrue(TextUtils.isEmpty(cat)); + } } /** diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TemperatureUtilsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TemperatureUtilsTest.java index f0770112b..2945dc677 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TemperatureUtilsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TemperatureUtilsTest.java @@ -69,6 +69,22 @@ public void setUp() { public void shutDown() { } + @Test + public void getHardwareManager() { + HardwarePropertiesManager manager = (HardwarePropertiesManager) mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE); + Assert.assertNotNull(manager); + try { + manager.getCpuUsages(); + Assert.fail("Should be permission denied"); + } catch (SecurityException ignored) { + } + try { + manager.getFanSpeeds(); + Assert.fail("Should be permission denied"); + } catch (SecurityException ignored) { + } + } + @Test public void testGetCpuTemp() { HardwarePropertiesManager manager = (HardwarePropertiesManager) mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE); From 727dc8541fea9b00c42bdd78d61a383c2913acb8 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 15 Jun 2022 11:27:13 +0800 Subject: [PATCH 063/263] Revert "resource-canary: treat soft reference as strong reference" This reverts commit 3706138994435dce37e5ac57065fdd3a4dc381ea. --- .../matrix/resource/analyzer/model/AndroidExcludedRefs.java | 5 +---- .../src/main/cpp/memory_util/excludes/excludes.cpp | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/model/AndroidExcludedRefs.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/model/AndroidExcludedRefs.java index 53060bd22..7efb93906 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/model/AndroidExcludedRefs.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/model/AndroidExcludedRefs.java @@ -684,10 +684,7 @@ void add(ExcludedRefs.Builder excluded) { @Override void add(ExcludedRefs.Builder excluded) { excluded.clazz(WeakReference.class.getName()).alwaysExclude(); -// we should treat soft reference as strong reference, because -// "all soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError." -// see https://developer.android.com/reference/java/lang/ref/SoftReference -// excluded.clazz(SoftReference.class.getName()).alwaysExclude(); + excluded.clazz(SoftReference.class.getName()).alwaysExclude(); excluded.clazz(PhantomReference.class.getName()).alwaysExclude(); excluded.clazz("java.lang.ref.Finalizer").alwaysExclude(); excluded.clazz("java.lang.ref.FinalizerReference").alwaysExclude(); diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/cpp/memory_util/excludes/excludes.cpp b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/cpp/memory_util/excludes/excludes.cpp index a6b7396e6..a18c3da4c 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/cpp/memory_util/excludes/excludes.cpp +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/cpp/memory_util/excludes/excludes.cpp @@ -931,10 +931,7 @@ bool exclude_default_references(HprofAnalyzer &analyzer) { * Non-strong references. */ analyzer.ExcludeInstanceFieldReference("java.lang.ref.WeakReference", "referent"); -// we should treat soft reference as strong reference, because -// "all soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError." -// see https://developer.android.com/reference/java/lang/ref/SoftReference -// analyzer.ExcludeInstanceFieldReference("java.lang.ref.SoftReference", "referent"); + analyzer.ExcludeInstanceFieldReference("java.lang.ref.SoftReference", "referent"); analyzer.ExcludeInstanceFieldReference("java.lang.ref.PhantomReference", "referent"); analyzer.ExcludeInstanceFieldReference("java.lang.ref.Finalizer", "prev"); analyzer.ExcludeInstanceFieldReference("java.lang.ref.Finalizer", "element"); From 7ee322a9094b9770c409aee83205bb90681a7fe3 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 15 Jun 2022 16:22:49 +0800 Subject: [PATCH 064/263] Update cpufreq sampling --- .../batterycanary/utils/CanaryUtilsTest.java | 16 +++++++++++++ .../monitor/feature/CompositeMonitors.java | 21 ++++++++++------ .../utils/BatteryCanaryUtil.java | 24 +++++++++++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java index 311966a13..353340c1b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java @@ -169,6 +169,22 @@ public void testGetCpuFreq() throws InterruptedException { } } + @Test + public void testGetCpuFreqSteps() throws InterruptedException { + List last = null; + for (int i = 0; i < 5; i++) { + List freqSteps = BatteryCanaryUtil.getCpuFreqSteps(); + Assert.assertNotNull(freqSteps); + if (last != null) { + for (int j = 0, freqStepsSize = freqSteps.size(); j < freqStepsSize; j++) { + Assert.assertArrayEquals(last.get(j), freqSteps.get(j)); + } + } + last = freqSteps; + Thread.sleep(100L); + } + } + @Test public void testGetBatteryTemps() throws InterruptedException { for (int i = 0; i < 5; i++) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 02cdaf8ef..16e92e0d1 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -485,13 +485,20 @@ public Number apply(Snapshot.Sampler sampler) { List> list = snapshot.cpuFreqs.getList(); MatrixLog.i(TAG, CompositeMonitors.this.hashCode() + " #onSampling: " + mScope); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + list); - Collections.sort(list, new Comparator>() { - @Override - public int compare(DigitEntry o1, DigitEntry o2) { - return o1.get().compareTo(o2.get()); - } - }); - return list.isEmpty() ? 0 : list.get(list.size() - 1).get(); + + // Better to use sum of all cpufreqs, rather than just use the max value? + // Collections.sort(list, new Comparator>() { + // @Override + // public int compare(DigitEntry o1, DigitEntry o2) { + // return o1.get().compareTo(o2.get()); + // } + // }); + // return list.isEmpty() ? 0 : list.get(list.size() - 1).get(); + long sum = 0; + for (DigitEntry item : list) { + sum += item.get(); + } + return sum; } }); mSamplers.put(snapshotClass, sampler); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java index 72183ddc7..2c6ef289b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java @@ -351,6 +351,30 @@ public static int[] getCpuCurrentFreq() { return output; } + public static List getCpuFreqSteps() { + int cpuCoreNum = getCpuCoreNum(); + List output = new ArrayList<>(cpuCoreNum); + for (int i = 0; i < cpuCoreNum; i++) { + String path = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_available_frequencies"; + String cat = cat(path); + if (!TextUtils.isEmpty(cat)) { + //noinspection ConstantConditions + String[] split = cat.split(" "); + int[] steps = new int[split.length]; + for (int j = 0, splitLength = split.length; j < splitLength; j++) { + try { + String item = split[j]; + steps[j] = Integer.parseInt(item) / 1000; + } catch (Exception ignored) { + steps[j] = 0; + } + } + output.add(steps); + } + } + return output; + } + public static int getCpuCoreNum() { return sCacheStub.getCpuCoreNum(); } From 892792b963d2112aba72063d5e9df73a7a4cccd3 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 15 Jun 2022 16:40:28 +0800 Subject: [PATCH 065/263] Add normalized cpuload test --- .../matrix/batterycanary/Examples.java | 46 ++++++++++++++++++- .../monitor/feature/CompositeMonitors.java | 19 ++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java index cdb18bf2d..010776319 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java @@ -37,6 +37,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.TrafficMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.WakeLockMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.WifiMonitorFeature; +import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.Consumer; import org.junit.After; @@ -45,6 +46,8 @@ import org.junit.Test; import org.junit.runner.RunWith; +import java.util.List; + import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; @@ -57,7 +60,7 @@ public class Examples { Context mContext; /** - * 监控 Cpu Load + * 计算 Cpu Load */ @Test public void exampleForCpuLoad() { @@ -72,7 +75,6 @@ public void exampleForCpuLoad() { if (monitor != null) { CompositeMonitors compositor = new CompositeMonitors(monitor.core()); compositor.metric(JiffiesMonitorFeature.JiffiesSnapshot.class); - compositor.metric(CpuStatFeature.CpuStateSnapshot.class); compositor.start(); doSomething(); @@ -112,6 +114,46 @@ public void exampleForCpuFreqSampling() { } } + /** + * 计算 Cpu Load(叠加 CpuFreq 采样权重) + */ + @Test + public void exampleForCpuLoadNormalize() { + if (TestUtils.isAssembleTest()) { + return; + } else { + mockSetup(); + } + + if (Matrix.isInstalled()) { + BatteryMonitorPlugin monitor = Matrix.with().getPluginByClass(BatteryMonitorPlugin.class); + if (monitor != null) { + CompositeMonitors compositor = new CompositeMonitors(monitor.core()); + compositor.metric(JiffiesMonitorFeature.JiffiesSnapshot.class); + compositor.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 10L); + compositor.start(); + + doSomething(); + + compositor.finish(); + int cpuLoad = compositor.getCpuLoad(); + Assert.assertTrue("cpuLoad: " + cpuLoad, cpuLoad >= 0); + + MonitorFeature.Snapshot.Sampler.Result result = compositor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class); + List cpuFreqSteps = BatteryCanaryUtil.getCpuFreqSteps(); + long sumMax = 0; + for (int[] item : cpuFreqSteps) { + sumMax += item[item.length - 1]; + } + Assert.assertTrue("cpuFreqSumAvg: " + result.sampleAvg + "vs cpuFreqSumMax: " + sumMax, sumMax >= result.sampleAvg); + int cpuLoadNormalized = (int) (cpuLoad * result.sampleAvg / sumMax); + Assert.assertTrue("cpuLoadNormalized: " + cpuLoadNormalized + "vs cpuLoad: " + sumMax, cpuLoad >= cpuLoadNormalized); + + Assert.assertEquals(cpuLoadNormalized, compositor.getNorCpuLoad()); + } + } + } + /** * 电量温度采样 */ diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 16e92e0d1..023991c44 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -175,6 +175,25 @@ public int getCpuLoad() { return (int) (cpuLoad * 100); } + public int getNorCpuLoad() { + int cpuLoad = getCpuLoad(); + if (cpuLoad == -1) { + return -1; + } + MonitorFeature.Snapshot.Sampler.Result result = getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class); + if (result == null) { + return -1; + } + List cpuFreqSteps = BatteryCanaryUtil.getCpuFreqSteps(); + long sumMax = 0; + for (int[] item : cpuFreqSteps) { + sumMax += item[item.length - 1]; + } + if (sumMax <= 0) { + return -1; + } + return (int) (cpuLoad * result.sampleAvg / sumMax); + } /** * Work in progress From bd05b6f63cb8622b3eb9838586b984e85392a1e3 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 15 Jun 2022 16:58:00 +0800 Subject: [PATCH 066/263] Update test codes --- .../java/com/tencent/matrix/batterycanary/Examples.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java index 010776319..360fa61c2 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java @@ -298,8 +298,14 @@ public void accept(MonitorFeature.Snapshot.Delta Date: Thu, 16 Jun 2022 14:05:56 +0800 Subject: [PATCH 067/263] Fix crash --- .../matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc index af90a9101..2711edd9f 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -118,7 +118,7 @@ static char* getNativeBacktrace(string keyString) { makeNativeStack(backtracePrt, nativeStack); return nativeStack; } else { - return new char; + return new char(0); } } From b770af226de4c2e9d57b61fc3ea4e603601c617f Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 22 Jun 2022 17:36:13 +0800 Subject: [PATCH 068/263] MemInfoFactory: disable log when getting oom_adj failed --- .../java/com/tencent/matrix/memory/canary/MemInfoFactory.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt index 1d747fa43..21affb910 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt @@ -242,13 +242,13 @@ data class StatusInfo( } } - private fun getOomAdj(pid: Int): Int = safeLet(TAG, defVal = Int.MAX_VALUE) { + private fun getOomAdj(pid: Int): Int = safeLet(TAG, defVal = Int.MAX_VALUE, log = false) { File("/proc/$pid/oom_adj").useLines { it.first().toInt() } } - private fun getOomScoreAdj(pid: Int): Int = safeLet(TAG, defVal = Int.MAX_VALUE) { + private fun getOomScoreAdj(pid: Int): Int = safeLet(TAG, defVal = Int.MAX_VALUE, log = false) { File("/proc/$pid/oom_score_adj").useLines { it.first().toInt() } From 989b39295f511a9b9f03ed662243b5ad5b0b5ff3 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 24 Jun 2022 11:18:34 +0800 Subject: [PATCH 069/263] Update battery metrics test --- .../matrix/batterycanary/Examples.java | 10 ++- .../utils/BatteryMetricsTest.java | 73 +++++++++++++++++-- .../utils/KernelCpuFreqPolicyReader.java | 62 ++++++++++++++++ .../utils/KernelCpuSpeedReader.java | 2 +- .../utils/KernelCpuUidFreqTimeReader.java | 2 +- 5 files changed, 137 insertions(+), 12 deletions(-) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/KernelCpuFreqPolicyReader.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java index 360fa61c2..044223b8f 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java @@ -60,7 +60,9 @@ public class Examples { Context mContext; /** - * 计算 Cpu Load + * 计算 Cpu Load: + * 1. CpuLoad 计算口径与 adb shell top 里的 CPU 负载计算一致 + * 2. CpuLoad = [0, 100 * cpu 核心数] */ @Test public void exampleForCpuLoad() { @@ -115,7 +117,11 @@ public void exampleForCpuFreqSampling() { } /** - * 计算 Cpu Load(叠加 CpuFreq 采样权重) + * 计算 Cpu Load(叠加 CpuFreq 采样权重): + * 1. CpuLoad 计算口径与 adb shell top 里的 CPU 负载计算一致 + * 2. CpuLoad = [0, 100 * cpu 核心数] + * 3. CpuLoad 只能反馈 CPU 资源的使用率, 如果需要考虑 CPU 整体负载还要考虑 CPU 大小核的工作频率, 因此需要额外加多 CpuFreq 的数据 + * 4. CpuLoadNormalized = cpuLoad * avgCpuFreq / maxCpuFreq */ @Test public void exampleForCpuLoadNormalize() { diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java index 7c9fa89cb..fa2ea8914 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java @@ -53,7 +53,6 @@ import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.JIFFY_MILLIS; import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_HOR; -import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_MIN; @RunWith(AndroidJUnit4.class) @@ -259,7 +258,7 @@ public void testReadKernelCpuSpeedState() throws IOException { for (int i = 0; i < readers.length; i++) { KernelCpuSpeedReader kernelCpuSpeedReader = readers[i]; Assert.assertNotNull(kernelCpuSpeedReader); - Assert.assertTrue(kernelCpuSpeedReader.readTotoal() > 0); + Assert.assertTrue(kernelCpuSpeedReader.readTotal() > 0); long[] cpuCoreJiffies = kernelCpuSpeedReader.readAbsolute(); Assert.assertEquals(powerProfile.getNumSpeedStepsInCpuCluster(i), cpuCoreJiffies.length); for (int j = 0; j < cpuCoreJiffies.length; j++) { @@ -291,7 +290,7 @@ public void testConfigureCpuLoad() throws IOException { for (int i = 0; i < readers.length; i++) { KernelCpuSpeedReader kernelCpuSpeedReader = readers[i]; Assert.assertNotNull(kernelCpuSpeedReader); - long cpuCoreJiffies = kernelCpuSpeedReader.readTotoal(); + long cpuCoreJiffies = kernelCpuSpeedReader.readTotal(); Assert.assertTrue("idx = " + i + ", read = " + Arrays.toString(kernelCpuSpeedReader.readAbsolute()), cpuCoreJiffies > 0); cpuJiffiesBgn += cpuCoreJiffies; } @@ -303,7 +302,7 @@ public void testConfigureCpuLoad() throws IOException { for (int i = 0; i < readers.length; i++) { KernelCpuSpeedReader kernelCpuSpeedReader = readers[i]; Assert.assertNotNull(kernelCpuSpeedReader); - long cpuCoreJiffies = kernelCpuSpeedReader.readTotoal(); + long cpuCoreJiffies = kernelCpuSpeedReader.readTotal(); Assert.assertTrue(cpuCoreJiffies > 0); cpuJiffiesEnd += cpuCoreJiffies; } @@ -346,7 +345,7 @@ public void testConfigureCpuLoadWithMultiThread() throws IOException { for (int i = 0; i < readers.length; i++) { KernelCpuSpeedReader kernelCpuSpeedReader = readers[i]; Assert.assertNotNull(kernelCpuSpeedReader); - long cpuCoreJiffies = kernelCpuSpeedReader.readTotoal(); + long cpuCoreJiffies = kernelCpuSpeedReader.readTotal(); Assert.assertTrue("idx = " + i + ", read = " + Arrays.toString(kernelCpuSpeedReader.readAbsolute()), cpuCoreJiffies > 0); cpuJiffiesBgn += cpuCoreJiffies; } @@ -366,7 +365,7 @@ public void run() { for (int i = 0; i < readers.length; i++) { KernelCpuSpeedReader kernelCpuSpeedReader = readers[i]; Assert.assertNotNull(kernelCpuSpeedReader); - long cpuCoreJiffies = kernelCpuSpeedReader.readTotoal(); + long cpuCoreJiffies = kernelCpuSpeedReader.readTotal(); Assert.assertTrue(cpuCoreJiffies > 0); cpuJiffiesEnd += cpuCoreJiffies; } @@ -513,7 +512,7 @@ public void testConfigureCpuBatterySippingDelta() throws IOException { for (int i = 0; i < readers.length; i++) { KernelCpuSpeedReader kernelCpuSpeedReader = readers[i]; Assert.assertNotNull(kernelCpuSpeedReader); - long cpuCoreJiffies = kernelCpuSpeedReader.readTotoal(); + long cpuCoreJiffies = kernelCpuSpeedReader.readTotal(); Assert.assertTrue("idx = " + i + ", read = " + Arrays.toString(kernelCpuSpeedReader.readAbsolute()), cpuCoreJiffies > 0); cpuJiffiesBgn += cpuCoreJiffies; } @@ -532,7 +531,7 @@ public void testConfigureCpuBatterySippingDelta() throws IOException { for (int i = 0; i < readers.length; i++) { KernelCpuSpeedReader kernelCpuSpeedReader = readers[i]; Assert.assertNotNull(kernelCpuSpeedReader); - long cpuCoreJiffies = kernelCpuSpeedReader.readTotoal(); + long cpuCoreJiffies = kernelCpuSpeedReader.readTotal(); Assert.assertTrue(cpuCoreJiffies > 0); cpuJiffiesEnd += cpuCoreJiffies; } @@ -809,6 +808,64 @@ public void testJiffiesConsumption2() { } } + @Test + public void testRead() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + List read = KernelCpuFreqPolicyReader.read(); + long uptimeBgn = SystemClock.uptimeMillis(); + long policyBgn = 0; + long kernelBgn = 0; + long procBgn = ProcStatUtil.of(Process.myPid()).getJiffies(); + + for (KernelCpuFreqPolicyReader item : read) { + policyBgn += item.readTotal(); + } + KernelCpuSpeedReader[] readers = new KernelCpuSpeedReader[BatteryCanaryUtil.getCpuCoreNum()]; + for (int i = 0; i < BatteryCanaryUtil.getCpuCoreNum(); i++) { + final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(powerProfile.getClusterByCpuNum(i)); + readers[i] = new KernelCpuSpeedReader(i, numSpeedSteps); + } + for (int i = 0; i < readers.length; i++) { + KernelCpuSpeedReader kernelCpuSpeedReader = readers[i]; + Assert.assertNotNull(kernelCpuSpeedReader); + long cpuCoreJiffies = kernelCpuSpeedReader.readTotal(); + Assert.assertTrue("idx = " + i + ", read = " + Arrays.toString(kernelCpuSpeedReader.readAbsolute()), cpuCoreJiffies > 0); + kernelBgn += cpuCoreJiffies; + } + + // No matter full-running or sleep, the delta of cpufreq policy & cpu speed time is always the same? + CpuConsumption.hanoi(20); + // try { + // Thread.sleep(10000L); + // } catch (InterruptedException e) { + // e.printStackTrace(); + // } + + long uptimeEnd = SystemClock.uptimeMillis(); + long policyEnd = 0; + long kernelEnd = 0; + long procEnd = ProcStatUtil.of(Process.myPid()).getJiffies(); + + for (KernelCpuFreqPolicyReader item : read) { + policyEnd += item.readTotal(); + } + for (int i = 0; i < readers.length; i++) { + KernelCpuSpeedReader kernelCpuSpeedReader = readers[i]; + Assert.assertNotNull(kernelCpuSpeedReader); + long cpuCoreJiffies = kernelCpuSpeedReader.readTotal(); + Assert.assertTrue(cpuCoreJiffies > 0); + kernelEnd += cpuCoreJiffies; + } + + Assert.fail("policy: " + (policyEnd - policyBgn) * 10f / (uptimeEnd - uptimeBgn) + + ", kernel: " + (kernelEnd - kernelBgn) * 10f / (uptimeEnd - uptimeBgn) + + ", procStat: " + (procEnd - procBgn) * 10f / (uptimeEnd - uptimeBgn) + ); + } + public static class CpuConsumption { public static void inc(int num) { for (int i = 0; i < num; i++) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/KernelCpuFreqPolicyReader.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/KernelCpuFreqPolicyReader.java new file mode 100644 index 000000000..20b3ec3d5 --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/KernelCpuFreqPolicyReader.java @@ -0,0 +1,62 @@ +package com.tencent.matrix.batterycanary.utils; + + +import android.text.TextUtils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +public class KernelCpuFreqPolicyReader { + private static final String TAG = "KernelCpuSpeedReader"; + + public static List read() { + List list = new ArrayList<>(); + File file = new File("/sys/devices/system/cpu/cpufreq/"); + File[] files = file.listFiles(); + if (files != null) { + for (File item : files) { + if (item.isDirectory() && item.getName().startsWith("policy") && item.canRead()) { + list.add(new KernelCpuFreqPolicyReader(item.getName())); + } + } + } + return list; + } + + private final String mPolicy; + private final String mProcFile; + + public KernelCpuFreqPolicyReader(String policy) { + mPolicy = policy; + mProcFile = "/sys/devices/system/cpu/cpufreq/" + policy + "/stats/time_in_state"; + } + + public long readTotal() throws IOException { + long sum = 0; + for (long item : readAbsolute()) { + sum += item; + } + return sum; + } + + public List readAbsolute() throws IOException { + List speedTimeJiffies = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(mProcFile))) { + TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); + String line; + while ((line = reader.readLine()) != null) { + splitter.setString(line); + splitter.next(); + speedTimeJiffies.add(Long.parseLong(splitter.next())); + } + } catch (Throwable e) { + throw new IOException("Failed to read cpu-freq time: " + e.getMessage(), e); + } + return speedTimeJiffies; + } +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/KernelCpuSpeedReader.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/KernelCpuSpeedReader.java index cd927965a..010aa133e 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/KernelCpuSpeedReader.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/KernelCpuSpeedReader.java @@ -39,7 +39,7 @@ public void smoke() throws IOException { } } - public long readTotoal() throws IOException { + public long readTotal() throws IOException { long sum = 0; for (long item : readAbsolute()) { sum += item; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/KernelCpuUidFreqTimeReader.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/KernelCpuUidFreqTimeReader.java index 248afed47..2d4d3e0c6 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/KernelCpuUidFreqTimeReader.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/KernelCpuUidFreqTimeReader.java @@ -54,7 +54,7 @@ public void smoke() throws IOException { } } - public List readTotoal() throws IOException { + public List readTotal() throws IOException { List cpuCoreStepJiffies = readAbsolute(); List cpuCoreJiffies = new ArrayList<>(cpuCoreStepJiffies.size()); for (long[] stepJiffies : cpuCoreStepJiffies) { From d6ed7336b585d6dd5182224ff671e156eb1c9d3a Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 24 Jun 2022 18:29:56 +0800 Subject: [PATCH 070/263] Update cpu core num test --- .../matrix/batterycanary/asm/KotlinTesting.kt | 7 ++++++ .../batterycanary/utils/CanaryUtilsTest.java | 25 +++++++++++++++++++ .../monitor/BatteryMonitorCallback.java | 3 +-- .../utils/BatteryCanaryUtil.java | 7 +++++- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/asm/KotlinTesting.kt b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/asm/KotlinTesting.kt index b8a98c142..677034199 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/asm/KotlinTesting.kt +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/asm/KotlinTesting.kt @@ -8,6 +8,7 @@ import android.bluetooth.le.ScanCallback import android.bluetooth.le.ScanFilter import android.bluetooth.le.ScanSettings import android.content.Context +import android.hardware.Camera import android.location.Criteria import android.location.LocationListener import android.location.LocationManager @@ -79,4 +80,10 @@ class KotlinTesting { am.cancel(pendingIntent) am.cancel {} } + + fun testCamera(context: Context) { + val camera = Camera.open() + camera.startPreview() + camera.release() + } } \ No newline at end of file diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java index 353340c1b..fa3c1a762 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java @@ -29,6 +29,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.PowerManager; +import android.os.SystemClock; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; @@ -46,6 +47,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.LinkedList; @@ -133,6 +135,29 @@ public void testGetPkgName() { Assert.assertEquals(mContext.getPackageName(), pkg); } + @Test + public void testGetCpuCoreNum() throws IOException { + long nanos1 = SystemClock.elapsedRealtimeNanos(); + + int coreNum1 = BatteryCanaryUtil.getCpuCoreNumImmediately(); + long nanos2 = SystemClock.elapsedRealtimeNanos(); + + int coreNum2 = Runtime.getRuntime().availableProcessors(); + long nanos3 = SystemClock.elapsedRealtimeNanos(); + + PowerProfile powerProfile = PowerProfile.init(mContext); + int coreNum3 = powerProfile.getCpuCoreNum(); + long nanos4 = SystemClock.elapsedRealtimeNanos(); + + + Assert.assertEquals(coreNum1, coreNum2); + Assert.assertEquals(coreNum2, coreNum3); + + if (!TestUtils.isAssembleTest()) { + Assert.fail((nanos2 - nanos1) + " vs " + (nanos3 - nanos2) + " vs " + (nanos4 - nanos3)); + } + } + @Test public void testGetThrowableStack() { if (TestUtils.isAssembleTest()) return; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java index 0845d75a7..5a6b7ccfa 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java @@ -1,7 +1,6 @@ package com.tencent.matrix.batterycanary.monitor; import android.content.ComponentName; -import android.os.Process; import android.os.SystemClock; import android.text.TextUtils; @@ -420,7 +419,7 @@ protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, final // header long minute = Math.max(1, delta.during / ONE_MIN); long avgJiffies = delta.dlt.totalJiffies.get() / minute; - printer.append("| ").append("pid=").append(Process.myPid()) + printer.append("| ").append("cpu=").append(monitors.getCpuLoad()).append("/").append(monitors.getNorCpuLoad()) .tab().tab().append("fg=").append(BatteryCanaryUtil.convertAppStat(appStats.getAppStat())) .tab().tab().append("during(min)=").append(minute) .tab().tab().append("diff(jiffies)=").append(delta.dlt.totalJiffies.get()) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java index 2c6ef289b..7dc42f4c0 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java @@ -395,10 +395,15 @@ public boolean accept(File pathname) { return files.length; } catch (Exception ignored) { // Default to return 1 core - return 1; + return getCpuCoreNumFromRuntime(); } } + public static int getCpuCoreNumFromRuntime() { + // fastest + return Runtime.getRuntime().availableProcessors(); + } + @Nullable public static String cat(String path) { if (TextUtils.isEmpty(path)) return null; From 00dd2ab5db14501b831705291662100379391f6c Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 27 Jun 2022 20:24:21 +0800 Subject: [PATCH 071/263] Update used resId parsing --- .../tencent/matrix/apk/model/task/UnusedResourcesTask.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java index 8962d9c3e..f3acf63e6 100644 --- a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java +++ b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java @@ -363,6 +363,13 @@ private void readSmaliLines(String[] lines) { resourceRefSet.add(resourceDefMap.get(resId)); } } + if (line.trim().startsWith("0x")) { + final String resId = parseResourceId(line.trim()); + if (!Util.isNullOrNil(resId) && resourceDefMap.containsKey(resId)) { + Log.d(TAG, "array field resource, %s", resId); + resourceRefSet.add(resourceDefMap.get(resId)); + } + } } } } From a450a3dbafb9cbc48d8c552ea382ea5ef3aa6bfd Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 28 Jun 2022 19:47:05 +0800 Subject: [PATCH 072/263] TrimMemoryNotifier: limit the frequency of system trim --- .../memory/canary/trim/TrimMemoryNotifier.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt index 81810e73b..4ae2afc68 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt @@ -11,6 +11,7 @@ import com.tencent.matrix.Matrix import com.tencent.matrix.lifecycle.IBackgroundStatefulOwner import com.tencent.matrix.lifecycle.IMatrixBackgroundCallback import com.tencent.matrix.lifecycle.owners.ProcessDeepBackgroundOwner +import com.tencent.matrix.lifecycle.owners.ProcessExplicitBackgroundOwner import com.tencent.matrix.lifecycle.owners.ProcessStagedBackgroundOwner import com.tencent.matrix.lifecycle.supervisor.AppDeepBackgroundOwner import com.tencent.matrix.lifecycle.supervisor.AppStagedBackgroundOwner @@ -139,7 +140,34 @@ object TrimMemoryNotifier { // system trim Matrix.with().application.registerComponentCallbacks(object : ComponentCallbacks2 { + + private var lastTrimTimeMillis = 0L + + @Volatile + private var trimCounter = 0 + private val maxTrimCount = 10 + + init { + ProcessExplicitBackgroundOwner.addLifecycleCallback(object : + IMatrixBackgroundCallback() { + + override fun onEnterBackground() { + // reset trim + trimCounter = 0 + } + + override fun onExitBackground() {} + }) + } + override fun onLowMemory() { + val current = System.currentTimeMillis() + if (current - lastTrimTimeMillis < TimeUnit.MINUTES.toMillis((trimCounter + 1).toLong()) || trimCounter >= maxTrimCount) { + MatrixLog.w(TAG, "onLowMemory skip for frequency") + return + } + lastTrimTimeMillis = current + trimCounter++ MatrixLog.e(TAG, "onLowMemory post") MatrixHandlerThread.getDefaultHandler().post { MatrixLog.e(TAG, "onLowMemory") @@ -150,6 +178,13 @@ object TrimMemoryNotifier { override fun onTrimMemory(level: Int) { if (level <= ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) { + val current = System.currentTimeMillis() + if (current - lastTrimTimeMillis < TimeUnit.MINUTES.toMillis((trimCounter + 1).toLong()) || trimCounter >= maxTrimCount) { + MatrixLog.w(TAG, "onLowMemory skip for frequency") + return + } + lastTrimTimeMillis = current + trimCounter++ MatrixLog.e(TAG, "onTrimMemory post: $level") MatrixHandlerThread.getDefaultHandler().post { MatrixLog.e(TAG, "onTrimMemory: $level") From ee67537b5fc48c9184fb6597a46918302ab1a529 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 29 Jun 2022 19:43:46 +0800 Subject: [PATCH 073/263] resource-plugin: remove Java analyze for native-fork-analyze mode --- .../processor/NativeForkAnalyzeProcessor.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt index 7939fe492..1efddbfb0 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/NativeForkAnalyzeProcessor.kt @@ -140,17 +140,17 @@ class NativeForkAnalyzeProcessor(watcher: ActivityRefWatcher) : BaseLeakProcesso var result = MemoryUtil.analyze(hprof.absolutePath, key, timeout = 1200) if (result.mFailure != null) { historyFailure.add(result.mFailure.toString()) - retryCount++ - safeLetOrNull(TAG) { - HprofFileManager.prepareHprofFile("RETRY", false) // prevent duplicated analyse after OOM - }?.let { cpy -> - hprof.copyTo(cpy, true) - hprof.deleteIfExist() - keyFile.deleteIfExist() - safeLet({ - result = analyze(cpy, key) // if crashed, the copied file could be auto-cleared by HprofFileManager later (lru or expired) - }, success = { cpy.deleteIfExist() }, failed = { cpy.deleteIfExist() }) - } +// retryCount++ +// safeLetOrNull(TAG) { +// HprofFileManager.prepareHprofFile("RETRY", false) // prevent duplicated analyse after OOM +// }?.let { cpy -> +// hprof.copyTo(cpy, true) +// hprof.deleteIfExist() +// keyFile.deleteIfExist() +// safeLet({ +// result = analyze(cpy, key) // if crashed, the copied file could be auto-cleared by HprofFileManager later (lru or expired) +// }, success = { cpy.deleteIfExist() }, failed = { cpy.deleteIfExist() }) +// } } if (result.mLeakFound) { watcher.markPublished(activity, false) From df34852a986e8cb2888eae3aa220ecd567ef897c Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 1 Jul 2022 20:54:53 +0800 Subject: [PATCH 074/263] Update uid jiffies with ipc collecting support --- .../monitor/BatteryMonitorConfig.java | 9 + .../feature/JiffiesMonitorFeature.java | 162 +++++++++++++++++- 2 files changed, 165 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java index 4dcebab48..81992180d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java @@ -3,10 +3,12 @@ import android.app.ActivityManager; import com.tencent.matrix.batterycanary.BuildConfig; +import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.UidJiffiesSnapshot.IpcJiffies.IpcProcessJiffies; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; import com.tencent.matrix.batterycanary.stats.BatteryRecorder; import com.tencent.matrix.batterycanary.stats.BatteryStats; import com.tencent.matrix.batterycanary.utils.CallStackCollector; +import com.tencent.matrix.batterycanary.utils.Function; import java.util.ArrayList; import java.util.Collections; @@ -16,6 +18,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.util.Pair; /** * @author Kaede @@ -64,6 +67,7 @@ public class BatteryMonitorConfig { public BatteryRecorder batteryRecorder; public BatteryStats batteryStats; public CallStackCollector callStackCollector; + public Function, IpcProcessJiffies> ipcJiffiesCollector; private BatteryMonitorConfig() { } @@ -285,6 +289,11 @@ public Builder setCollector(CallStackCollector collector) { return this; } + public Builder setCollector(Function, IpcProcessJiffies> collector) { + config.ipcJiffiesCollector = collector; + return this; + } + public BatteryMonitorConfig build() { Collections.sort(config.features, new Comparator() { @Override diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java index e6d0f2dda..898992643 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java @@ -3,13 +3,15 @@ import android.content.Context; import android.os.Handler; import android.os.HandlerThread; +import android.os.Parcel; +import android.os.Parcelable; import android.os.Process; import android.os.SystemClock; import android.text.TextUtils; import com.tencent.matrix.Matrix; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore.Callback; -import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.ListEntry; import com.tencent.matrix.batterycanary.shell.TopThreadFeature; @@ -89,7 +91,7 @@ public JiffiesSnapshot currentJiffiesSnapshot(int pid) { @WorkerThread public UidJiffiesSnapshot currentUidJiffiesSnapshot() { - return UidJiffiesSnapshot.of(mCore.getContext(), mCore.getConfig().isStatPidProc); + return UidJiffiesSnapshot.of(mCore.getContext(), mCore.getConfig()); } @AnyThread @@ -500,7 +502,7 @@ private long setNext(long millis) { } public static class UidJiffiesSnapshot extends Snapshot { - public static UidJiffiesSnapshot of(Context context, boolean isStatPidProc) { + public static UidJiffiesSnapshot of(Context context, BatteryMonitorConfig config) { UidJiffiesSnapshot curr = new UidJiffiesSnapshot(); List> procList = TopThreadFeature.getProcList(context); curr.pidCurrJiffiesList = new ArrayList<>(procList.size()); @@ -511,13 +513,24 @@ public static UidJiffiesSnapshot of(Context context, boolean isStatPidProc) { int pid = item.first; String procName = String.valueOf(item.second); if (ProcStatUtil.exists(pid)) { - MatrixLog.i(TAG, " exits: " + pid); - JiffiesSnapshot snapshot = JiffiesSnapshot.currentJiffiesSnapshot(ProcessInfo.getProcessInfo(pid), isStatPidProc); + MatrixLog.i(TAG, "proc: " + pid); + JiffiesSnapshot snapshot = JiffiesSnapshot.currentJiffiesSnapshot(ProcessInfo.getProcessInfo(pid), config.isStatPidProc); snapshot.name = TopThreadIndicator.getProcSuffix(procName); sum += snapshot.totalJiffies.get(); curr.pidCurrJiffiesList.add(snapshot); } else { - MatrixLog.i(TAG, " not exits: " + pid); + if (config.ipcJiffiesCollector != null) { + IpcJiffies.IpcProcessJiffies ipcProcessJiffies = config.ipcJiffiesCollector.apply(item); + if (ipcProcessJiffies != null) { + MatrixLog.i(TAG, "ipc: " + pid); + JiffiesSnapshot snapshot = IpcJiffies.toLocal(ipcProcessJiffies); + snapshot.name = TopThreadIndicator.getProcSuffix(procName); + sum += snapshot.totalJiffies.get(); + curr.pidCurrJiffiesList.add(snapshot); + continue; + } + } + MatrixLog.i(TAG, "skip: " + pid); } } curr.totalUidJiffies = DigitEntry.of(sum); @@ -574,5 +587,142 @@ public int compare(Delta o1, Delta o2) { } }; } + + + public static final class IpcJiffies { + public static IpcProcessJiffies toIpc(JiffiesSnapshot local) { + IpcProcessJiffies ipc = new IpcProcessJiffies(); + ipc.pid = local.pid; + ipc.name = local.name; + ipc.threadNum = local.threadNum.get(); + ipc.totalJiffies = local.totalJiffies.get(); + ipc.threadJiffyList = new ArrayList<>(local.threadEntries.getList().size()); + for (JiffiesSnapshot.ThreadJiffiesSnapshot item : local.threadEntries.getList()) { + ipc.threadJiffyList.add(toIpc(item)); + } + return ipc; + } + + public static IpcProcessJiffies.IpcThreadJiffies toIpc(JiffiesSnapshot.ThreadJiffiesSnapshot local) { + IpcProcessJiffies.IpcThreadJiffies ipc = new IpcProcessJiffies.IpcThreadJiffies(); + ipc.tid = local.tid; + ipc.name = local.name; + ipc.stat = local.stat; + ipc.jiffies = local.get(); + return ipc; + } + + public static JiffiesSnapshot toLocal(IpcProcessJiffies ipc) { + JiffiesSnapshot local = new JiffiesSnapshot(); + local.pid = ipc.pid; + local.name = ipc.name; + local.totalJiffies = DigitEntry.of(ipc.totalJiffies); + List threadJiffiesList = Collections.emptyList(); + if (!ipc.threadJiffyList.isEmpty()) { + threadJiffiesList = new ArrayList<>(ipc.threadJiffyList.size()); + for (IpcProcessJiffies.IpcThreadJiffies item : ipc.threadJiffyList) { + JiffiesSnapshot.ThreadJiffiesSnapshot threadJiffies = toLocal(item); + threadJiffiesList.add(threadJiffies); + } + } + local.threadEntries = ListEntry.of(threadJiffiesList); + local.threadNum = DigitEntry.of(threadJiffiesList.size()); + return local; + } + + public static JiffiesSnapshot.ThreadJiffiesSnapshot toLocal(IpcProcessJiffies.IpcThreadJiffies ipc) { + JiffiesSnapshot.ThreadJiffiesSnapshot local = new JiffiesSnapshot.ThreadJiffiesSnapshot(ipc.jiffies); + local.name = ipc.name; + local.stat = ipc.stat; + local.tid = ipc.tid; + local.isNewAdded = true; + return local; + } + + public static class IpcProcessJiffies implements Parcelable { + public int pid; + public String name; + public long totalJiffies; + public int threadNum; + public List threadJiffyList; + + protected IpcProcessJiffies(Parcel in) { + pid = in.readInt(); + name = in.readString(); + totalJiffies = in.readLong(); + threadNum = in.readInt(); + threadJiffyList = in.createTypedArrayList(IpcThreadJiffies.CREATOR); + } + + public static final Creator CREATOR = new Creator() { + @Override + public IpcProcessJiffies createFromParcel(Parcel in) { + return new IpcProcessJiffies(in); + } + @Override + public IpcProcessJiffies[] newArray(int size) { + return new IpcProcessJiffies[size]; + } + }; + + public IpcProcessJiffies() { + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(pid); + dest.writeString(name); + dest.writeLong(totalJiffies); + dest.writeInt(threadNum); + dest.writeTypedList(threadJiffyList); + } + + public static class IpcThreadJiffies implements Parcelable { + public int tid; + public String name; + public String stat; + public long jiffies; + + protected IpcThreadJiffies(Parcel in) { + tid = in.readInt(); + name = in.readString(); + stat = in.readString(); + jiffies = in.readLong(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public IpcThreadJiffies createFromParcel(Parcel in) { + return new IpcThreadJiffies(in); + } + @Override + public IpcThreadJiffies[] newArray(int size) { + return new IpcThreadJiffies[size]; + } + }; + + public IpcThreadJiffies() { + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(tid); + dest.writeString(name); + dest.writeString(stat); + dest.writeLong(jiffies); + } + } + } + } } } From 3829c0e9d54bea0fba7489eb4332be1adde00ef0 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 5 Jul 2022 19:38:06 +0800 Subject: [PATCH 075/263] Update battery avg jiffies cfg --- .../src/androidTest/AndroidManifest.xml | 7 +++++++ .../monitor/BatteryMonitorCallback.java | 6 +++--- .../monitor/feature/CompositeMonitors.java | 19 +++++++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml index 34c4adfb8..1e6c6be76 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml @@ -1,4 +1,5 @@ @@ -8,6 +9,12 @@ + + + diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java index 5a6b7ccfa..4eb351a0d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java @@ -418,7 +418,7 @@ protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, final Delta delta = (Delta) sessionDelta; // header long minute = Math.max(1, delta.during / ONE_MIN); - long avgJiffies = delta.dlt.totalJiffies.get() / minute; + long avgJiffies = monitors.computeAvgJiffies(delta.dlt.totalJiffies.get()); printer.append("| ").append("cpu=").append(monitors.getCpuLoad()).append("/").append(monitors.getNorCpuLoad()) .tab().tab().append("fg=").append(BatteryCanaryUtil.convertAppStat(appStats.getAppStat())) .tab().tab().append("during(min)=").append(minute) @@ -439,7 +439,7 @@ protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, final if (i < toppingCount) { printer.append("| -> (").append(threadJiffies.isNewAdded ? "+" : "~").append("/").append(threadJiffies.stat).append(")") .append(threadJiffies.name).append("(").append(threadJiffies.tid).append(")\t") - .append(entryJffies / minute).append("/").append(entryJffies).append("\tjiffies") + .append(monitors.computeAvgJiffies(entryJffies)).append("/").append(entryJffies).append("\tjiffies") .append("\n"); } else { remainJffies += entryJffies; @@ -449,7 +449,7 @@ protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, final if (remainJffies > 0) { printer.append("| -> R/R)") .append("REMAINS").append("(").append(delta.dlt.threadEntries.getList().size() - toppingCount).append(")\t") - .append(remainJffies / minute).append("/").append(remainJffies).append("\tjiffies") + .append(monitors.computeAvgJiffies(remainJffies) / minute).append("/").append(remainJffies).append("\tjiffies") .append("\n"); } if (avgJiffies > 1000L || !delta.isValid()) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 023991c44..543369a18 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -215,6 +215,21 @@ public int getDevCpuLoad() { return (int) (cpuLoad * 100); } + public long computeAvgJiffies(long jiffies) { + if (mAppStats == null) { + MatrixLog.w(TAG, "AppStats should not be null to computeAvgJiffies"); + return -1; + } + return computeAvgJiffies(jiffies, mAppStats.duringMillis); + } + + public static long computeAvgJiffies(long jiffies, long millis) { + if (millis <= 0) { + throw new IllegalArgumentException("Illegal millis: " + millis); + } + return (long) (jiffies / (millis / 60000f)); + } + public > boolean isOverHeat(Class snapshotClass) { AppStats appStats = getAppStats(); Delta delta = getDelta(snapshotClass); @@ -621,10 +636,10 @@ public Number apply(Snapshot.Sampler sampler) { if (mLastSnapshot != null) { Delta delta = curr.diff(mLastSnapshot); long minute = Math.max(1, delta.during / BatteryCanaryUtil.ONE_MIN); - long avgUidJiffies = delta.dlt.totalUidJiffies.get() / minute; + long avgUidJiffies = computeAvgJiffies(delta.dlt.totalUidJiffies.get(), delta.during); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgUidJiffies, val = " + avgUidJiffies + ", minute = " + minute); for (Delta item : delta.dlt.pidDeltaJiffiesList) { - long avgPidJiffies = item.dlt.totalJiffies.get() / minute; + long avgPidJiffies = computeAvgJiffies(item.dlt.totalJiffies.get(), delta.during); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + " avgPidJiffies, val = " + avgPidJiffies + ", minute = " + minute + ", name = " + item.dlt.name); } mLastSnapshot = curr; From 9909d84f9f29697dcadc5a2f08b456f10d18bbe4 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 7 Jul 2022 14:10:03 +0800 Subject: [PATCH 076/263] Add battery healthstats test --- .../batterycanary/utils/HealthStatsTest.java | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java new file mode 100644 index 000000000..5b2653c70 --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java @@ -0,0 +1,143 @@ +/* + * Tencent is pleased to support the open source community by making wechat-matrix available. + * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tencent.matrix.batterycanary.utils; + +import android.app.Application; +import android.content.Context; +import android.os.health.HealthStats; +import android.os.health.PidHealthStats; +import android.os.health.SystemHealthManager; +import android.os.health.TimerStat; +import android.os.health.UidHealthStats; + +import com.tencent.matrix.Matrix; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + + +@RunWith(AndroidJUnit4.class) +public class HealthStatsTest { + static final String TAG = "Matrix.test.HealthStatsTest"; + + Context mContext; + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + if (!Matrix.isInstalled()) { + Matrix.init(new Matrix.Builder(((Application) mContext.getApplicationContext())).build()); + } + } + + @After + public void shutDown() { + } + + + @Test + public void testLiterateStats() { + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + Assert.assertEquals("UidHealthStats", healthStats.getDataType()); + + List statsList = new ArrayList<>(); + statsList.add(healthStats); + + int statsKeyCount = healthStats.getStatsKeyCount(); + Assert.assertTrue(statsKeyCount > 0); + + for (int i = 0; i < statsKeyCount; i++) { + int key = healthStats.getStatsKeyAt(i); + if (healthStats.hasStats(key)) { + Map stats = healthStats.getStats(key); + for (HealthStats item : stats.values()) { + Assert.assertTrue(Arrays.asList( + "PidHealthStats", + "ProcessHealthStats", + "PackageHealthStats", + "ServiceHealthStats" + ).contains(item.getDataType())); + + statsList.add(item); + + int subKeyCount = item.getStatsKeyCount(); + if (subKeyCount > 0) { + for (int j = 0; j < subKeyCount; j++) { + int subKey = item.getStatsKeyAt(j); + if (item.hasStats(subKey)) { + statsList.addAll(item.getStats(subKey).values()); + } + } + } + } + } + } + + for (HealthStats item : statsList) { + int count = item.getMeasurementKeyCount(); + for (int i = 0; i < count; i++) { + int key = item.getMeasurementKeyAt(i); + long value = item.getMeasurement(key); + Assert.assertTrue(item.getDataType() + ": " + key + "=" + value, value >= 0); + } + } + for (HealthStats item : statsList) { + int count = item.getMeasurementsKeyCount(); + for (int i = 0; i < count; i++) { + int key = item.getMeasurementsKeyAt(i); + Map values = item.getMeasurements(key); + for (Map.Entry entry : values.entrySet()) { + Assert.assertTrue(item.getDataType() + ": " + entry.getKey() + "=" + entry.getValue(), entry.getValue() >= 0); + } + } + } + + for (HealthStats item : statsList) { + int count = item.getTimerKeyCount(); + for (int i = 0; i < count; i++) { + int key = item.getTimerKeyAt(i); + TimerStat timerStat = item.getTimer(key); + Assert.assertTrue(item.getDataType() + ": " + key + "=" + timerStat.getCount() + "," + timerStat.getTime(), timerStat.getCount() >= 0); + Assert.assertTrue(item.getDataType() + ": " + key + "=" + timerStat.getCount() + "," + timerStat.getTime(), timerStat.getTime() >= 0); + } + } + for (HealthStats item : statsList) { + int count = item.getTimersKeyCount(); + for (int i = 0; i < count; i++) { + int key = item.getTimersKeyAt(i); + Map timerStatMap = item.getTimers(key); + for (Map.Entry entry : timerStatMap.entrySet()) { + Assert.assertTrue(item.getDataType() + ": " + entry.getKey() + "=" + entry.getValue().getCount() + "," + entry.getValue().getTime(), entry.getValue().getCount() >= 0); + Assert.assertTrue(item.getDataType() + ": " + entry.getKey() + "=" + entry.getValue().getCount() + "," + entry.getValue().getTime(), entry.getValue().getTime() >= 0); + } + } + } + } +} \ No newline at end of file From 6a5f7f59b502b666c3c24d445a7fad76ee332c79 Mon Sep 17 00:00:00 2001 From: leafjia Date: Sun, 10 Jul 2022 22:52:54 +0800 Subject: [PATCH 077/263] use condition_variable --- .../src/main/cpp/TouchEventTracer.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.cc b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.cc index c0c229ce1..f465be880 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.cc +++ b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.cc @@ -15,7 +15,7 @@ using namespace std; static mutex queueMutex; -static lock_guard lock(queueMutex); +static condition_variable cv; static bool loopRunning = false; static bool startDetect = false; static int LAG_THRESHOLD; @@ -37,7 +37,7 @@ void TouchEventTracer::touchRecv(int fd) { lastRecvTouchEventTimeStamp = 0; } else { lastRecvTouchEventTimeStamp = time(nullptr); - queueMutex.unlock(); + cv.notify_one(); } } @@ -52,10 +52,10 @@ void TouchEventTracer::touchSendFinish(int fd) { void recvQueueLooper() { - queueMutex.lock(); + unique_lock lk(queueMutex); while (loopRunning) { if (lastRecvTouchEventTimeStamp == 0) { - queueMutex.lock(); + cv.wait(lk); } else { long lastRecvTouchEventTimeStampNow = lastRecvTouchEventTimeStamp; if (lastRecvTouchEventTimeStampNow <= 0) { @@ -65,7 +65,7 @@ void recvQueueLooper() { if (time(nullptr) - lastRecvTouchEventTimeStampNow >= LAG_THRESHOLD && startDetect) { lagFd = currentFd; onTouchEventLagDumpTrace(currentFd); - queueMutex.lock(); + cv.wait(lk); } } } From 72bbc0a0fecffd6d690a4e8304a70f400afb6dac Mon Sep 17 00:00:00 2001 From: leafjia Date: Sun, 10 Jul 2022 23:35:58 +0800 Subject: [PATCH 078/263] Matrix Traffic Upgrade --- .../src/main/cpp/common/HookCommon.h | 1 + .../src/main/cpp/MatrixTraffic.cc | 94 ++++++++++++++----- .../src/main/cpp/TrafficCollector.cc | 35 +++++-- .../tencent/matrix/traffic/TrafficConfig.java | 10 ++ .../tencent/matrix/traffic/TrafficPlugin.java | 4 +- 5 files changed, 114 insertions(+), 30 deletions(-) diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h b/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h index 1e6952c54..d38c1c1a2 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h @@ -100,6 +100,7 @@ xhook_grouped_ignore(group_id, ".*/libmatrix-opengl-leak\\.so$", NULL); \ xhook_grouped_ignore(group_id, ".*/libmatrix-memguard\\.so$", NULL);\ xhook_grouped_ignore(group_id, ".*/libTcpOptimizer\\.mobiledata\\.samsung\\.so$", NULL); \ + xhook_grouped_ignore(group_id, ".*/libmatrix-traffic\\.so$", NULL);\ } while (0) #include diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc index 2711edd9f..d4402ad9d 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -125,14 +125,18 @@ static char* getNativeBacktrace(string keyString) { ssize_t (*original_read)(int fd, void *buf, size_t count); ssize_t my_read(int fd, void *buf, size_t count) { ssize_t ret = original_read(fd, buf, count); - TrafficCollector::enQueueRx(MSG_TYPE_READ, fd, ret); + if (ret > 0) { + TrafficCollector::enQueueRx(MSG_TYPE_READ, fd, ret); + } return ret; } ssize_t (*original_recv)(int sockfd, void *buf, size_t len, int flags); ssize_t my_recv(int sockfd, void *buf, size_t len, int flags) { ssize_t ret = original_recv(sockfd, buf, len, flags); - TrafficCollector::enQueueRx(MSG_TYPE_RECV, sockfd, ret); + if (ret > 0) { + TrafficCollector::enQueueRx(MSG_TYPE_RECV, sockfd, ret); + } return ret; } @@ -141,28 +145,36 @@ ssize_t (*original_recvfrom)(int sockfd, void *buf, size_t len, int flags, ssize_t my_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { ssize_t ret = original_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); - TrafficCollector::enQueueRx(MSG_TYPE_RECVFROM, sockfd, ret); + if (ret > 0) { + TrafficCollector::enQueueRx(MSG_TYPE_RECVFROM, sockfd, ret); + } return ret; } ssize_t (*original_recvmsg)(int sockfd, struct msghdr *msg, int flags); ssize_t my_recvmsg(int sockfd, struct msghdr *msg, int flags) { ssize_t ret = original_recvmsg(sockfd, msg, flags); - TrafficCollector::enQueueRx(MSG_TYPE_RECVMSG, sockfd, ret); + if (ret > 0) { + TrafficCollector::enQueueRx(MSG_TYPE_RECVMSG, sockfd, ret); + } return ret; } ssize_t (*original_write)(int fd, const void *buf, size_t count); ssize_t my_write(int fd, const void *buf, size_t count) { ssize_t ret = original_write(fd, buf, count); - TrafficCollector::enQueueTx(MSG_TYPE_WRITE, fd, ret); + if (ret > 0) { + TrafficCollector::enQueueTx(MSG_TYPE_WRITE, fd, ret); + } return ret; } ssize_t (*original_send)(int sockfd, const void *buf, size_t len, int flags); ssize_t my_send(int sockfd, const void *buf, size_t len, int flags) { ssize_t ret = original_send(sockfd, buf, len, flags); - TrafficCollector::enQueueTx(MSG_TYPE_SEND, sockfd, ret); + if (ret > 0) { + TrafficCollector::enQueueTx(MSG_TYPE_SEND, sockfd, ret); + } return ret; } @@ -171,21 +183,38 @@ ssize_t (*original_sendto)(int sockfd, const void *buf, size_t len, int flags, ssize_t my_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { ssize_t ret = original_sendto(sockfd, buf, len, flags, dest_addr, addrlen); - TrafficCollector::enQueueTx(MSG_TYPE_SENDTO, sockfd, ret); + if (ret > 0) { + TrafficCollector::enQueueTx(MSG_TYPE_SENDTO, sockfd, ret); + } return ret; } ssize_t (*original_sendmsg)(int sockfd, const struct msghdr *msg, int flags); ssize_t my_sendmsg(int sockfd, const struct msghdr *msg, int flags) { ssize_t ret = original_sendmsg(sockfd, msg, flags); - TrafficCollector::enQueueTx(MSG_TYPE_SENDMSG, sockfd, ret); + if (ret > 0) { + TrafficCollector::enQueueTx(MSG_TYPE_SENDMSG, sockfd, ret); + } + return ret; +} + +int (*original_fclose)(FILE *stream); +int my_fclose(FILE *stream) { + int fd = fileno(stream); + int ret = original_fclose(stream); + if (ret == 0) { + TrafficCollector::enQueueClose(fd); + } return ret; } int (*original_close)(int fd); int my_close(int fd) { - TrafficCollector::enQueueClose(fd); - return original_close(fd); + int ret = original_close(fd); + if (ret == 0) { + TrafficCollector::enQueueClose(fd); + } + return ret; } static jobject nativeGetTrafficInfoMap(JNIEnv *env, jclass, jint type) { @@ -225,18 +254,24 @@ void setFdStackTraceCall(const char* key) { env->DeleteLocalRef(jKey); } -static void hookSocket(bool rxHook, bool txHook) { +static void hookSocket(bool rxHook, bool txHook, bool willHookAllSoReadWrite) { if (HOOKED) { return; } xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "close", (void *) my_close, (void **) (&original_close)); + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "fclose", + (void *) my_fclose, (void **) (&original_fclose)); if (rxHook) { - - xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, "/data/.*", "read", - (void *) my_read, (void **) (&original_read)); + if (willHookAllSoReadWrite) { + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "read", + (void *) my_read, (void **) (&original_read)); + } else { + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, "/data/.*\\.so$", "read", + (void *) my_read, (void **) (&original_read)); + } xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "recv", (void *) my_recv, (void **) (&original_recv)); xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "recvfrom", @@ -246,8 +281,13 @@ static void hookSocket(bool rxHook, bool txHook) { } if (txHook) { - xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, "/data/.*", "write", - (void *) my_write, (void **) (&original_write)); + if (willHookAllSoReadWrite) { + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "write", + (void *) my_write, (void **) (&original_write)); + } else { + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, "/data/.*\\.so$", "write", + (void *) my_write, (void **) (&original_write)); + } xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "send", (void *) my_send, (void **) (&original_send)); xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "sendto", @@ -256,9 +296,19 @@ static void hookSocket(bool rxHook, bool txHook) { (void *) my_sendmsg, (void **) (&original_sendmsg)); } + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libc\\.so$", "read"); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libc\\.so$", "recv"); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libc\\.so$", "recvfrom"); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libc\\.so$", "recvmsg"); + + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libc\\.so$", "write"); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libc\\.so$", "send"); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libc\\.so$", "sendto"); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libc\\.so$", "sendmsg"); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, "/vendor/lib.*", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libinput\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libmeminfo\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libgui\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libsensor\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libutils\\.so$", nullptr); @@ -270,7 +320,6 @@ static void hookSocket(bool rxHook, bool txHook) { xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libandroid_runtime\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libnetd_client\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libstatssocket\\.so$", nullptr); - xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libc\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libprofile\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libbinder\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libGLES_mali\\.so$", nullptr); @@ -286,6 +335,9 @@ static void hookSocket(bool rxHook, bool txHook) { xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libandroidfw\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libaudioclient\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libjavacrypto\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libwechatbacktrace\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libmatrix-memoryhook\\.so$", nullptr); + xhook_refresh(true); HOOKED = true; @@ -299,18 +351,18 @@ static void ignoreSo(JNIEnv *env, jobjectArray ignoreSoFiles) { } } -static void nativeInitMatrixTraffic(JNIEnv *env, jclass, jboolean rxEnable, jboolean txEnable, jboolean dumpStackTrace, jboolean dumpNativeBackTrace, jobjectArray ignoreSoFiles) { +static void nativeInitMatrixTraffic(JNIEnv *env, jclass, jboolean rxEnable, jboolean txEnable, jboolean dumpStackTrace, jboolean dumpNativeBackTrace, jboolean willHookAllSoReadWrite, jobjectArray ignoreSoFiles) { TrafficCollector::startLoop(dumpStackTrace == JNI_TRUE); sDumpNativeBackTrace = (dumpNativeBackTrace == JNI_TRUE); ignoreSo(env, ignoreSoFiles); - hookSocket(rxEnable == JNI_TRUE, txEnable == JNI_TRUE); + hookSocket(rxEnable == JNI_TRUE, txEnable == JNI_TRUE, willHookAllSoReadWrite == JNI_TRUE); } template static inline constexpr std::size_t NELEM(const T(&)[sz]) { return sz; } static const JNINativeMethod TRAFFIC_METHODS[] = { - {"nativeInitMatrixTraffic", "(ZZZZ[Ljava/lang/String;)V", (void *) nativeInitMatrixTraffic}, + {"nativeInitMatrixTraffic", "(ZZZZZ[Ljava/lang/String;)V", (void *) nativeInitMatrixTraffic}, {"nativeGetTrafficInfoMap", "(I)Ljava/util/HashMap;", (void *) nativeGetTrafficInfoMap}, {"nativeClearTrafficInfo", "()V", (void *) nativeClearTrafficInfo}, {"nativeReleaseMatrixTraffic", "()V", (void *) nativeReleaseMatrixTraffic}, @@ -338,4 +390,4 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { env->DeleteLocalRef(trafficCollectorCls); return JNI_VERSION_1_6; -} // namespace MatrixTraffic +} // namespace MatrixTraffic \ No newline at end of file diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc index d3ce5dcc0..91fcc0f02 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc @@ -39,11 +39,15 @@ using namespace std; namespace MatrixTraffic { static mutex queueMutex; -static lock_guard lock(queueMutex); +static condition_variable cv; + static bool loopRunning = false; static bool sDumpStackTrace = false; static bool sLookupIpAddress = false; + static unordered_set activeFdSet; +static shared_mutex activeFdSetMutex; + static unordered_set invalidFdSet; static blocking_queue> msgQueue; @@ -151,7 +155,7 @@ void TrafficCollector::enQueueClose(int fd) { } shared_ptr msg = make_shared(MSG_TYPE_CLOSE, fd, 0); msgQueue.push(msg); - queueMutex.unlock(); + cv.notify_one(); } void enQueueMsg(int type, int fd, size_t len) { @@ -159,10 +163,18 @@ void enQueueMsg(int type, int fd, size_t len) { return; } - saveFdInfo(fd); + activeFdSetMutex.lock_shared(); + if (activeFdSet.count(fd) > 0) { + activeFdSetMutex.unlock_shared(); + saveFdInfo(fd); + } else { + activeFdSetMutex.unlock_shared(); + } + shared_ptr msg = make_shared(type, fd, len); msgQueue.push(msg); - queueMutex.unlock(); + + cv.notify_one(); } void TrafficCollector::enQueueTx(int type, int fd, size_t len) { @@ -193,9 +205,10 @@ void appendTxTraffic(int fd, long len) { void loop() { + unique_lock lk(queueMutex); while (loopRunning) { if (msgQueue.empty()) { - queueMutex.lock(); + cv.wait(lk); } else { shared_ptr msg = msgQueue.front(); int fd = msg->fd; @@ -208,7 +221,9 @@ void loop() { fdThreadNameMap.erase(fd); fdThreadNameMapSharedLock.unlock(); } else { + activeFdSetMutex.lock(); activeFdSet.insert(fd); + activeFdSetMutex.unlock(); } } } @@ -226,9 +241,12 @@ void loop() { fdThreadNameMapSharedLock.lock(); fdThreadNameMap.erase(fd); fdThreadNameMapSharedLock.unlock(); + + activeFdSetMutex.lock(); activeFdSet.erase(fd); - invalidFdSet.erase(fd); + activeFdSetMutex.unlock(); } + invalidFdSet.erase(fd); } msgQueue.pop(); } @@ -237,8 +255,11 @@ void loop() { void TrafficCollector::startLoop(bool dumpStackTrace) { - sDumpStackTrace = dumpStackTrace; + if (loopRunning) { + return; + } loopRunning = true; + sDumpStackTrace = dumpStackTrace; thread loopThread(loop); loopThread.detach(); } diff --git a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java index b19f0c9e7..5f5c5960f 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java +++ b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java @@ -11,6 +11,7 @@ public class TrafficConfig { private boolean txCollectorEnable; private boolean dumpStackTraceEnable; private boolean dumpNativeBackTraceEnable; + private boolean hookAllSoReadWrite = true; //TODO //private boolean lookupIpAddressEnable; private int stackTraceFilterMode = 0; @@ -85,4 +86,13 @@ public int getStackTraceFilterMode() { public String getStackTraceFilterCore() { return this.stackTraceFilterCore; } + + public boolean willHookAllSoReadWrite() { + return hookAllSoReadWrite; + } + + public void setHookAllSoReadWrite(boolean hookAllSoReadWrite) { + this.hookAllSoReadWrite = hookAllSoReadWrite; + } + } diff --git a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java index 340e694ea..9791731ef 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java +++ b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java @@ -43,7 +43,7 @@ public void start() { String[] ignoreSoFiles = trafficConfig.getIgnoreSoFiles(); stackTraceFilterMode = trafficConfig.getStackTraceFilterMode(); stackTraceFilterCore = trafficConfig.getStackTraceFilterCore(); - nativeInitMatrixTraffic(trafficConfig.isRxCollectorEnable(), trafficConfig.isTxCollectorEnable(), trafficConfig.willDumpStackTrace(), trafficConfig.willDumpNativeBackTrace(), ignoreSoFiles); + nativeInitMatrixTraffic(trafficConfig.isRxCollectorEnable(), trafficConfig.isTxCollectorEnable(), trafficConfig.willDumpStackTrace(), trafficConfig.willDumpNativeBackTrace(), trafficConfig.willHookAllSoReadWrite(), ignoreSoFiles); } @@ -88,7 +88,7 @@ public void clearTrafficInfo() { nativeClearTrafficInfo(); } - private static native void nativeInitMatrixTraffic(boolean rxEnable, boolean txEnable, boolean dumpStackTrace, boolean dumpNativeBackTrace, String[] ignoreSoFiles); + private static native void nativeInitMatrixTraffic(boolean rxEnable, boolean txEnable, boolean dumpStackTrace, boolean dumpNativeBackTrace, boolean willHookAllSoReadWrite, String[] ignoreSoFiles); private static native String nativeGetTrafficInfo(); private static native String nativeGetAllStackTraceTrafficInfo(); private static native void nativeReleaseMatrixTraffic(); From 5874fc0ccc0813fc4e8e347eb67e8ced2b967154 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 12 Jul 2022 11:45:04 +0800 Subject: [PATCH 079/263] Add debug info for nor cpuload --- .../com/tencent/matrix/batterycanary/Examples.java | 1 + .../monitor/feature/CompositeMonitors.java | 8 ++++++++ .../monitor/feature/MonitorFeature.java | 14 ++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java index 044223b8f..f7aaa5d68 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java @@ -146,6 +146,7 @@ public void exampleForCpuLoadNormalize() { Assert.assertTrue("cpuLoad: " + cpuLoad, cpuLoad >= 0); MonitorFeature.Snapshot.Sampler.Result result = compositor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class); + Assert.assertNotNull(result); List cpuFreqSteps = BatteryCanaryUtil.getCpuFreqSteps(); long sumMax = 0; for (int[] item : cpuFreqSteps) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 543369a18..c6e83cb63 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -19,6 +19,7 @@ import com.tencent.matrix.util.MatrixLog; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -192,6 +193,13 @@ public int getNorCpuLoad() { if (sumMax <= 0) { return -1; } + if (result.sampleAvg >= sumMax) { + // avgFreq should not greater than maxFreq + MatrixLog.w(TAG, "NorCpuLoad err: sampling = " + result); + for (int[] item : cpuFreqSteps) { + MatrixLog.w(TAG, "NorCpuLoad err: freqs = " + Arrays.toString(item)); + } + } return (int) (cpuLoad * result.sampleAvg / sumMax); } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index f9ebc3776..85d946deb 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -551,6 +551,20 @@ public static final class Result { public double sampleMax; public double sampleMin; public double sampleAvg; + + @Override + public String toString() { + return "Result{" + + "interval=" + interval + + ", count=" + count + + ", duringMillis=" + duringMillis + + ", sampleFst=" + sampleFst + + ", sampleLst=" + sampleLst + + ", sampleMax=" + sampleMax + + ", sampleMin=" + sampleMin + + ", sampleAvg=" + sampleAvg + + '}'; + } } } } From 6647bf9a4fac285a756e8b34d6593ade55ae0100 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 12 Jul 2022 16:28:55 +0800 Subject: [PATCH 080/263] Fix nor cpuload cfg --- .../matrix/batterycanary/Examples.java | 12 ++++++++-- .../batterycanary/utils/HealthStatsTest.java | 24 +++++++++++++++++-- .../monitor/feature/CompositeMonitors.java | 10 ++++++-- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java index f7aaa5d68..945a7aec8 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java @@ -46,6 +46,8 @@ import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import androidx.test.core.app.ApplicationProvider; @@ -149,8 +151,14 @@ public void exampleForCpuLoadNormalize() { Assert.assertNotNull(result); List cpuFreqSteps = BatteryCanaryUtil.getCpuFreqSteps(); long sumMax = 0; - for (int[] item : cpuFreqSteps) { - sumMax += item[item.length - 1]; + for (int[] steps : cpuFreqSteps) { + int max = 0; + for (int item : steps) { + if (item > max) { + max = item; + } + } + sumMax += max; } Assert.assertTrue("cpuFreqSumAvg: " + result.sampleAvg + "vs cpuFreqSumMax: " + sumMax, sumMax >= result.sampleAvg); int cpuLoadNormalized = (int) (cpuLoad * result.sampleAvg / sumMax); diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java index 5b2653c70..33fd080f3 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java @@ -18,11 +18,11 @@ import android.app.Application; import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorManager; import android.os.health.HealthStats; -import android.os.health.PidHealthStats; import android.os.health.SystemHealthManager; import android.os.health.TimerStat; -import android.os.health.UidHealthStats; import com.tencent.matrix.Matrix; @@ -32,6 +32,8 @@ import org.junit.Test; import org.junit.runner.RunWith; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -140,4 +142,22 @@ public void testLiterateStats() { } } } + + @Test + public void testGetSenorsHandle() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + SensorManager sm = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + Assert.assertNotNull(sm); + List sensorList = sm.getSensorList(Sensor.TYPE_ALL); + Assert.assertFalse(sensorList.isEmpty()); + + for (Sensor item : sensorList) { + String name = item.getName(); + int id = item.getId(); + int type = item.getType(); + float power = item.getPower(); + Method method = item.getClass().getDeclaredMethod("getHandle"); + int handle = (int) method.invoke(item); + Assert.assertTrue(handle > 0); + } + } } \ No newline at end of file diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index c6e83cb63..49358210e 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -187,8 +187,14 @@ public int getNorCpuLoad() { } List cpuFreqSteps = BatteryCanaryUtil.getCpuFreqSteps(); long sumMax = 0; - for (int[] item : cpuFreqSteps) { - sumMax += item[item.length - 1]; + for (int[] steps : cpuFreqSteps) { + int max = 0; + for (int item : steps) { + if (item > max) { + max = item; + } + } + sumMax += max; } if (sumMax <= 0) { return -1; From 00560cd2478a6b53deb905a57df1928016a06c35 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 13 Jul 2022 12:58:21 +0800 Subject: [PATCH 081/263] Update nor cpuload cfg --- .../java/com/tencent/matrix/batterycanary/Examples.java | 2 ++ .../batterycanary/monitor/feature/CompositeMonitors.java | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java index 945a7aec8..3abb5e8ac 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java @@ -150,6 +150,8 @@ public void exampleForCpuLoadNormalize() { MonitorFeature.Snapshot.Sampler.Result result = compositor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class); Assert.assertNotNull(result); List cpuFreqSteps = BatteryCanaryUtil.getCpuFreqSteps(); + Assert.assertEquals(BatteryCanaryUtil.getCpuCoreNum(), cpuFreqSteps.size()); + long sumMax = 0; for (int[] steps : cpuFreqSteps) { int max = 0; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 49358210e..38cf0cce5 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -179,13 +179,18 @@ public int getCpuLoad() { public int getNorCpuLoad() { int cpuLoad = getCpuLoad(); if (cpuLoad == -1) { + MatrixLog.w(TAG, "cpu is invalid"); return -1; } MonitorFeature.Snapshot.Sampler.Result result = getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class); if (result == null) { + MatrixLog.w(TAG, "cpufreq is null"); return -1; } List cpuFreqSteps = BatteryCanaryUtil.getCpuFreqSteps(); + if (cpuFreqSteps.size() != BatteryCanaryUtil.getCpuCoreNum()) { + MatrixLog.w(TAG, "cpuCore is invalid: " + cpuFreqSteps.size() + " vs " + BatteryCanaryUtil.getCpuCoreNum()); + } long sumMax = 0; for (int[] steps : cpuFreqSteps) { int max = 0; @@ -197,6 +202,7 @@ public int getNorCpuLoad() { sumMax += max; } if (sumMax <= 0) { + MatrixLog.w(TAG, "cpufreq sum is invalid: " + sumMax); return -1; } if (result.sampleAvg >= sumMax) { From 6007449ec5a475250a1d386528c981d53c7dd71d Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 15 Jul 2022 21:27:18 +0800 Subject: [PATCH 082/263] Update power profile estimate --- .../batterycanary/utils/HealthStatsTest.java | 440 +++++++++++++++++- 1 file changed, 427 insertions(+), 13 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java index 33fd080f3..9eba0c268 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java @@ -23,8 +23,14 @@ import android.os.health.HealthStats; import android.os.health.SystemHealthManager; import android.os.health.TimerStat; +import android.os.health.UidHealthStats; import com.tencent.matrix.Matrix; +import com.tencent.matrix.batterycanary.BatteryCanary; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; +import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; import org.junit.After; import org.junit.Assert; @@ -32,16 +38,22 @@ import org.junit.Test; import org.junit.runner.RunWith; +import java.io.IOException; +import java.io.PipedWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; +import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.JIFFY_MILLIS; +import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_HOR; + @RunWith(AndroidJUnit4.class) public class HealthStatsTest { @@ -61,6 +73,36 @@ public void setUp() { public void shutDown() { } + private BatteryMonitorCore mockMonitor() { + BatteryMonitorConfig config = new BatteryMonitorConfig.Builder() + .enable(CpuStatFeature.class) + .enableBuiltinForegroundNotify(false) + .enableForegroundMode(false) + .wakelockTimeout(1000) + .greyJiffiesTime(100) + .foregroundLoopCheckTime(1000) + .build(); + return new BatteryMonitorCore(config); + } + + + @Test + public void testGetSenorsHandle() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + SensorManager sm = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + Assert.assertNotNull(sm); + List sensorList = sm.getSensorList(Sensor.TYPE_ALL); + Assert.assertFalse(sensorList.isEmpty()); + + for (Sensor item : sensorList) { + String name = item.getName(); + int id = item.getId(); + int type = item.getType(); + float power = item.getPower(); + Method method = item.getClass().getDeclaredMethod("getHandle"); + int handle = (int) method.invoke(item); + Assert.assertTrue(handle > 0); + } + } @Test public void testLiterateStats() { @@ -144,20 +186,392 @@ public void testLiterateStats() { } @Test - public void testGetSenorsHandle() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { - SensorManager sm = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); - Assert.assertNotNull(sm); - List sensorList = sm.getSensorList(Sensor.TYPE_ALL); - Assert.assertFalse(sensorList.isEmpty()); + public void testEstimateCpuPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); - for (Sensor item : sensorList) { - String name = item.getName(); - int id = item.getId(); - int type = item.getType(); - float power = item.getPower(); - Method method = item.getClass().getDeclaredMethod("getHandle"); - int handle = (int) method.invoke(item); - Assert.assertTrue(handle > 0); + double cpuActivePower = powerProfile.getAveragePower("cpu.active"); + Assert.assertTrue(cpuActivePower > 0); + UsageBasedPowerEstimator etmCpuActivePower = new UsageBasedPowerEstimator(cpuActivePower); + } + + @Test + public void testEstimateCpuPowerByHealthStats() throws IOException { + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + if (healthStats.hasStats(UidHealthStats.MEASUREMENT_CPU_POWER_MAMS)) { + double powerMah = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_CPU_POWER_MAMS) / (1000.0 * 60 * 60); + Assert.assertTrue(powerMah >= 0); + } + } + + @Test + public void testEstimateCpuPowerByCpuStats() throws IOException { + CpuStatFeature feature = new CpuStatFeature(); + feature.configure(mockMonitor()); + feature.onTurnOn(); + + Assert.assertTrue(feature.isSupported()); + CpuStatFeature.CpuStateSnapshot cpuStateSnapshot = feature.currentCpuStateSnapshot(); + Assert.assertTrue(cpuStateSnapshot.procCpuCoreStates.size() > 0); + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS); + healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); + long cpuTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + healthStats.getMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); + double powerMah = estimateCpuPowerByCpuStats(cpuTimeMs); + Assert.assertTrue(powerMah >= 0); + } + + private static double estimateCpuPowerByCpuStats(long cpuTimeMs) { + CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); + if (feat != null && feat.isSupported()) { + CpuStatFeature.CpuStateSnapshot cpuStateSnapshot = feat.currentCpuStateSnapshot(); + if (cpuStateSnapshot != null) { + long jiffySum = 0; + for (MonitorFeature.Snapshot.Entry.ListEntry> stepJiffies : cpuStateSnapshot.procCpuCoreStates) { + for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies.getList()) { + jiffySum += item.get(); + } + } + double powerMah = 0; + for (int i = 0; i < cpuStateSnapshot.procCpuCoreStates.size(); i++) { + List> stepJiffies = cpuStateSnapshot.procCpuCoreStates.get(i).getList(); + for (int j = 0; j < stepJiffies.size(); j++) { + long jiffy = stepJiffies.get(j).get(); + long figuredCpuTimeMs = (long) ((jiffy * 1.0f / jiffySum) * cpuTimeMs); + double powerMa = feat.getPowerProfile().getAveragePowerForCpuCore(i, j); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); + } + } + return powerMah; + } } + return 0; + } + + @Test + public void testEstimateMemoryPower() throws IOException { } + + @Test + public void testEstimateWakelockPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + Assert.assertTrue(powerProfile.getAveragePower("cpu.idle") > 0); + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + double powerMah = 0; + if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL); + long timeMs = 0; + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + double powerMa = powerProfile.getAveragePower("cpu.idle"); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + Assert.assertTrue(powerMah >= 0); + } + + @Test + public void testEstimateMobileRadioPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS)) { + double powerMahByHealthStats = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS) / (1000.0 * 60 * 60); + Assert.assertTrue(powerMahByHealthStats >= 0); + } + + double powerMahByRadio = 0; + if (powerProfile.getAveragePower("radio.active") > 0) { + if (healthStats.hasTimer(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE); + double powerMa = powerProfile.getAveragePower("radio.active"); + powerMahByRadio += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + } + Assert.assertTrue(powerMahByRadio >= 0); + + double powerMahByTime = 0; + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); + double powerMa = powerProfile.getAveragePower("modem.controller.idle"); + powerMahByTime += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS); + double powerMa = powerProfile.getAveragePower("modem.controller.rx"); + powerMahByTime += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS); + double powerMa = powerProfile.getAveragePower("modem.controller.tx"); + powerMahByTime += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + Assert.assertTrue(powerMahByTime >= 0); + } + + @Test + public void testEstimateWifiPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + + double wifiIdlePower = powerProfile.getAveragePower("wifi.controller.idle"); + Assert.assertTrue(wifiIdlePower > 0); + UsageBasedPowerEstimator etmWifiIdlePower = new UsageBasedPowerEstimator(wifiIdlePower); + double wifiRxPower = powerProfile.getAveragePower("wifi.controller.rx"); + Assert.assertTrue(wifiRxPower > 0); + UsageBasedPowerEstimator etmWifiRxPower = new UsageBasedPowerEstimator(wifiIdlePower); + double wifiTxPower = powerProfile.getAveragePower("wifi.controller.tx"); + Assert.assertTrue(wifiTxPower > 0); + UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiIdlePower); + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS)) { + double powerMahByHealthStats = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS) / (1000.0 * 60 * 60); + Assert.assertTrue(powerMahByHealthStats >= 0); + } + + double powerMah = 0; + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS)) { + long idleMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS); + powerMah += etmWifiIdlePower.calculatePower(idleMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS)) { + long rxMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS); + powerMah += etmWifiRxPower.calculatePower(rxMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS)) { + long txMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS); + powerMah += etmWifiTxPower.calculatePower(txMs); + } + Assert.assertTrue(powerMah >= 0); + } + + @Test + public void testEstimateBlueToothPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + Assert.assertTrue(powerProfile.getAveragePower("bluetooth.controller.idle") > 0); + Assert.assertTrue(powerProfile.getAveragePower("bluetooth.controller.rx") > 0); + Assert.assertTrue(powerProfile.getAveragePower("bluetooth.controller.tx") > 0); + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS)) { + double powerMahByHealthStats = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS) / (1000.0 * 60 * 60); + Assert.assertTrue(powerMahByHealthStats >= 0); + } + + double powerMah = 0; + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS); + double powerMa = powerProfile.getAveragePower("bluetooth.controller.idle"); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS); + double powerMa = powerProfile.getAveragePower("bluetooth.controller.rx"); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS); + double powerMa = powerProfile.getAveragePower("bluetooth.controller.tx"); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + Assert.assertTrue(powerMah >= 0); + } + + @Test + public void testEstimateGpsPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + double powerMa = 0; + if (powerProfile.getAveragePower("gps.voltage") > 0) { + powerMa = powerProfile.getAveragePower("gps.on"); + if (powerMa <= 0) { + int num = powerProfile.getNumElements("gps.signalqualitybased"); + double sumMa = 0; + for (int i = 0; i < num; i++) { + sumMa += powerProfile.getAveragePower("gps.signalqualitybased", i); + } + powerMa = sumMa / num; + } + } + + Assert.assertTrue(powerMa > 0); + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + double powerMah = 0; + if (healthStats.hasTimer(UidHealthStats.TIMER_GPS_SENSOR)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_GPS_SENSOR); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + Assert.assertTrue(powerMah >= 0); + } + + @Test + public void testEstimateSensorsPower() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + double powerMah = 0; + if (healthStats.hasTimers(UidHealthStats.TIMERS_SENSORS)) { + SensorManager sm = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + Assert.assertNotNull(sm); + List sensorList = sm.getSensorList(Sensor.TYPE_ALL); + Assert.assertFalse(sensorList.isEmpty()); + + Map sensorMap = new HashMap<>(); + for (Sensor item : sensorList) { + Method method = item.getClass().getDeclaredMethod("getHandle"); + int handle = (int) method.invoke(item); + sensorMap.put(String.valueOf(handle), item); + } + + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_SENSORS); + for (Map.Entry item : timers.entrySet()) { + String handle = item.getKey(); + long timeMs = item.getValue().getTime(); + if (handle.equals("-10000")) { + continue; // skip GPS Sensors + } + Sensor sensor = sensorMap.get(handle); + if (sensor != null) { + powerMah += new UsageBasedPowerEstimator(sensor.getPower()).calculatePower(timeMs); + } + } + } + Assert.assertTrue(powerMah >= 0); + } + + @Test + public void testEstimateMediaAndHwPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + double powerMah = 0; + + // Camera + Assert.assertTrue(powerProfile.getAveragePower("camera.avg") > 0); + if (healthStats.hasTimer(UidHealthStats.TIMER_CAMERA)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_CAMERA); + double powerMa = powerProfile.getAveragePower("camera.avg"); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + // Flash Light + Assert.assertTrue(powerProfile.getAveragePower("camera.flashlight") > 0); + if (healthStats.hasTimer(UidHealthStats.TIMER_FLASHLIGHT)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_FLASHLIGHT); + double powerMa = powerProfile.getAveragePower("camera.flashlight"); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + // Media + Assert.assertTrue(powerProfile.getAveragePower("audio") > 0); + Assert.assertTrue(powerProfile.getAveragePower("video") > 0); + if (healthStats.hasTimer(UidHealthStats.TIMER_AUDIO)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_AUDIO); + double powerMa = powerProfile.getAveragePower("audio"); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (healthStats.hasTimer(UidHealthStats.TIMER_VIDEO)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_VIDEO); + double powerMa = powerProfile.getAveragePower("video"); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + Assert.assertTrue(powerMah >= 0); + } + + @Test + public void testEstimateScreenPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + Assert.assertTrue(powerProfile.getAveragePower("screen.on") > 0); + Assert.assertTrue(powerProfile.getAveragePower("screen.full") > 0); + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + Assert.assertTrue(healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS)); + Assert.assertTrue(healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS)); + + long totalTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); + long screenOffTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS); + Assert.assertTrue(totalTimeMs >= screenOffTimeMs); + long screenOnTimeMs = totalTimeMs - screenOffTimeMs; + + double powerMah = 0; + powerMah += new UsageBasedPowerEstimator(powerProfile.getAveragePower("screen.on")).calculatePower(screenOnTimeMs); + + Assert.assertTrue(powerMah > 0); + } + + @Test + public void testEstimateSystemServicePower() throws IOException { + } + + @Test + public void testEstimateIdlePower() throws IOException { + } + + + public static class UsageBasedPowerEstimator { + private static final double MILLIS_IN_HOUR = 1000.0 * 60 * 60; + private final double mAveragePowerMahPerMs; + + public UsageBasedPowerEstimator(double averagePowerMilliAmp) { + mAveragePowerMahPerMs = averagePowerMilliAmp / MILLIS_IN_HOUR; + } + + public boolean isSupported() { + return mAveragePowerMahPerMs != 0; + } + + public double calculatePower(long durationMs) { + return mAveragePowerMahPerMs * durationMs; + } + } + } \ No newline at end of file From 92657892d5e92bdc159b1083405e6fadd4414e24 Mon Sep 17 00:00:00 2001 From: leafjia Date: Mon, 18 Jul 2022 04:22:54 +0800 Subject: [PATCH 083/263] Fix Matrix Traffic Memory Problems --- .../src/main/cpp/MatrixTraffic.cc | 11 +-- .../src/main/cpp/TrafficCollector.cc | 97 ++++--------------- 2 files changed, 26 insertions(+), 82 deletions(-) diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc index d4402ad9d..3b20c7fda 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -92,13 +92,12 @@ void makeNativeStack(wechat_backtrace::Backtrace* backtrace, char *&stack) { static void saveNativeBackTrace(const char* key) { wechat_backtrace::Backtrace *backtracePrt; - - wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER(16); - + int max_frames = 16; backtracePrt = new wechat_backtrace::Backtrace; - backtracePrt->max_frames = backtrace_zero.max_frames; - backtracePrt->frame_size = backtrace_zero.frame_size; - backtracePrt->frames = backtrace_zero.frames; + backtracePrt->max_frames = max_frames; + backtracePrt->frame_size = 0; + backtracePrt->frames = std::shared_ptr( + new wechat_backtrace::Frame[max_frames], std::default_delete()); wechat_backtrace::unwind_adapter(backtracePrt->frames.get(), backtracePrt->max_frames, backtracePrt->frame_size); diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc index 91fcc0f02..34113dabf 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc @@ -43,7 +43,6 @@ static condition_variable cv; static bool loopRunning = false; static bool sDumpStackTrace = false; -static bool sLookupIpAddress = false; static unordered_set activeFdSet; static shared_mutex activeFdSetMutex; @@ -58,42 +57,7 @@ static shared_mutex rxTrafficInfoMapLock; static shared_mutex txTrafficInfoMapLock; static map fdThreadNameMap; -static map fdIpAddressMap; static shared_mutex fdThreadNameMapSharedLock; -static mutex fdIpAddressMapLock; - -string getIpAddressFromAddr(sockaddr* _addr) { - string ipAddress; - if (_addr != nullptr) { - if ((int)_addr->sa_family == AF_LOCAL) { - ipAddress = _addr->sa_data; - ipAddress.append(":LOCAL"); - } else if ((int)_addr->sa_family == AF_INET) { - auto *sin4 = reinterpret_cast(_addr); - char ipv4str[INET_ADDRSTRLEN]; - if (inet_ntop(AF_INET, &(sin4->sin_addr), ipv4str, INET6_ADDRSTRLEN) != nullptr) { - ipAddress = ipv4str; - int port = ntohs(sin4->sin_port); - if (port != -1) { - ipAddress.append(":"); - ipAddress.append(to_string(port)); - } - } - } else if ((int)_addr->sa_family == AF_INET6) { - auto *sin6 = reinterpret_cast(_addr); - char ipv6str[INET6_ADDRSTRLEN]; - if (inet_ntop(AF_INET6, &(sin6->sin6_addr), ipv6str, INET6_ADDRSTRLEN) != nullptr) { - ipAddress = ipv6str; - int port = ntohs(sin6->sin6_port); - if (port != -1) { - ipAddress.append(":"); - ipAddress.append(to_string(port)); - } - } - } - } - return ipAddress; -} int isNetworkSocketFd(int fd) { struct sockaddr c; @@ -107,28 +71,12 @@ int isNetworkSocketFd(int fd) { return 0; } -void saveIpAddress(int fd, sockaddr* addr) { - fdIpAddressMapLock.lock(); - if (fdIpAddressMap.count(fd) == 0) { - fdIpAddressMap[fd] = getIpAddressFromAddr(addr); - } - fdIpAddressMapLock.unlock(); -} - -string getIpAddress(int fd) { - fdIpAddressMapLock.lock(); - string ipAddress = fdIpAddressMap[fd]; - fdIpAddressMapLock.unlock(); - return ipAddress; -} - - string saveFdInfo(int fd) { fdThreadNameMapSharedLock.lock_shared(); if (fdThreadNameMap.count(fd) == 0) { fdThreadNameMapSharedLock.unlock_shared(); - auto threadName = new char[15]; + char threadName[15]; prctl(PR_GET_NAME, threadName); char key[32]; snprintf(key, sizeof(key), "%d-%s", fd, threadName); @@ -203,7 +151,6 @@ void appendTxTraffic(int fd, long len) { txTrafficInfoMapLock.unlock(); } - void loop() { unique_lock lk(queueMutex); while (loopRunning) { @@ -213,7 +160,18 @@ void loop() { shared_ptr msg = msgQueue.front(); int fd = msg->fd; int type = msg->type; - if (type != MSG_TYPE_CLOSE) { + if (type == MSG_TYPE_CLOSE) { + if (activeFdSet.count(fd) > 0) { + fdThreadNameMapSharedLock.lock(); + fdThreadNameMap.erase(fd); + fdThreadNameMapSharedLock.unlock(); + + activeFdSetMutex.lock(); + activeFdSet.erase(fd); + activeFdSetMutex.unlock(); + } + invalidFdSet.erase(fd); + } else { if (activeFdSet.count(fd) == 0 && invalidFdSet.count(fd) == 0) { if (!isNetworkSocketFd(fd)) { invalidFdSet.insert(fd); @@ -226,34 +184,21 @@ void loop() { activeFdSetMutex.unlock(); } } - } - - if (type >= MSG_TYPE_READ && type <= MSG_TYPE_RECVMSG) { - if (activeFdSet.count(fd) > 0 && invalidFdSet.count(fd) == 0) { - appendRxTraffic(fd, msg->len); - } - } else if (type >= MSG_TYPE_WRITE && type <= MSG_TYPE_SENDMSG) { - if (activeFdSet.count(fd) > 0 && invalidFdSet.count(fd) == 0) { - appendTxTraffic(fd, msg->len); - } - } else if (type == MSG_TYPE_CLOSE) { - if (activeFdSet.count(fd) > 0) { - fdThreadNameMapSharedLock.lock(); - fdThreadNameMap.erase(fd); - fdThreadNameMapSharedLock.unlock(); - - activeFdSetMutex.lock(); - activeFdSet.erase(fd); - activeFdSetMutex.unlock(); + if (type >= MSG_TYPE_READ && type <= MSG_TYPE_RECVMSG) { + if (activeFdSet.count(fd) > 0 && invalidFdSet.count(fd) == 0) { + appendRxTraffic(fd, msg->len); + } + } else if (type >= MSG_TYPE_WRITE && type <= MSG_TYPE_SENDMSG) { + if (activeFdSet.count(fd) > 0 && invalidFdSet.count(fd) == 0) { + appendTxTraffic(fd, msg->len); + } } - invalidFdSet.erase(fd); } msgQueue.pop(); } } } - void TrafficCollector::startLoop(bool dumpStackTrace) { if (loopRunning) { return; From 4bfc1e8e620dc3addecb394c80486100e71fb942 Mon Sep 17 00:00:00 2001 From: leafjia Date: Mon, 18 Jul 2022 04:40:25 +0800 Subject: [PATCH 084/263] Fix Matrix Tracer Memory Problems --- .../src/main/cpp/MatrixTracer.cc | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc index 17f263e4a..2a9a0d553 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc +++ b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.cc @@ -288,23 +288,13 @@ void makeNativeStack(wechat_backtrace::Backtrace* backtrace, char *&stack) { strcpy(stack, full_stack_builder.str().c_str()); } -static const char* getNativeBacktrace() { - wechat_backtrace::Backtrace *backtracePrt; - +static char* getNativeBacktrace() { wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( 16); - - - backtracePrt = new wechat_backtrace::Backtrace; - backtracePrt->max_frames = backtrace_zero.max_frames; - backtracePrt->frame_size = backtrace_zero.frame_size; - backtracePrt->frames = backtrace_zero.frames; - - wechat_backtrace::unwind_adapter(backtracePrt->frames.get(), backtracePrt->max_frames, - backtracePrt->frame_size); - + wechat_backtrace::unwind_adapter(backtrace_zero.frames.get(), backtrace_zero.max_frames, + backtrace_zero.frame_size); char* nativeStack; - makeNativeStack(backtracePrt, nativeStack); + makeNativeStack(&backtrace_zero, nativeStack); return nativeStack; } @@ -317,9 +307,11 @@ int my_pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) { Dl_info dl_info; dladdr(__caller_addr, &dl_info); const char* soName = dl_info.dli_fname; + char* backtrace = getNativeBacktrace(); if (!strstr(soName, "libc.so")) { - pthreadKeyCallback(0, ret, keySeq, soName, getNativeBacktrace()); + pthreadKeyCallback(0, ret, keySeq, soName, backtrace); } + delete[] backtrace; return ret; } @@ -331,9 +323,11 @@ int my_pthread_key_delete(pthread_key_t key) { Dl_info dl_info; dladdr(__caller_addr, &dl_info); const char* soName = dl_info.dli_fname; + char* backtrace = getNativeBacktrace(); if (!strstr(soName, "libc.so")) { - pthreadKeyCallback(1, ret, keySeq, soName, getNativeBacktrace()); + pthreadKeyCallback(1, ret, keySeq, soName, backtrace); } + delete[] backtrace; return 0; } From 2aacb85fe4d2f4344a90f989d7cc3cb5bd1cfcf8 Mon Sep 17 00:00:00 2001 From: leafjia Date: Mon, 18 Jul 2022 16:48:55 +0800 Subject: [PATCH 085/263] ignore libmatrix-traffic.so --- .../matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc index 3b20c7fda..110c59fea 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -336,7 +336,7 @@ static void hookSocket(bool rxHook, bool txHook, bool willHookAllSoReadWrite) { xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libjavacrypto\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libwechatbacktrace\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libmatrix-memoryhook\\.so$", nullptr); - + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libmatrix-traffic\\.so$", nullptr); xhook_refresh(true); HOOKED = true; From 617079838e1d200a113a47fcdd9d14ce73f5d71d Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 18 Jul 2022 18:05:27 +0800 Subject: [PATCH 086/263] Add health stats feature --- .../{utils => stats}/HealthStatsTest.java | 27 +- .../monitor/feature/CompositeMonitors.java | 8 + .../stats/HealthStatsFeature.java | 248 ++++++++++++ .../stats/HealthStatsHelper.java | 352 ++++++++++++++++++ 4 files changed, 634 insertions(+), 1 deletion(-) rename matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/{utils => stats}/HealthStatsTest.java (96%) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java create mode 100644 matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java similarity index 96% rename from matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java rename to matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 9eba0c268..5553a036d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.tencent.matrix.batterycanary.utils; +package com.tencent.matrix.batterycanary.stats; import android.app.Application; import android.content.Context; @@ -31,6 +31,9 @@ import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; +import com.tencent.matrix.batterycanary.stats.HealthStatsFeature.HealthStatsSnapshot; +import com.tencent.matrix.batterycanary.utils.PowerProfile; import org.junit.After; import org.junit.Assert; @@ -76,6 +79,7 @@ public void shutDown() { private BatteryMonitorCore mockMonitor() { BatteryMonitorConfig config = new BatteryMonitorConfig.Builder() .enable(CpuStatFeature.class) + .enable(HealthStatsFeature.class) .enableBuiltinForegroundNotify(false) .enableForegroundMode(false) .wakelockTimeout(1000) @@ -556,6 +560,27 @@ public void testEstimateSystemServicePower() throws IOException { public void testEstimateIdlePower() throws IOException { } + @Test + public void testGetCurrSnapshot() { + HealthStatsFeature feature = new HealthStatsFeature(); + feature.configure(mockMonitor()); + feature.onTurnOn(); + + Assert.assertNotNull(feature.currHealthStats()); + + HealthStatsSnapshot bgn = feature.currHealthStatsSnapshot(); + Assert.assertNotNull(bgn); + Assert.assertNotNull(bgn.healthStats); + + HealthStatsSnapshot end = feature.currHealthStatsSnapshot(); + Assert.assertNotNull(end); + Assert.assertNotNull(end.healthStats); + + Delta delta = end.diff(bgn); + Assert.assertNotNull(delta); + Assert.assertNull(delta.dlt.healthStats); + } + public static class UsageBasedPowerEstimator { private static final double MILLIS_IN_HOUR = 1000.0 * 60 * 60; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 38cf0cce5..5d02ff001 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -13,6 +13,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; +import com.tencent.matrix.batterycanary.stats.HealthStatsFeature; import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.Consumer; import com.tencent.matrix.batterycanary.utils.Function; @@ -502,6 +503,13 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas } return snapshot; } + if (snapshotClass == HealthStatsFeature.HealthStatsSnapshot.class) { + HealthStatsFeature feature = getFeature(HealthStatsFeature.class); + if (feature != null) { + snapshot = feature.currHealthStatsSnapshot(); + } + return snapshot; + } return null; } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java new file mode 100644 index 000000000..bfd0186b6 --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -0,0 +1,248 @@ +package com.tencent.matrix.batterycanary.stats; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorManager; +import android.os.Build; +import android.os.health.HealthStats; +import android.os.health.TimerStat; +import android.os.health.UidHealthStats; + +import com.tencent.matrix.batterycanary.monitor.feature.AbsMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; +import com.tencent.matrix.batterycanary.utils.PowerProfile; +import com.tencent.matrix.util.MatrixLog; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import androidx.annotation.VisibleForTesting; + +/** + * @author Kaede + * @since 18/7/2022 + */ +public class HealthStatsFeature extends AbsMonitorFeature { + private static final String TAG = "Matrix.battery.HealthStats"; + + @Override + protected String getTag() { + return TAG; + } + + @Override + public int weight() { + return 0; + } + + public HealthStats currHealthStats() { + return HealthStatsHelper.getCurrStats(mCore.getContext()); + } + + public HealthStatsSnapshot currHealthStatsSnapshot() { + HealthStatsSnapshot snapshot = new HealthStatsSnapshot(); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + return snapshot; + } + final HealthStats healthStats = currHealthStats(); + if (healthStats != null) { + snapshot.healthStats = healthStats; + + // Power + CpuStatFeature cpuStatFeat = mCore.getMonitorFeature(CpuStatFeature.class); + if (cpuStatFeat != null) { + PowerProfile powerProfile = cpuStatFeat.getPowerProfile(); + if (powerProfile != null && powerProfile.isSupported()) { + snapshot.cpuPower = DigitEntry.of(HealthStatsHelper.calcCpuPower(powerProfile, healthStats)); + snapshot.wakelocksPower = DigitEntry.of(HealthStatsHelper.calcWakelocksPower(powerProfile, healthStats)); + snapshot.mobilePower = DigitEntry.of(HealthStatsHelper.calcMobilePower(powerProfile, healthStats)); + snapshot.wifiPower = DigitEntry.of(HealthStatsHelper.calcWifiPower(powerProfile, healthStats)); + snapshot.blueToothPower = DigitEntry.of(HealthStatsHelper.calcBlueToothPower(powerProfile, healthStats)); + snapshot.gpsPower = DigitEntry.of(HealthStatsHelper.calcGpsPower(powerProfile, healthStats)); + snapshot.sensorsPower = DigitEntry.of(HealthStatsHelper.calcSensorsPower(mCore.getContext(), healthStats)); + snapshot.cameraPower = DigitEntry.of(HealthStatsHelper.calcCameraPower(powerProfile, healthStats)); + snapshot.flashLightPower = DigitEntry.of(HealthStatsHelper.calcFlashLightPower(powerProfile, healthStats)); + snapshot.audioPower = DigitEntry.of(HealthStatsHelper.calcAudioPower(powerProfile, healthStats)); + snapshot.videoPower = DigitEntry.of(HealthStatsHelper.calcVideoPower(powerProfile, healthStats)); + snapshot.screenPower = DigitEntry.of(HealthStatsHelper.calcScreenPower(powerProfile, healthStats)); + } + } + + // Meta data + snapshot.cpuPowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_CPU_POWER_MAMS)); + snapshot.cpuUsrTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS)); + snapshot.cpuSysTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS)); + + if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL); + long timeMs = 0; + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + snapshot.wakelocksPartialMs = DigitEntry.of(timeMs); + } + + snapshot.mobilePowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS)); + snapshot.mobileRadioActiveMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE)); + snapshot.mobileIdleMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS)); + snapshot.mobileRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_MS)); + snapshot.mobileTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_MS)); + + snapshot.wifiPowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS)); + snapshot.wifiIdleMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_IDLE_MS)); + snapshot.wifiRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_MS)); + snapshot.wifiTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_MS)); + + snapshot.blueToothPowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS)); + snapshot.blueToothIdleMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS)); + snapshot.blueToothRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS)); + snapshot.blueToothTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS)); + + snapshot.gpsMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_GPS_SENSOR)); + + if (healthStats.hasTimers(UidHealthStats.TIMERS_SENSORS)) { + SensorManager sm = (SensorManager) mCore.getContext().getSystemService(Context.SENSOR_SERVICE); + List sensorList = sm.getSensorList(Sensor.TYPE_ALL); + Map sensorMap = new HashMap<>(); + for (Sensor item : sensorList) { + try { + //noinspection JavaReflectionMemberAccess + @SuppressLint("DiscouragedPrivateApi") + Method method = item.getClass().getDeclaredMethod("getHandle"); + //noinspection ConstantConditions + int handle = (int) method.invoke(item); + sensorMap.put(String.valueOf(handle), item); + } catch (Throwable e) { + MatrixLog.w(TAG, "getSensorHandle err: " + e.getMessage()); + } + } + + long sensorsPowerMams = 0; + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_SENSORS); + for (Map.Entry item : timers.entrySet()) { + String handle = item.getKey(); + long timeMs = item.getValue().getTime(); + if (handle.equals("-10000")) { + continue; // skip GPS Sensors + } + Sensor sensor = sensorMap.get(handle); + if (sensor != null) { + sensorsPowerMams += sensor.getPower() * timeMs; + } + } + snapshot.sensorsPowerMams = DigitEntry.of(sensorsPowerMams); + } + + snapshot.cameraMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_CAMERA)); + snapshot.flashLightMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_FLASHLIGHT)); + snapshot.audioMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_AUDIO)); + snapshot.videoMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_VIDEO)); + + { + long totalTimeMs = HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); + long screenOffTimeMs = HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS); + long screenOnTimeMs = totalTimeMs - screenOffTimeMs; + snapshot.screenOnMs = DigitEntry.of(screenOnTimeMs); + } + } + return snapshot; + } + + public static class HealthStatsSnapshot extends Snapshot { + @VisibleForTesting + public HealthStats healthStats; + + // Estimated Powers + public DigitEntry cpuPower = DigitEntry.of(0D); + public DigitEntry wakelocksPower = DigitEntry.of(0D); + public DigitEntry mobilePower = DigitEntry.of(0D); + public DigitEntry wifiPower = DigitEntry.of(0D); + public DigitEntry blueToothPower = DigitEntry.of(0D); + public DigitEntry gpsPower = DigitEntry.of(0D); + public DigitEntry sensorsPower = DigitEntry.of(0D); + public DigitEntry cameraPower = DigitEntry.of(0D); + public DigitEntry flashLightPower = DigitEntry.of(0D); + public DigitEntry audioPower = DigitEntry.of(0D); + public DigitEntry videoPower = DigitEntry.of(0D); + public DigitEntry screenPower = DigitEntry.of(0D); + + // CPU + public DigitEntry cpuPowerMams = DigitEntry.of(0L); + public DigitEntry cpuUsrTimeMs = DigitEntry.of(0L); + public DigitEntry cpuSysTimeMs = DigitEntry.of(0L); + + // SystemService & Sensors + public DigitEntry wakelocksPartialMs = DigitEntry.of(0L); + public DigitEntry gpsMs = DigitEntry.of(0L); + public DigitEntry sensorsPowerMams = DigitEntry.of(0L); + public DigitEntry cameraMs = DigitEntry.of(0L); + public DigitEntry flashLightMs = DigitEntry.of(0L); + + // Network + public DigitEntry mobilePowerMams = DigitEntry.of(0L); + public DigitEntry mobileRadioActiveMs = DigitEntry.of(0L); + public DigitEntry mobileIdleMs = DigitEntry.of(0L); + public DigitEntry mobileRxMs = DigitEntry.of(0L); + public DigitEntry mobileTxMs = DigitEntry.of(0L); + + public DigitEntry wifiPowerMams = DigitEntry.of(0L); + public DigitEntry wifiIdleMs = DigitEntry.of(0L); + public DigitEntry wifiRxMs = DigitEntry.of(0L); + public DigitEntry wifiTxMs = DigitEntry.of(0L); + + public DigitEntry blueToothPowerMams = DigitEntry.of(0L); + public DigitEntry blueToothIdleMs = DigitEntry.of(0L); + public DigitEntry blueToothRxMs = DigitEntry.of(0L); + public DigitEntry blueToothTxMs = DigitEntry.of(0L); + + // Media & Hardware + public DigitEntry audioMs = DigitEntry.of(0L); + public DigitEntry videoMs = DigitEntry.of(0L); + public DigitEntry screenOnMs = DigitEntry.of(0L); + + + @Override + public Delta diff(HealthStatsSnapshot bgn) { + return new Delta(bgn, this) { + @Override + protected HealthStatsSnapshot computeDelta() { + HealthStatsSnapshot delta = new HealthStatsSnapshot(); + delta.cpuPowerMams = Differ.DigitDiffer.globalDiff(bgn.cpuPowerMams, end.cpuPowerMams); + delta.cpuUsrTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuUsrTimeMs, end.cpuUsrTimeMs); + delta.cpuSysTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuSysTimeMs, end.cpuSysTimeMs); + + delta.wakelocksPartialMs = Differ.DigitDiffer.globalDiff(bgn.wakelocksPartialMs, end.wakelocksPartialMs); + delta.gpsMs = Differ.DigitDiffer.globalDiff(bgn.gpsMs, end.gpsMs); + delta.sensorsPowerMams = Differ.DigitDiffer.globalDiff(bgn.sensorsPowerMams, end.sensorsPowerMams); + delta.cameraMs = Differ.DigitDiffer.globalDiff(bgn.cameraMs, end.cameraMs); + delta.flashLightMs = Differ.DigitDiffer.globalDiff(bgn.flashLightMs, end.flashLightMs); + + delta.mobilePowerMams = Differ.DigitDiffer.globalDiff(bgn.mobilePowerMams, end.mobilePowerMams); + delta.mobileRadioActiveMs = Differ.DigitDiffer.globalDiff(bgn.mobileRadioActiveMs, end.mobileRadioActiveMs); + delta.mobileIdleMs = Differ.DigitDiffer.globalDiff(bgn.mobileIdleMs, end.mobileIdleMs); + delta.mobileRxMs = Differ.DigitDiffer.globalDiff(bgn.mobileRxMs, end.mobileRxMs); + delta.mobileTxMs = Differ.DigitDiffer.globalDiff(bgn.mobileTxMs, end.mobileTxMs); + + delta.wifiPowerMams = Differ.DigitDiffer.globalDiff(bgn.wifiPowerMams, end.wifiPowerMams); + delta.wifiIdleMs = Differ.DigitDiffer.globalDiff(bgn.wifiIdleMs, end.wifiIdleMs); + delta.wifiRxMs = Differ.DigitDiffer.globalDiff(bgn.wifiRxMs, end.wifiRxMs); + delta.wifiTxMs = Differ.DigitDiffer.globalDiff(bgn.wifiTxMs, end.wifiTxMs); + + delta.blueToothPowerMams = Differ.DigitDiffer.globalDiff(bgn.blueToothPowerMams, end.blueToothPowerMams); + delta.blueToothIdleMs = Differ.DigitDiffer.globalDiff(bgn.blueToothIdleMs, end.blueToothIdleMs); + delta.blueToothRxMs = Differ.DigitDiffer.globalDiff(bgn.blueToothRxMs, end.blueToothRxMs); + delta.blueToothTxMs = Differ.DigitDiffer.globalDiff(bgn.blueToothTxMs, end.blueToothTxMs); + + delta.audioMs = Differ.DigitDiffer.globalDiff(bgn.audioMs, end.audioMs); + delta.videoMs = Differ.DigitDiffer.globalDiff(bgn.videoMs, end.videoMs); + delta.screenOnMs = Differ.DigitDiffer.globalDiff(bgn.screenOnMs, end.screenOnMs); + return delta; + } + }; + } + } +} diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java new file mode 100644 index 000000000..71e4c76ff --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -0,0 +1,352 @@ +package com.tencent.matrix.batterycanary.stats; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorManager; +import android.os.Build; +import android.os.health.HealthStats; +import android.os.health.SystemHealthManager; +import android.os.health.TimerStat; +import android.os.health.UidHealthStats; + +import com.tencent.matrix.batterycanary.BatteryCanary; +import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; +import com.tencent.matrix.batterycanary.utils.PowerProfile; +import com.tencent.matrix.util.MatrixLog; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + +/** + * @author Kaede + * @since 6/7/2022 + */ +@SuppressLint("RestrictedApi") +public final class HealthStatsHelper { + public static final String TAG = "HealthStatsHelper"; + + public static class UsageBasedPowerEstimator { + private static final double MILLIS_IN_HOUR = 1000.0 * 60 * 60; + private final double mAveragePowerMahPerMs; + + public UsageBasedPowerEstimator(double averagePowerMilliAmp) { + mAveragePowerMahPerMs = averagePowerMilliAmp / MILLIS_IN_HOUR; + } + public double calculatePower(long durationMs) { + return mAveragePowerMahPerMs * durationMs; + } + } + + public static boolean isSupported() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; + } + + @Nullable + public static HealthStats getCurrStats(Context context) { + if (isSupported()) { + try { + SystemHealthManager shm = (SystemHealthManager) context.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + return shm.takeMyUidSnapshot(); + } catch (Exception e) { + MatrixLog.w(TAG, "takeMyUidSnapshot err: " + e); + } + } + return null; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + static long getMeasure(HealthStats healthStats, int key) { + if (healthStats.hasMeasurement(key)) { + return healthStats.getMeasurement(key); + } + return 0L; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + static long getTimerTime(HealthStats healthStats, int key) { + if (healthStats.hasTimer(key)) { + return healthStats.getTimerTime(key); + } + return 0L; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcCpuPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_CPU_POWER_MAMS)) { + power = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_CPU_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + if (power > 0) { + MatrixLog.i(TAG, "estimate CPU by mams"); + } + } + if (power == 0) { + long cpuTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + healthStats.getMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); + power = estimateCpuPowerByCpuStats(powerProfile, cpuTimeMs); + } + return power; + } + + private static double estimateCpuPowerByCpuStats(PowerProfile powerProfile, long cpuTimeMs) { + CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); + if (feat != null && feat.isSupported()) { + CpuStatFeature.CpuStateSnapshot cpuStateSnapshot = feat.currentCpuStateSnapshot(); + if (cpuStateSnapshot != null) { + long jiffySum = 0; + for (MonitorFeature.Snapshot.Entry.ListEntry> stepJiffies : cpuStateSnapshot.procCpuCoreStates) { + for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies.getList()) { + jiffySum += item.get(); + } + } + double powerMah = 0; + for (int i = 0; i < cpuStateSnapshot.procCpuCoreStates.size(); i++) { + List> stepJiffies = cpuStateSnapshot.procCpuCoreStates.get(i).getList(); + for (int j = 0; j < stepJiffies.size(); j++) { + long jiffy = stepJiffies.get(j).get(); + long figuredCpuTimeMs = (long) ((jiffy * 1.0f / jiffySum) * cpuTimeMs); + double powerMa = powerProfile.getAveragePowerForCpuCore(i, j); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); + } + } + return powerMah; + } + } + return 0; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcWakelocksPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL); + long timeMs = 0; + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + double powerMa = powerProfile.getAveragePower("cpu.idle"); + power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcMobilePower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS)) { + power = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + if (power > 0) { + MatrixLog.i(TAG, "estimate Mobile by mams"); + } + } + if (power == 0) { + if (healthStats.hasTimer(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE); + double powerMa = powerProfile.getAveragePower("radio.active"); + power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (power > 0) { + MatrixLog.i(TAG, "estimate CPU by radio"); + } + } + if (power == 0) { + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); + double powerMa = powerProfile.getAveragePower("modem.controller.idle"); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS); + double powerMa = powerProfile.getAveragePower("modem.controller.rx"); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS); + double powerMa = powerProfile.getAveragePower("modem.controller.tx"); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcWifiPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS)) { + power = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + if (power > 0) { + MatrixLog.i(TAG, "estimate WIFI by mams"); + } + } + if (power == 0) { + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS)) { + double wifiIdlePower = powerProfile.getAveragePower("wifi.controller.idle"); + long idleMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS); + UsageBasedPowerEstimator etmWifiIdlePower = new UsageBasedPowerEstimator(wifiIdlePower); + power += etmWifiIdlePower.calculatePower(idleMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS)) { + double wifiRxPower = powerProfile.getAveragePower("wifi.controller.rx"); + UsageBasedPowerEstimator etmWifiRxPower = new UsageBasedPowerEstimator(wifiRxPower); + long rxMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS); + power += etmWifiRxPower.calculatePower(rxMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS)) { + long txMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS); + double wifiTxPower = powerProfile.getAveragePower("wifi.controller.tx"); + UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiTxPower); + power += etmWifiTxPower.calculatePower(txMs); + } + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcBlueToothPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS)) { + power = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + if (power > 0) { + MatrixLog.i(TAG, "etmMobilePower BLE by mams"); + } + } + if (power == 0) { + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS); + double powerMa = powerProfile.getAveragePower("bluetooth.controller.idle"); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS); + double powerMa = powerProfile.getAveragePower("bluetooth.controller.rx"); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS)) { + long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS); + double powerMa = powerProfile.getAveragePower("bluetooth.controller.tx"); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcGpsPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasTimer(UidHealthStats.TIMER_GPS_SENSOR)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_GPS_SENSOR); + double powerMa = 0; + if (powerProfile.getAveragePower("gps.voltage") > 0) { + powerMa = powerProfile.getAveragePower("gps.on"); + if (powerMa <= 0) { + int num = powerProfile.getNumElements("gps.signalqualitybased"); + double sumMa = 0; + for (int i = 0; i < num; i++) { + sumMa += powerProfile.getAveragePower("gps.signalqualitybased", i); + } + powerMa = sumMa / num; + } + } + power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcSensorsPower(Context context, HealthStats healthStats) { + double power = 0; + if (healthStats.hasTimers(UidHealthStats.TIMERS_SENSORS)) { + SensorManager sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + List sensorList = sm.getSensorList(Sensor.TYPE_ALL); + Map sensorMap = new HashMap<>(); + for (Sensor item : sensorList) { + try { + //noinspection JavaReflectionMemberAccess + @SuppressLint("DiscouragedPrivateApi") + Method method = item.getClass().getDeclaredMethod("getHandle"); + //noinspection ConstantConditions + int handle = (int) method.invoke(item); + sensorMap.put(String.valueOf(handle), item); + } catch (Throwable e) { + MatrixLog.w(TAG, "getSensorHandle err: " + e.getMessage()); + } + } + + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_SENSORS); + for (Map.Entry item : timers.entrySet()) { + String handle = item.getKey(); + long timeMs = item.getValue().getTime(); + if (handle.equals("-10000")) { + continue; // skip GPS Sensors + } + Sensor sensor = sensorMap.get(handle); + if (sensor != null) { + power += new UsageBasedPowerEstimator(sensor.getPower()).calculatePower(timeMs); + } + } + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcCameraPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasTimer(UidHealthStats.TIMER_CAMERA)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_CAMERA); + double powerMa = powerProfile.getAveragePower("camera.avg"); + power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcFlashLightPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasTimer(UidHealthStats.TIMER_FLASHLIGHT)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_FLASHLIGHT); + double powerMa = powerProfile.getAveragePower("camera.flashlight"); + power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcAudioPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasTimer(UidHealthStats.TIMER_AUDIO)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_AUDIO); + double powerMa = powerProfile.getAveragePower("audio"); + power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcVideoPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasTimer(UidHealthStats.TIMER_VIDEO)) { + long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_VIDEO); + double powerMa = powerProfile.getAveragePower("video"); + power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcScreenPower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS) && healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS)) { + long totalTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); + long screenOffTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS); + long screenOnTimeMs = totalTimeMs - screenOffTimeMs; + double powerMa = powerProfile.getAveragePower("screen.on"); + power = new UsageBasedPowerEstimator(powerMa).calculatePower(screenOnTimeMs); + } + return power; + } +} From 4135c1ef160b7f3d49ad15da813a3d14d10be925 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 18 Jul 2022 19:00:38 +0800 Subject: [PATCH 087/263] Optimize healthstats cfg --- .../batterycanary/stats/HealthStatsTest.java | 36 +++++ .../stats/HealthStatsHelper.java | 148 +++++++----------- 2 files changed, 94 insertions(+), 90 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 5553a036d..791fa719d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -231,6 +231,9 @@ public void testEstimateCpuPowerByCpuStats() throws IOException { long cpuTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + healthStats.getMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); double powerMah = estimateCpuPowerByCpuStats(cpuTimeMs); Assert.assertTrue(powerMah >= 0); + + double calcCpuPower = HealthStatsHelper.calcCpuPower(feature.getPowerProfile(), healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); } private static double estimateCpuPowerByCpuStats(long cpuTimeMs) { @@ -287,6 +290,9 @@ public void testEstimateWakelockPower() throws IOException { powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } Assert.assertTrue(powerMah >= 0); + + double calcCpuPower = HealthStatsHelper.calcWakelocksPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); } @Test @@ -331,6 +337,9 @@ public void testEstimateMobileRadioPower() throws IOException { powerMahByTime += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } Assert.assertTrue(powerMahByTime >= 0); + + double calcCpuPower = HealthStatsHelper.calcMobilePower(powerProfile, healthStats); + Assert.assertEquals(powerMahByTime, calcCpuPower, 1d); } @Test @@ -373,6 +382,9 @@ public void testEstimateWifiPower() throws IOException { powerMah += etmWifiTxPower.calculatePower(txMs); } Assert.assertTrue(powerMah >= 0); + + double calcCpuPower = HealthStatsHelper.calcWifiPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); } @Test @@ -411,6 +423,9 @@ public void testEstimateBlueToothPower() throws IOException { powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } Assert.assertTrue(powerMah >= 0); + + double calcCpuPower = HealthStatsHelper.calcBlueToothPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); } @Test @@ -444,6 +459,9 @@ public void testEstimateGpsPower() throws IOException { powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } Assert.assertTrue(powerMah >= 0); + + double calcCpuPower = HealthStatsHelper.calcGpsPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); } @Test @@ -502,6 +520,10 @@ public void testEstimateMediaAndHwPower() throws IOException { double powerMa = powerProfile.getAveragePower("camera.avg"); powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } + + double calcCpuPower = HealthStatsHelper.calcCameraPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); + // Flash Light Assert.assertTrue(powerProfile.getAveragePower("camera.flashlight") > 0); if (healthStats.hasTimer(UidHealthStats.TIMER_FLASHLIGHT)) { @@ -509,6 +531,10 @@ public void testEstimateMediaAndHwPower() throws IOException { double powerMa = powerProfile.getAveragePower("camera.flashlight"); powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } + + calcCpuPower = HealthStatsHelper.calcFlashLightPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); + // Media Assert.assertTrue(powerProfile.getAveragePower("audio") > 0); Assert.assertTrue(powerProfile.getAveragePower("video") > 0); @@ -517,12 +543,19 @@ public void testEstimateMediaAndHwPower() throws IOException { double powerMa = powerProfile.getAveragePower("audio"); powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } + + calcCpuPower = HealthStatsHelper.calcAudioPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); + if (healthStats.hasTimer(UidHealthStats.TIMER_VIDEO)) { long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_VIDEO); double powerMa = powerProfile.getAveragePower("video"); powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } Assert.assertTrue(powerMah >= 0); + + calcCpuPower = HealthStatsHelper.calcVideoPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); } @Test @@ -550,6 +583,9 @@ public void testEstimateScreenPower() throws IOException { powerMah += new UsageBasedPowerEstimator(powerProfile.getAveragePower("screen.on")).calculatePower(screenOnTimeMs); Assert.assertTrue(powerMah > 0); + + double calcCpuPower = HealthStatsHelper.calcScreenPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcCpuPower, 1d); } @Test diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 71e4c76ff..3ff307a09 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -39,6 +39,7 @@ public static class UsageBasedPowerEstimator { public UsageBasedPowerEstimator(double averagePowerMilliAmp) { mAveragePowerMahPerMs = averagePowerMilliAmp / MILLIS_IN_HOUR; } + public double calculatePower(long durationMs) { return mAveragePowerMahPerMs * durationMs; } @@ -79,15 +80,11 @@ static long getTimerTime(HealthStats healthStats, int key) { @RequiresApi(api = Build.VERSION_CODES.N) public static double calcCpuPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_CPU_POWER_MAMS)) { - power = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_CPU_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; - if (power > 0) { - MatrixLog.i(TAG, "estimate CPU by mams"); - } - } - if (power == 0) { - long cpuTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + healthStats.getMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); + double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_CPU_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + if (power > 0) { + MatrixLog.i(TAG, "estimate CPU by mams"); + } else if (power == 0) { + long cpuTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); power = estimateCpuPowerByCpuStats(powerProfile, cpuTimeMs); } return power; @@ -137,16 +134,13 @@ public static double calcWakelocksPower(PowerProfile powerProfile, HealthStats h @RequiresApi(api = Build.VERSION_CODES.N) public static double calcMobilePower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS)) { - power = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; - if (power > 0) { - MatrixLog.i(TAG, "estimate Mobile by mams"); - } + double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + if (power > 0) { + MatrixLog.i(TAG, "estimate Mobile by mams"); } if (power == 0) { - if (healthStats.hasTimer(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE)) { - long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE); + { + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE); double powerMa = powerProfile.getAveragePower("radio.active"); power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -155,18 +149,18 @@ public static double calcMobilePower(PowerProfile powerProfile, HealthStats heal } } if (power == 0) { - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS)) { - long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); double powerMa = powerProfile.getAveragePower("modem.controller.idle"); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS)) { - long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS); + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_MS); double powerMa = powerProfile.getAveragePower("modem.controller.rx"); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS)) { - long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS); + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_MS); double powerMa = powerProfile.getAveragePower("modem.controller.tx"); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -176,28 +170,26 @@ public static double calcMobilePower(PowerProfile powerProfile, HealthStats heal @RequiresApi(api = Build.VERSION_CODES.N) public static double calcWifiPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS)) { - power = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; - if (power > 0) { - MatrixLog.i(TAG, "estimate WIFI by mams"); - } + double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + if (power > 0) { + MatrixLog.i(TAG, "estimate WIFI by mams"); + } if (power == 0) { - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS)) { + { double wifiIdlePower = powerProfile.getAveragePower("wifi.controller.idle"); - long idleMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS); + long idleMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_IDLE_MS); UsageBasedPowerEstimator etmWifiIdlePower = new UsageBasedPowerEstimator(wifiIdlePower); power += etmWifiIdlePower.calculatePower(idleMs); } - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS)) { + { double wifiRxPower = powerProfile.getAveragePower("wifi.controller.rx"); UsageBasedPowerEstimator etmWifiRxPower = new UsageBasedPowerEstimator(wifiRxPower); - long rxMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS); + long rxMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_MS); power += etmWifiRxPower.calculatePower(rxMs); } - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS)) { - long txMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS); + { + long txMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_MS); double wifiTxPower = powerProfile.getAveragePower("wifi.controller.tx"); UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiTxPower); power += etmWifiTxPower.calculatePower(txMs); @@ -208,26 +200,24 @@ public static double calcWifiPower(PowerProfile powerProfile, HealthStats health @RequiresApi(api = Build.VERSION_CODES.N) public static double calcBlueToothPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS)) { - power = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; - if (power > 0) { - MatrixLog.i(TAG, "etmMobilePower BLE by mams"); - } + double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + if (power > 0) { + MatrixLog.i(TAG, "etmMobilePower BLE by mams"); + } if (power == 0) { - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS)) { - long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS); + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS); double powerMa = powerProfile.getAveragePower("bluetooth.controller.idle"); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS)) { - long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS); + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS); double powerMa = powerProfile.getAveragePower("bluetooth.controller.rx"); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS)) { - long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS); + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS); double powerMa = powerProfile.getAveragePower("bluetooth.controller.tx"); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -237,10 +227,9 @@ public static double calcBlueToothPower(PowerProfile powerProfile, HealthStats h @RequiresApi(api = Build.VERSION_CODES.N) public static double calcGpsPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasTimer(UidHealthStats.TIMER_GPS_SENSOR)) { - long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_GPS_SENSOR); - double powerMa = 0; + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_GPS_SENSOR); + double powerMa = 0; + if (timeMs > 0) { if (powerProfile.getAveragePower("gps.voltage") > 0) { powerMa = powerProfile.getAveragePower("gps.on"); if (powerMa <= 0) { @@ -252,9 +241,8 @@ public static double calcGpsPower(PowerProfile powerProfile, HealthStats healthS powerMa = sumMa / num; } } - power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - return power; + return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @RequiresApi(api = Build.VERSION_CODES.N) @@ -295,58 +283,38 @@ public static double calcSensorsPower(Context context, HealthStats healthStats) @RequiresApi(api = Build.VERSION_CODES.N) public static double calcCameraPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasTimer(UidHealthStats.TIMER_CAMERA)) { - long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_CAMERA); - double powerMa = powerProfile.getAveragePower("camera.avg"); - power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - return power; + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_CAMERA); + double powerMa = powerProfile.getAveragePower("camera.avg"); + return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @RequiresApi(api = Build.VERSION_CODES.N) public static double calcFlashLightPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasTimer(UidHealthStats.TIMER_FLASHLIGHT)) { - long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_FLASHLIGHT); - double powerMa = powerProfile.getAveragePower("camera.flashlight"); - power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - return power; + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_FLASHLIGHT); + double powerMa = powerProfile.getAveragePower("camera.flashlight"); + return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @RequiresApi(api = Build.VERSION_CODES.N) public static double calcAudioPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasTimer(UidHealthStats.TIMER_AUDIO)) { - long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_AUDIO); - double powerMa = powerProfile.getAveragePower("audio"); - power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - return power; + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_AUDIO); + double powerMa = powerProfile.getAveragePower("audio"); + return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @RequiresApi(api = Build.VERSION_CODES.N) public static double calcVideoPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasTimer(UidHealthStats.TIMER_VIDEO)) { - long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_VIDEO); - double powerMa = powerProfile.getAveragePower("video"); - power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - return power; + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_VIDEO); + double powerMa = powerProfile.getAveragePower("video"); + return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @RequiresApi(api = Build.VERSION_CODES.N) public static double calcScreenPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = 0; - if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS) && healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS)) { - long totalTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); - long screenOffTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS); - long screenOnTimeMs = totalTimeMs - screenOffTimeMs; - double powerMa = powerProfile.getAveragePower("screen.on"); - power = new UsageBasedPowerEstimator(powerMa).calculatePower(screenOnTimeMs); - } - return power; + long totalTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); + long screenOffTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS); + long screenOnTimeMs = totalTimeMs - screenOffTimeMs; + double powerMa = powerProfile.getAveragePower("screen.on"); + return new UsageBasedPowerEstimator(powerMa).calculatePower(screenOnTimeMs); } } From 0d822828c64d90b7883c717cf53283eeab9cc9a9 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 18 Jul 2022 19:10:33 +0800 Subject: [PATCH 088/263] Update healthstats feat --- .../batterycanary/stats/HealthStatsFeature.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index bfd0186b6..0eba27fc8 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -170,6 +170,7 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry videoPower = DigitEntry.of(0D); public DigitEntry screenPower = DigitEntry.of(0D); + // Meta Data: // CPU public DigitEntry cpuPowerMams = DigitEntry.of(0L); public DigitEntry cpuUsrTimeMs = DigitEntry.of(0L); @@ -211,6 +212,19 @@ public Delta diff(HealthStatsSnapshot bgn) { @Override protected HealthStatsSnapshot computeDelta() { HealthStatsSnapshot delta = new HealthStatsSnapshot(); + delta.cpuPower = Differ.DigitDiffer.globalDiff(bgn.cpuPower, end.cpuPower); + delta.wakelocksPower = Differ.DigitDiffer.globalDiff(bgn.wakelocksPower, end.wakelocksPower); + delta.mobilePower = Differ.DigitDiffer.globalDiff(bgn.mobilePower, end.mobilePower); + delta.wifiPower = Differ.DigitDiffer.globalDiff(bgn.wifiPower, end.wifiPower); + delta.blueToothPower = Differ.DigitDiffer.globalDiff(bgn.blueToothPower, end.blueToothPower); + delta.gpsPower = Differ.DigitDiffer.globalDiff(bgn.gpsPower, end.gpsPower); + delta.sensorsPower = Differ.DigitDiffer.globalDiff(bgn.sensorsPower, end.sensorsPower); + delta.cameraPower = Differ.DigitDiffer.globalDiff(bgn.cameraPower, end.cameraPower); + delta.flashLightPower = Differ.DigitDiffer.globalDiff(bgn.flashLightPower, end.flashLightPower); + delta.audioPower = Differ.DigitDiffer.globalDiff(bgn.audioPower, end.audioPower); + delta.videoPower = Differ.DigitDiffer.globalDiff(bgn.videoPower, end.videoPower); + delta.screenPower = Differ.DigitDiffer.globalDiff(bgn.screenPower, end.screenPower); + delta.cpuPowerMams = Differ.DigitDiffer.globalDiff(bgn.cpuPowerMams, end.cpuPowerMams); delta.cpuUsrTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuUsrTimeMs, end.cpuUsrTimeMs); delta.cpuSysTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuSysTimeMs, end.cpuSysTimeMs); From 11b47ce5a6d04718715d47af00bdf02d64442671 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 18 Jul 2022 19:21:28 +0800 Subject: [PATCH 089/263] Add total power --- .../batterycanary/stats/HealthStatsFeature.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 0eba27fc8..27a4036e5 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -69,6 +69,21 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.audioPower = DigitEntry.of(HealthStatsHelper.calcAudioPower(powerProfile, healthStats)); snapshot.videoPower = DigitEntry.of(HealthStatsHelper.calcVideoPower(powerProfile, healthStats)); snapshot.screenPower = DigitEntry.of(HealthStatsHelper.calcScreenPower(powerProfile, healthStats)); + + double total = snapshot.cpuPower.get() + + snapshot.wakelocksPower.get() + + snapshot.mobilePower.get() + + snapshot.wifiPower.get() + + snapshot.blueToothPower.get() + + snapshot.gpsPower.get() + + snapshot.sensorsPower.get() + + snapshot.cameraPower.get() + + snapshot.flashLightPower.get() + + snapshot.audioPower.get() + + snapshot.videoPower.get() + + snapshot.screenPower.get(); + + snapshot.totalPower = DigitEntry.of(total); } } @@ -157,6 +172,7 @@ public static class HealthStatsSnapshot extends Snapshot { public HealthStats healthStats; // Estimated Powers + public DigitEntry totalPower = DigitEntry.of(0D); public DigitEntry cpuPower = DigitEntry.of(0D); public DigitEntry wakelocksPower = DigitEntry.of(0D); public DigitEntry mobilePower = DigitEntry.of(0D); @@ -212,6 +228,7 @@ public Delta diff(HealthStatsSnapshot bgn) { @Override protected HealthStatsSnapshot computeDelta() { HealthStatsSnapshot delta = new HealthStatsSnapshot(); + delta.totalPower = Differ.DigitDiffer.globalDiff(bgn.totalPower, end.totalPower); delta.cpuPower = Differ.DigitDiffer.globalDiff(bgn.cpuPower, end.cpuPower); delta.wakelocksPower = Differ.DigitDiffer.globalDiff(bgn.wakelocksPower, end.wakelocksPower); delta.mobilePower = Differ.DigitDiffer.globalDiff(bgn.mobilePower, end.mobilePower); From 09424242980e64ebb378b71c0608af818c358de3 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 18 Jul 2022 20:27:07 +0800 Subject: [PATCH 090/263] Update powerprofile api --- .../matrix/batterycanary/utils/PowerProfile.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java index 09f6881b2..7993d2f62 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java @@ -13,6 +13,7 @@ import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; +import androidx.annotation.VisibleForTesting; /** * @see com.android.internal.os.PowerProfile @@ -257,8 +258,8 @@ public int getClusterByCpuNum(int cpuCoreNum) { private static final Object sLock = new Object(); - - PowerProfile(Context context) { + @VisibleForTesting + public PowerProfile(Context context) { // Read the XML file for the given profile (normally only one per device) synchronized (sLock) { if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) { @@ -268,6 +269,16 @@ public int getClusterByCpuNum(int cpuCoreNum) { } } + @VisibleForTesting + public static HashMap getPowerItemMap() { + return sPowerItemMap; + } + + @VisibleForTesting + public static HashMap getPowerArrayMap() { + return sPowerArrayMap; + } + @SuppressWarnings({"ToArrayCallWithZeroLengthArrayArgument", "UnnecessaryBoxing", "CatchMayIgnoreException", "TryWithIdenticalCatches"}) private void readPowerValuesFromXml(Context context) { final int id = context.getResources().getIdentifier("power_profile", "xml", "android"); From 40d0dd92b897d78052915f2defb7ba31cd9a4e26 Mon Sep 17 00:00:00 2001 From: leafjia Date: Tue, 19 Jul 2022 04:05:23 +0800 Subject: [PATCH 091/263] AF_NETLINK DO NOT count --- .../matrix-traffic/src/main/cpp/TrafficCollector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc index 34113dabf..c691746c6 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc @@ -64,7 +64,7 @@ int isNetworkSocketFd(int fd) { socklen_t cLen = sizeof(c); int getSockNameRet = getsockname(fd, (struct sockaddr*) &c, &cLen); if (getSockNameRet == 0) { - if (c.sa_family != AF_LOCAL && c.sa_family != AF_UNIX) { + if (c.sa_family != AF_LOCAL && c.sa_family != AF_NETLINK) { return 1; } } From df366ece306afbab37b48c482d44e79c98829d4e Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 19 Jul 2022 15:36:38 +0800 Subject: [PATCH 092/263] memory-canary: fix smaps entry pattern --- .../java/com/tencent/matrix/memory/canary/MemInfoFactory.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt index 21affb910..74c9af0a4 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt @@ -641,7 +641,7 @@ data class MergedSmapsInfo( private fun mergeSmaps(pid: Int): ArrayList { val pattern = - Pattern.compile("^[0-9a-f]+-[0-9a-f]+\\s+([rwxps-]{4})\\s+\\d+\\s+\\d+:\\d+\\s+\\d+\\s+(.*)$") + Pattern.compile("^[0-9a-f]+-[0-9a-f]+\\s+([rwxps-]{4})\\s+[0-9a-f]+\\s+[0-9a-f]+:[0-9a-f]+\\s+\\d+\\s+(.*)$") val merged: HashMap = HashMap() var currentInfo: SmapsItem? = null From 665bb8f53e2b6109878c30a55ff9ac77ccfb6a6b Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 19 Jul 2022 16:57:58 +0800 Subject: [PATCH 093/263] Update battery healstats power cfg --- .../batterycanary/stats/HealthStatsTest.java | 5 +- .../stats/HealthStatsFeature.java | 3 + .../stats/HealthStatsHelper.java | 93 ++++++++++++------- 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 791fa719d..673264cd8 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -320,6 +320,9 @@ public void testEstimateMobileRadioPower() throws IOException { } Assert.assertTrue(powerMahByRadio >= 0); + double calcCpuPower = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats); + Assert.assertEquals(powerMahByRadio, calcCpuPower, 1d); + double powerMahByTime = 0; if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS)) { long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); @@ -338,7 +341,7 @@ public void testEstimateMobileRadioPower() throws IOException { } Assert.assertTrue(powerMahByTime >= 0); - double calcCpuPower = HealthStatsHelper.calcMobilePower(powerProfile, healthStats); + calcCpuPower = HealthStatsHelper.calcMobilePower(powerProfile, healthStats); Assert.assertEquals(powerMahByTime, calcCpuPower, 1d); } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 27a4036e5..4c116b28b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -60,6 +60,7 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.cpuPower = DigitEntry.of(HealthStatsHelper.calcCpuPower(powerProfile, healthStats)); snapshot.wakelocksPower = DigitEntry.of(HealthStatsHelper.calcWakelocksPower(powerProfile, healthStats)); snapshot.mobilePower = DigitEntry.of(HealthStatsHelper.calcMobilePower(powerProfile, healthStats)); + snapshot.radioActivePower = DigitEntry.of(HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats)); snapshot.wifiPower = DigitEntry.of(HealthStatsHelper.calcWifiPower(powerProfile, healthStats)); snapshot.blueToothPower = DigitEntry.of(HealthStatsHelper.calcBlueToothPower(powerProfile, healthStats)); snapshot.gpsPower = DigitEntry.of(HealthStatsHelper.calcGpsPower(powerProfile, healthStats)); @@ -176,6 +177,7 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry cpuPower = DigitEntry.of(0D); public DigitEntry wakelocksPower = DigitEntry.of(0D); public DigitEntry mobilePower = DigitEntry.of(0D); + public DigitEntry radioActivePower = DigitEntry.of(0D); public DigitEntry wifiPower = DigitEntry.of(0D); public DigitEntry blueToothPower = DigitEntry.of(0D); public DigitEntry gpsPower = DigitEntry.of(0D); @@ -232,6 +234,7 @@ protected HealthStatsSnapshot computeDelta() { delta.cpuPower = Differ.DigitDiffer.globalDiff(bgn.cpuPower, end.cpuPower); delta.wakelocksPower = Differ.DigitDiffer.globalDiff(bgn.wakelocksPower, end.wakelocksPower); delta.mobilePower = Differ.DigitDiffer.globalDiff(bgn.mobilePower, end.mobilePower); + delta.radioActivePower = Differ.DigitDiffer.globalDiff(bgn.radioActivePower, end.radioActivePower); delta.wifiPower = Differ.DigitDiffer.globalDiff(bgn.wifiPower, end.wifiPower); delta.blueToothPower = Differ.DigitDiffer.globalDiff(bgn.blueToothPower, end.blueToothPower); delta.gpsPower = Differ.DigitDiffer.globalDiff(bgn.gpsPower, end.gpsPower); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 3ff307a09..e93a27c12 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; +import androidx.annotation.ChecksSdkIntAtLeast; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @@ -28,6 +29,7 @@ * @author Kaede * @since 6/7/2022 */ +@SuppressWarnings("JavadocReference") @SuppressLint("RestrictedApi") public final class HealthStatsHelper { public static final String TAG = "HealthStatsHelper"; @@ -45,6 +47,7 @@ public double calculatePower(long durationMs) { } } + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N) public static boolean isSupported() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; } @@ -126,71 +129,76 @@ public static double calcWakelocksPower(PowerProfile powerProfile, HealthStats h for (TimerStat item : timers.values()) { timeMs += item.getTime(); } - double powerMa = powerProfile.getAveragePower("cpu.idle"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE); power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } return power; } + /** + * @see com.android.internal.os.MobileRadioPowerCalculator + */ + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcMobilePowerByRadioActive(PowerProfile powerProfile, HealthStats healthStats) { + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE); + return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + + /** + * @see com.android.internal.os.MobileRadioPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcMobilePower(PowerProfile powerProfile, HealthStats healthStats) { double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; if (power > 0) { MatrixLog.i(TAG, "estimate Mobile by mams"); } - if (power == 0) { - { - long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE); - double powerMa = powerProfile.getAveragePower("radio.active"); - power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - if (power > 0) { - MatrixLog.i(TAG, "estimate CPU by radio"); - } - } if (power == 0) { { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); - double powerMa = powerProfile.getAveragePower("modem.controller.idle"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_MS); - double powerMa = powerProfile.getAveragePower("modem.controller.rx"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_MS); - double powerMa = powerProfile.getAveragePower("modem.controller.tx"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } } return power; } + /** + * @see com.android.internal.os.WifiPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcWifiPower(PowerProfile powerProfile, HealthStats healthStats) { double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; if (power > 0) { MatrixLog.i(TAG, "estimate WIFI by mams"); - } if (power == 0) { { - double wifiIdlePower = powerProfile.getAveragePower("wifi.controller.idle"); + double wifiIdlePower = powerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE); long idleMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_IDLE_MS); UsageBasedPowerEstimator etmWifiIdlePower = new UsageBasedPowerEstimator(wifiIdlePower); power += etmWifiIdlePower.calculatePower(idleMs); } { - double wifiRxPower = powerProfile.getAveragePower("wifi.controller.rx"); + double wifiRxPower = powerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX); UsageBasedPowerEstimator etmWifiRxPower = new UsageBasedPowerEstimator(wifiRxPower); long rxMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_MS); power += etmWifiRxPower.calculatePower(rxMs); } { + double wifiTxPower = powerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX); long txMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_MS); - double wifiTxPower = powerProfile.getAveragePower("wifi.controller.tx"); UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiTxPower); power += etmWifiTxPower.calculatePower(txMs); } @@ -198,45 +206,50 @@ public static double calcWifiPower(PowerProfile powerProfile, HealthStats health return power; } + /** + * @see com.android.internal.os.BluetoothPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcBlueToothPower(PowerProfile powerProfile, HealthStats healthStats) { double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; if (power > 0) { MatrixLog.i(TAG, "etmMobilePower BLE by mams"); - } if (power == 0) { { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS); - double powerMa = powerProfile.getAveragePower("bluetooth.controller.idle"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS); - double powerMa = powerProfile.getAveragePower("bluetooth.controller.rx"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS); - double powerMa = powerProfile.getAveragePower("bluetooth.controller.tx"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } } return power; } + /** + * @see com.android.internal.os.GnssPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcGpsPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_GPS_SENSOR); double powerMa = 0; if (timeMs > 0) { - if (powerProfile.getAveragePower("gps.voltage") > 0) { - powerMa = powerProfile.getAveragePower("gps.on"); + if (powerProfile.getAveragePower(PowerProfile.POWER_GPS_OPERATING_VOLTAGE) > 0) { + powerMa = powerProfile.getAveragePower(PowerProfile.POWER_GPS_ON); if (powerMa <= 0) { - int num = powerProfile.getNumElements("gps.signalqualitybased"); + int num = powerProfile.getNumElements(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED); double sumMa = 0; for (int i = 0; i < num; i++) { - sumMa += powerProfile.getAveragePower("gps.signalqualitybased", i); + sumMa += powerProfile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i); } powerMa = sumMa / num; } @@ -245,6 +258,9 @@ public static double calcGpsPower(PowerProfile powerProfile, HealthStats healthS return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } + /** + * @see com.android.internal.os.SensorPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcSensorsPower(Context context, HealthStats healthStats) { double power = 0; @@ -281,40 +297,55 @@ public static double calcSensorsPower(Context context, HealthStats healthStats) return power; } + /** + * @see com.android.internal.os.CameraPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcCameraPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_CAMERA); - double powerMa = powerProfile.getAveragePower("camera.avg"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_CAMERA); return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } + /** + * @see com.android.internal.os.FlashlightPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcFlashLightPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_FLASHLIGHT); - double powerMa = powerProfile.getAveragePower("camera.flashlight"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT); return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } + /** + * @see com.android.internal.os.MediaPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcAudioPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_AUDIO); - double powerMa = powerProfile.getAveragePower("audio"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_AUDIO); return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } + /** + * @see com.android.internal.os.MediaPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcVideoPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_VIDEO); - double powerMa = powerProfile.getAveragePower("video"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_VIDEO); return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } + /** + * @see com.android.internal.os.ScreenPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcScreenPower(PowerProfile powerProfile, HealthStats healthStats) { long totalTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); long screenOffTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS); long screenOnTimeMs = totalTimeMs - screenOffTimeMs; - double powerMa = powerProfile.getAveragePower("screen.on"); + double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON); return new UsageBasedPowerEstimator(powerMa).calculatePower(screenOnTimeMs); } } From ad8b4f58ffbb49126577b6e172a4a9eb9fdb144f Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 19 Jul 2022 19:45:09 +0800 Subject: [PATCH 094/263] memory-canary: add toBriefString api to MergedSmapsInfo --- .../matrix/memory/canary/MemInfoFactory.kt | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt index 74c9af0a4..3d410960b 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt @@ -555,6 +555,83 @@ data class SmapsItem( data class MergedSmapsInfo( val list: List? = null ) { + fun toBriefString(): String { + val sb = StringBuilder() + sb.append("\n") + sb.append( + String.format( + FORMAT, + "PSS", + "RSS", + "SIZE", + "SWAP_PSS", + "SH_C", + "SH_D", + "PRI_C", + "PRI_D", + "COUNT", + "PERM", + "NAME" + ) + ).append("\n") + sb.append( + String.format( + FORMAT, + "----", + "----", + "----", + "----", + "----", + "----", + "----", + "----", + "----", + "----", + "----" + ) + ).append("\n") + for ((name, permission, count, vmSize, rss, pss, sharedClean, sharedDirty, privateClean, privateDirty, swapPss) in list!!) { + if (pss < 1024 /* K */) { + continue + } + sb.append( + String.format( + FORMAT, + pss, + rss, + vmSize, + swapPss, + sharedClean, + sharedDirty, + privateClean, + privateDirty, + count, + permission, + name + ) + ).append("\n") + } + sb.append( + String.format( + FORMAT, + "----", + "----", + "----", + "----", + "----", + "----", + "----", + "----", + "----", + "----", + "----" + ) + ) + sb.append("\n") + + return sb.toString() + } + override fun toString(): String { val sb = StringBuilder() sb.append("\n") From 6db4a0535eed3dcee51374ec80c223c4ddc430d2 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 20 Jul 2022 15:29:31 +0800 Subject: [PATCH 095/263] Update battery power calc --- .../batterycanary/stats/HealthStatsTest.java | 73 ++++++++----------- .../stats/HealthStatsFeature.java | 7 +- .../stats/HealthStatsHelper.java | 70 ++++++++++++++---- 3 files changed, 89 insertions(+), 61 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 673264cd8..72abfb893 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -291,8 +291,8 @@ public void testEstimateWakelockPower() throws IOException { } Assert.assertTrue(powerMah >= 0); - double calcCpuPower = HealthStatsHelper.calcWakelocksPower(powerProfile, healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); + double calcPower = HealthStatsHelper.calcWakelocksPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcPower, 1d); } @Test @@ -320,8 +320,8 @@ public void testEstimateMobileRadioPower() throws IOException { } Assert.assertTrue(powerMahByRadio >= 0); - double calcCpuPower = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats); - Assert.assertEquals(powerMahByRadio, calcCpuPower, 1d); + double calcPower = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats); + Assert.assertEquals(powerMahByRadio, calcPower, 1d); double powerMahByTime = 0; if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS)) { @@ -341,8 +341,8 @@ public void testEstimateMobileRadioPower() throws IOException { } Assert.assertTrue(powerMahByTime >= 0); - calcCpuPower = HealthStatsHelper.calcMobilePower(powerProfile, healthStats); - Assert.assertEquals(powerMahByTime, calcCpuPower, 1d); + calcPower = HealthStatsHelper.calcMobilePower(powerProfile, healthStats); + Assert.assertEquals(powerMahByTime, calcPower, 1d); } @Test @@ -386,8 +386,8 @@ public void testEstimateWifiPower() throws IOException { } Assert.assertTrue(powerMah >= 0); - double calcCpuPower = HealthStatsHelper.calcWifiPower(powerProfile, healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); + double calcPower = HealthStatsHelper.calcWifiPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcPower, 1d); } @Test @@ -427,8 +427,8 @@ public void testEstimateBlueToothPower() throws IOException { } Assert.assertTrue(powerMah >= 0); - double calcCpuPower = HealthStatsHelper.calcBlueToothPower(powerProfile, healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); + double calcPower = HealthStatsHelper.calcBlueToothPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcPower, 1d); } @Test @@ -438,16 +438,14 @@ public void testEstimateGpsPower() throws IOException { Assert.assertTrue(powerProfile.isSupported()); double powerMa = 0; - if (powerProfile.getAveragePower("gps.voltage") > 0) { - powerMa = powerProfile.getAveragePower("gps.on"); - if (powerMa <= 0) { - int num = powerProfile.getNumElements("gps.signalqualitybased"); - double sumMa = 0; - for (int i = 0; i < num; i++) { - sumMa += powerProfile.getAveragePower("gps.signalqualitybased", i); - } - powerMa = sumMa / num; + powerMa = powerProfile.getAveragePower("gps.on"); + if (powerMa <= 0) { + int num = powerProfile.getNumElements("gps.signalqualitybased"); + double sumMa = 0; + for (int i = 0; i < num; i++) { + sumMa += powerProfile.getAveragePower("gps.signalqualitybased", i); } + powerMa = sumMa / num; } Assert.assertTrue(powerMa > 0); @@ -463,8 +461,8 @@ public void testEstimateGpsPower() throws IOException { } Assert.assertTrue(powerMah >= 0); - double calcCpuPower = HealthStatsHelper.calcGpsPower(powerProfile, healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); + double calcPower = HealthStatsHelper.calcGpsPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcPower, 1d); } @Test @@ -524,8 +522,8 @@ public void testEstimateMediaAndHwPower() throws IOException { powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - double calcCpuPower = HealthStatsHelper.calcCameraPower(powerProfile, healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); + double calcPower = HealthStatsHelper.calcCameraPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcPower, 1d); // Flash Light Assert.assertTrue(powerProfile.getAveragePower("camera.flashlight") > 0); @@ -535,8 +533,8 @@ public void testEstimateMediaAndHwPower() throws IOException { powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - calcCpuPower = HealthStatsHelper.calcFlashLightPower(powerProfile, healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); + calcPower = HealthStatsHelper.calcFlashLightPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcPower, 1d); // Media Assert.assertTrue(powerProfile.getAveragePower("audio") > 0); @@ -547,8 +545,8 @@ public void testEstimateMediaAndHwPower() throws IOException { powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - calcCpuPower = HealthStatsHelper.calcAudioPower(powerProfile, healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); + calcPower = HealthStatsHelper.calcAudioPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcPower, 1d); if (healthStats.hasTimer(UidHealthStats.TIMER_VIDEO)) { long timeMs = healthStats.getTimerTime(UidHealthStats.TIMER_VIDEO); @@ -557,8 +555,8 @@ public void testEstimateMediaAndHwPower() throws IOException { } Assert.assertTrue(powerMah >= 0); - calcCpuPower = HealthStatsHelper.calcVideoPower(powerProfile, healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); + calcPower = HealthStatsHelper.calcVideoPower(powerProfile, healthStats); + Assert.assertEquals(powerMah, calcPower, 1d); } @Test @@ -574,21 +572,8 @@ public void testEstimateScreenPower() throws IOException { HealthStats healthStats = manager.takeMyUidSnapshot(); Assert.assertNotNull(healthStats); - Assert.assertTrue(healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS)); - Assert.assertTrue(healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS)); - - long totalTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); - long screenOffTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS); - Assert.assertTrue(totalTimeMs >= screenOffTimeMs); - long screenOnTimeMs = totalTimeMs - screenOffTimeMs; - - double powerMah = 0; - powerMah += new UsageBasedPowerEstimator(powerProfile.getAveragePower("screen.on")).calculatePower(screenOnTimeMs); - - Assert.assertTrue(powerMah > 0); - - double calcCpuPower = HealthStatsHelper.calcScreenPower(powerProfile, healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); + double calcPower = HealthStatsHelper.calcScreenPower(powerProfile, healthStats); + Assert.assertTrue(calcPower >= 0); } @Test diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 4c116b28b..d93f4b850 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -60,7 +60,6 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.cpuPower = DigitEntry.of(HealthStatsHelper.calcCpuPower(powerProfile, healthStats)); snapshot.wakelocksPower = DigitEntry.of(HealthStatsHelper.calcWakelocksPower(powerProfile, healthStats)); snapshot.mobilePower = DigitEntry.of(HealthStatsHelper.calcMobilePower(powerProfile, healthStats)); - snapshot.radioActivePower = DigitEntry.of(HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats)); snapshot.wifiPower = DigitEntry.of(HealthStatsHelper.calcWifiPower(powerProfile, healthStats)); snapshot.blueToothPower = DigitEntry.of(HealthStatsHelper.calcBlueToothPower(powerProfile, healthStats)); snapshot.gpsPower = DigitEntry.of(HealthStatsHelper.calcGpsPower(powerProfile, healthStats)); @@ -85,6 +84,7 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { + snapshot.screenPower.get(); snapshot.totalPower = DigitEntry.of(total); + snapshot.radioActivePower = DigitEntry.of(HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats)); } } @@ -230,11 +230,9 @@ public Delta diff(HealthStatsSnapshot bgn) { @Override protected HealthStatsSnapshot computeDelta() { HealthStatsSnapshot delta = new HealthStatsSnapshot(); - delta.totalPower = Differ.DigitDiffer.globalDiff(bgn.totalPower, end.totalPower); delta.cpuPower = Differ.DigitDiffer.globalDiff(bgn.cpuPower, end.cpuPower); delta.wakelocksPower = Differ.DigitDiffer.globalDiff(bgn.wakelocksPower, end.wakelocksPower); delta.mobilePower = Differ.DigitDiffer.globalDiff(bgn.mobilePower, end.mobilePower); - delta.radioActivePower = Differ.DigitDiffer.globalDiff(bgn.radioActivePower, end.radioActivePower); delta.wifiPower = Differ.DigitDiffer.globalDiff(bgn.wifiPower, end.wifiPower); delta.blueToothPower = Differ.DigitDiffer.globalDiff(bgn.blueToothPower, end.blueToothPower); delta.gpsPower = Differ.DigitDiffer.globalDiff(bgn.gpsPower, end.gpsPower); @@ -245,6 +243,9 @@ protected HealthStatsSnapshot computeDelta() { delta.videoPower = Differ.DigitDiffer.globalDiff(bgn.videoPower, end.videoPower); delta.screenPower = Differ.DigitDiffer.globalDiff(bgn.screenPower, end.screenPower); + delta.totalPower = Differ.DigitDiffer.globalDiff(bgn.totalPower, end.totalPower); + delta.radioActivePower = Differ.DigitDiffer.globalDiff(bgn.radioActivePower, end.radioActivePower); + delta.cpuPowerMams = Differ.DigitDiffer.globalDiff(bgn.cpuPowerMams, end.cpuPowerMams); delta.cpuUsrTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuUsrTimeMs, end.cpuUsrTimeMs); delta.cpuSysTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuSysTimeMs, end.cpuSysTimeMs); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index e93a27c12..72cac9798 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -37,11 +37,12 @@ public final class HealthStatsHelper { public static class UsageBasedPowerEstimator { private static final double MILLIS_IN_HOUR = 1000.0 * 60 * 60; private final double mAveragePowerMahPerMs; - public UsageBasedPowerEstimator(double averagePowerMilliAmp) { mAveragePowerMahPerMs = averagePowerMilliAmp / MILLIS_IN_HOUR; } - + public boolean isSupported() { + return mAveragePowerMahPerMs != 0; + } public double calculatePower(long durationMs) { return mAveragePowerMahPerMs * durationMs; } @@ -81,12 +82,34 @@ static long getTimerTime(HealthStats healthStats, int key) { return 0L; } + /** + * @see com.android.internal.os.CpuPowerCalculator + * @see com.android.internal.os.PowerProfile + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcCpuPower(PowerProfile powerProfile, HealthStats healthStats) { double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_CPU_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; if (power > 0) { MatrixLog.i(TAG, "estimate CPU by mams"); } else if (power == 0) { + /* + * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode. + * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should + * be zero on devices that can go into full CPU power collapse even when a wake + * lock is held. Otherwise, this is the power consumption in addition to + * POWER_CPU_SUSPEND due to a wake lock being held but with no CPU activity. + * POWER_CPU_ACTIVE: Power consumption when CPU is running, excluding power consumed by clusters + * and cores. + * + * CPU Power Equation (assume two clusters): + * Total power = POWER_CPU_SUSPEND (always added) + * + POWER_CPU_IDLE (skip this and below if in power collapse mode) + * + POWER_CPU_ACTIVE (skip this and below if CPU is not running, but a wakelock + * is held) + * + cluster_power.cluster0 + cluster_power.cluster1 (skip cluster not running) + * + core_power.cluster0 * num running cores in cluster 0 + * + core_power.cluster1 * num running cores in cluster 1 + */ long cpuTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); power = estimateCpuPowerByCpuStats(powerProfile, cpuTimeMs); } @@ -120,6 +143,23 @@ private static double estimateCpuPowerByCpuStats(PowerProfile powerProfile, long return 0; } + /** + * WIP + * @see com.android.internal.os.MemoryPowerCalculator + */ + public static double calcMemoryPower(PowerProfile powerProfile) { + double power = 0; + int numBuckets = powerProfile.getNumElements(PowerProfile.POWER_MEMORY); + for (int i = 0; i < numBuckets; i++) { + long timeMs = 0; // TODO: Memory TimeStats supported, see "com.android.internal.os.KernelMemoryBandwidthStats" + power += new UsageBasedPowerEstimator(powerProfile.getAveragePower(PowerProfile.POWER_MEMORY, i)).calculatePower(timeMs); + } + return power; + } + + /** + * @see com.android.internal.os.WakelockPowerCalculator + */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcWakelocksPower(PowerProfile powerProfile, HealthStats healthStats) { double power = 0; @@ -170,6 +210,8 @@ public static double calcMobilePower(PowerProfile powerProfile, HealthStats heal double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } + + // FIXME: calc with packets } return power; } @@ -202,6 +244,8 @@ public static double calcWifiPower(PowerProfile powerProfile, HealthStats health UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiTxPower); power += etmWifiTxPower.calculatePower(txMs); } + + // FIXME: calc without wifi-controller } return power; } @@ -243,16 +287,14 @@ public static double calcGpsPower(PowerProfile powerProfile, HealthStats healthS long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_GPS_SENSOR); double powerMa = 0; if (timeMs > 0) { - if (powerProfile.getAveragePower(PowerProfile.POWER_GPS_OPERATING_VOLTAGE) > 0) { - powerMa = powerProfile.getAveragePower(PowerProfile.POWER_GPS_ON); - if (powerMa <= 0) { - int num = powerProfile.getNumElements(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED); - double sumMa = 0; - for (int i = 0; i < num; i++) { - sumMa += powerProfile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i); - } - powerMa = sumMa / num; + powerMa = powerProfile.getAveragePower(PowerProfile.POWER_GPS_ON); + if (powerMa <= 0) { + int num = powerProfile.getNumElements(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED); + double sumMa = 0; + for (int i = 0; i < num; i++) { + sumMa += powerProfile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i); } + powerMa = sumMa / num; } } return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); @@ -342,9 +384,9 @@ public static double calcVideoPower(PowerProfile powerProfile, HealthStats healt */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcScreenPower(PowerProfile powerProfile, HealthStats healthStats) { - long totalTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); - long screenOffTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS); - long screenOnTimeMs = totalTimeMs - screenOffTimeMs; + long topAppMs = getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_TOP_MS); + long fgActivityMs = getTimerTime(healthStats, UidHealthStats.TIMER_FOREGROUND_ACTIVITY); + long screenOnTimeMs = Math.min(topAppMs, fgActivityMs); double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON); return new UsageBasedPowerEstimator(powerMa).calculatePower(screenOnTimeMs); } From 922e33d618b8b2c818ee79efeb38ad85bfca20bc Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 20 Jul 2022 17:34:41 +0800 Subject: [PATCH 096/263] Add battery systemservice & idle power calc --- .../batterycanary/stats/HealthStatsTest.java | 64 +++++++++++++- .../stats/HealthStatsHelper.java | 88 +++++++++++++++---- 2 files changed, 131 insertions(+), 21 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 72abfb893..3d40b8cff 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -229,15 +229,14 @@ public void testEstimateCpuPowerByCpuStats() throws IOException { healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS); healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); long cpuTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + healthStats.getMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); - double powerMah = estimateCpuPowerByCpuStats(cpuTimeMs); + double powerMah = estimateCpuPowerByCpuStats(feature, cpuTimeMs); Assert.assertTrue(powerMah >= 0); double calcCpuPower = HealthStatsHelper.calcCpuPower(feature.getPowerProfile(), healthStats); Assert.assertEquals(powerMah, calcCpuPower, 1d); } - private static double estimateCpuPowerByCpuStats(long cpuTimeMs) { - CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); + private static double estimateCpuPowerByCpuStats(CpuStatFeature feat, long cpuTimeMs) { if (feat != null && feat.isSupported()) { CpuStatFeature.CpuStateSnapshot cpuStateSnapshot = feat.currentCpuStateSnapshot(); if (cpuStateSnapshot != null) { @@ -265,6 +264,17 @@ private static double estimateCpuPowerByCpuStats(long cpuTimeMs) { @Test public void testEstimateMemoryPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + int num = powerProfile.getNumElements(PowerProfile.POWER_MEMORY); + for (int i = 0; i < num; i++) { + Assert.assertTrue(powerProfile.getAveragePower(PowerProfile.POWER_MEMORY, num) > 0); + } + + double calcPower = HealthStatsHelper.calcMemoryPower(powerProfile); + Assert.assertTrue(calcPower >= 0); } @Test @@ -578,10 +588,58 @@ public void testEstimateScreenPower() throws IOException { @Test public void testEstimateSystemServicePower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + CpuStatFeature feature = new CpuStatFeature(); + feature.configure(mockMonitor()); + feature.onTurnOn(); + + Assert.assertTrue(feature.isSupported()); + CpuStatFeature.CpuStateSnapshot cpuStateSnapshot = feature.currentCpuStateSnapshot(); + Assert.assertTrue(cpuStateSnapshot.procCpuCoreStates.size() > 0); + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + long timeMs = 0; + if (healthStats.hasTimers(UidHealthStats.TIMERS_JOBS)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_JOBS); + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + } + if (healthStats.hasTimers(UidHealthStats.TIMERS_SYNCS)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_SYNCS); + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + } + + double calcPower = estimateCpuPowerByCpuStats(feature, timeMs); + Assert.assertTrue(calcPower >= 0); + + calcPower = HealthStatsHelper.calcSystemServicePower(powerProfile, healthStats); + Assert.assertTrue(calcPower >= 0); } @Test public void testEstimateIdlePower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + Assert.assertTrue(powerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND) > 0); + Assert.assertTrue(powerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE) > 0); + + SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); + HealthStats healthStats = manager.takeMyUidSnapshot(); + Assert.assertNotNull(healthStats); + + double calcPower = HealthStatsHelper.calcIdlePower(powerProfile, healthStats); + Assert.assertTrue(calcPower >= 0); } @Test diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 72cac9798..5da046b09 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -26,6 +26,23 @@ import androidx.annotation.RequiresApi; /** + * totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + + * sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah + + * flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah + * + systemServiceCpuPowerMah; + * if (customMeasuredPowerMah != null) { + * for (int idx = 0; idx < customMeasuredPowerMah.length; idx++) { + * totalPowerMah += customMeasuredPowerMah[idx]; + * } + * } + * // powerAttributedToOtherSippersMah is negative or zero + * totalPowerMah = totalPowerMah + powerReattributedToOtherSippersMah; + * totalSmearedPowerMah = totalPowerMah + screenPowerMah + proportionalSmearMah; + * + * @see com.android.internal.os.BatterySipper#sumPower + * @see com.android.internal.os.BatteryStatsHelper + * @see com.android.internal.os.BatteryStatsImpl.Uid + * * @author Kaede * @since 6/7/2022 */ @@ -117,27 +134,29 @@ public static double calcCpuPower(PowerProfile powerProfile, HealthStats healthS } private static double estimateCpuPowerByCpuStats(PowerProfile powerProfile, long cpuTimeMs) { - CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); - if (feat != null && feat.isSupported()) { - CpuStatFeature.CpuStateSnapshot cpuStateSnapshot = feat.currentCpuStateSnapshot(); - if (cpuStateSnapshot != null) { - long jiffySum = 0; - for (MonitorFeature.Snapshot.Entry.ListEntry> stepJiffies : cpuStateSnapshot.procCpuCoreStates) { - for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies.getList()) { - jiffySum += item.get(); + if (cpuTimeMs > 0) { + CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); + if (feat != null && feat.isSupported()) { + CpuStatFeature.CpuStateSnapshot cpuStateSnapshot = feat.currentCpuStateSnapshot(); + if (cpuStateSnapshot != null) { + long jiffySum = 0; + for (MonitorFeature.Snapshot.Entry.ListEntry> stepJiffies : cpuStateSnapshot.procCpuCoreStates) { + for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies.getList()) { + jiffySum += item.get(); + } } - } - double powerMah = 0; - for (int i = 0; i < cpuStateSnapshot.procCpuCoreStates.size(); i++) { - List> stepJiffies = cpuStateSnapshot.procCpuCoreStates.get(i).getList(); - for (int j = 0; j < stepJiffies.size(); j++) { - long jiffy = stepJiffies.get(j).get(); - long figuredCpuTimeMs = (long) ((jiffy * 1.0f / jiffySum) * cpuTimeMs); - double powerMa = powerProfile.getAveragePowerForCpuCore(i, j); - powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); + double powerMah = 0; + for (int i = 0; i < cpuStateSnapshot.procCpuCoreStates.size(); i++) { + List> stepJiffies = cpuStateSnapshot.procCpuCoreStates.get(i).getList(); + for (int j = 0; j < stepJiffies.size(); j++) { + long jiffy = stepJiffies.get(j).get(); + long figuredCpuTimeMs = (long) ((jiffy * 1.0f / jiffySum) * cpuTimeMs); + double powerMa = powerProfile.getAveragePowerForCpuCore(i, j); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); + } } + return powerMah; } - return powerMah; } } return 0; @@ -390,4 +409,37 @@ public static double calcScreenPower(PowerProfile powerProfile, HealthStats heal double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON); return new UsageBasedPowerEstimator(powerMa).calculatePower(screenOnTimeMs); } + + /** + * @see com.android.internal.os.SystemServicePowerCalculator + */ + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcSystemServicePower(PowerProfile powerProfile, HealthStats healthStats) { + long timeMs = 0; + if (healthStats.hasTimers(UidHealthStats.TIMERS_JOBS)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_JOBS); + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + } + if (healthStats.hasTimers(UidHealthStats.TIMERS_SYNCS)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_SYNCS); + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + } + return estimateCpuPowerByCpuStats(powerProfile, timeMs); + } + + /** + * @see com.android.internal.os.IdlePowerCalculator#IdlePowerCalculator + */ + @RequiresApi(api = Build.VERSION_CODES.N) + public static double calcIdlePower(PowerProfile powerProfile, HealthStats healthStats) { + long batteryRealtimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); + long batteryUptimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_UPTIME_BATTERY_MS); + double suspendPowerMah = new UsageBasedPowerEstimator(powerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND)).calculatePower(batteryRealtimeMs); + double idlePowerMah = new UsageBasedPowerEstimator(powerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE)).calculatePower(batteryUptimeMs); + return suspendPowerMah + idlePowerMah; + } } From 07e4553f7039e2296b0da9bd949f3d5e37a2d513 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 20 Jul 2022 18:10:40 +0800 Subject: [PATCH 097/263] Update health stats feature --- .../stats/HealthStatsFeature.java | 101 +++++++++++------- 1 file changed, 65 insertions(+), 36 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index d93f4b850..47e203d4a 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -69,6 +69,8 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.audioPower = DigitEntry.of(HealthStatsHelper.calcAudioPower(powerProfile, healthStats)); snapshot.videoPower = DigitEntry.of(HealthStatsHelper.calcVideoPower(powerProfile, healthStats)); snapshot.screenPower = DigitEntry.of(HealthStatsHelper.calcScreenPower(powerProfile, healthStats)); + snapshot.systemServicePower = DigitEntry.of(HealthStatsHelper.calcSystemServicePower(powerProfile, healthStats)); + snapshot.idlePower = DigitEntry.of(HealthStatsHelper.calcIdlePower(powerProfile, healthStats)); double total = snapshot.cpuPower.get() + snapshot.wakelocksPower.get() @@ -81,7 +83,9 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { + snapshot.flashLightPower.get() + snapshot.audioPower.get() + snapshot.videoPower.get() - + snapshot.screenPower.get(); + + snapshot.screenPower.get() + + snapshot.systemServicePower.get() + + snapshot.idlePower.get(); snapshot.totalPower = DigitEntry.of(total); snapshot.radioActivePower = DigitEntry.of(HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats)); @@ -92,15 +96,8 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.cpuPowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_CPU_POWER_MAMS)); snapshot.cpuUsrTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS)); snapshot.cpuSysTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS)); - - if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL)) { - Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL); - long timeMs = 0; - for (TimerStat item : timers.values()) { - timeMs += item.getTime(); - } - snapshot.wakelocksPartialMs = DigitEntry.of(timeMs); - } + snapshot.realTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS)); + snapshot.upTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_UPTIME_BATTERY_MS)); snapshot.mobilePowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS)); snapshot.mobileRadioActiveMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE)); @@ -118,8 +115,15 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.blueToothRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS)); snapshot.blueToothTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS)); + if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL); + long timeMs = 0; + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + snapshot.wakelocksPartialMs = DigitEntry.of(timeMs); + } snapshot.gpsMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_GPS_SENSOR)); - if (healthStats.hasTimers(UidHealthStats.TIMERS_SENSORS)) { SensorManager sm = (SensorManager) mCore.getContext().getSystemService(Context.SENSOR_SERVICE); List sensorList = sm.getSensorList(Sensor.TYPE_ALL); @@ -152,18 +156,29 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { } snapshot.sensorsPowerMams = DigitEntry.of(sensorsPowerMams); } - snapshot.cameraMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_CAMERA)); snapshot.flashLightMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_FLASHLIGHT)); snapshot.audioMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_AUDIO)); snapshot.videoMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_VIDEO)); - - { - long totalTimeMs = HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); - long screenOffTimeMs = HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS); - long screenOnTimeMs = totalTimeMs - screenOffTimeMs; - snapshot.screenOnMs = DigitEntry.of(screenOnTimeMs); + if (healthStats.hasTimers(UidHealthStats.TIMERS_JOBS)) { + long timeMs = 0; + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_JOBS); + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + snapshot.jobsMs = DigitEntry.of(timeMs); + } + if (healthStats.hasTimers(UidHealthStats.TIMERS_SYNCS)) { + long timeMs = 0; + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_SYNCS); + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + snapshot.syncMs = DigitEntry.of(timeMs); } + + snapshot.topAppMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_TOP_MS)); + snapshot.fgActivityMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_FOREGROUND_ACTIVITY)); } return snapshot; } @@ -173,11 +188,9 @@ public static class HealthStatsSnapshot extends Snapshot { public HealthStats healthStats; // Estimated Powers - public DigitEntry totalPower = DigitEntry.of(0D); public DigitEntry cpuPower = DigitEntry.of(0D); public DigitEntry wakelocksPower = DigitEntry.of(0D); public DigitEntry mobilePower = DigitEntry.of(0D); - public DigitEntry radioActivePower = DigitEntry.of(0D); public DigitEntry wifiPower = DigitEntry.of(0D); public DigitEntry blueToothPower = DigitEntry.of(0D); public DigitEntry gpsPower = DigitEntry.of(0D); @@ -187,19 +200,19 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry audioPower = DigitEntry.of(0D); public DigitEntry videoPower = DigitEntry.of(0D); public DigitEntry screenPower = DigitEntry.of(0D); + public DigitEntry systemServicePower = DigitEntry.of(0D); + public DigitEntry idlePower = DigitEntry.of(0D); + + public DigitEntry totalPower = DigitEntry.of(0D); + public DigitEntry radioActivePower = DigitEntry.of(0D); // Meta Data: // CPU public DigitEntry cpuPowerMams = DigitEntry.of(0L); public DigitEntry cpuUsrTimeMs = DigitEntry.of(0L); public DigitEntry cpuSysTimeMs = DigitEntry.of(0L); - - // SystemService & Sensors - public DigitEntry wakelocksPartialMs = DigitEntry.of(0L); - public DigitEntry gpsMs = DigitEntry.of(0L); - public DigitEntry sensorsPowerMams = DigitEntry.of(0L); - public DigitEntry cameraMs = DigitEntry.of(0L); - public DigitEntry flashLightMs = DigitEntry.of(0L); + public DigitEntry realTimeMs = DigitEntry.of(0L); + public DigitEntry upTimeMs = DigitEntry.of(0L); // Network public DigitEntry mobilePowerMams = DigitEntry.of(0L); @@ -218,11 +231,20 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry blueToothRxMs = DigitEntry.of(0L); public DigitEntry blueToothTxMs = DigitEntry.of(0L); - // Media & Hardware + // SystemService & Media + public DigitEntry wakelocksPartialMs = DigitEntry.of(0L); + public DigitEntry gpsMs = DigitEntry.of(0L); + public DigitEntry sensorsPowerMams = DigitEntry.of(0L); + public DigitEntry cameraMs = DigitEntry.of(0L); + public DigitEntry flashLightMs = DigitEntry.of(0L); public DigitEntry audioMs = DigitEntry.of(0L); public DigitEntry videoMs = DigitEntry.of(0L); - public DigitEntry screenOnMs = DigitEntry.of(0L); + public DigitEntry jobsMs = DigitEntry.of(0L); + public DigitEntry syncMs = DigitEntry.of(0L); + // Screen + public DigitEntry topAppMs = DigitEntry.of(0L); + public DigitEntry fgActivityMs = DigitEntry.of(0L); @Override public Delta diff(HealthStatsSnapshot bgn) { @@ -242,6 +264,8 @@ protected HealthStatsSnapshot computeDelta() { delta.audioPower = Differ.DigitDiffer.globalDiff(bgn.audioPower, end.audioPower); delta.videoPower = Differ.DigitDiffer.globalDiff(bgn.videoPower, end.videoPower); delta.screenPower = Differ.DigitDiffer.globalDiff(bgn.screenPower, end.screenPower); + delta.systemServicePower = Differ.DigitDiffer.globalDiff(bgn.systemServicePower, end.systemServicePower); + delta.idlePower = Differ.DigitDiffer.globalDiff(bgn.idlePower, end.idlePower); delta.totalPower = Differ.DigitDiffer.globalDiff(bgn.totalPower, end.totalPower); delta.radioActivePower = Differ.DigitDiffer.globalDiff(bgn.radioActivePower, end.radioActivePower); @@ -249,12 +273,8 @@ protected HealthStatsSnapshot computeDelta() { delta.cpuPowerMams = Differ.DigitDiffer.globalDiff(bgn.cpuPowerMams, end.cpuPowerMams); delta.cpuUsrTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuUsrTimeMs, end.cpuUsrTimeMs); delta.cpuSysTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuSysTimeMs, end.cpuSysTimeMs); - - delta.wakelocksPartialMs = Differ.DigitDiffer.globalDiff(bgn.wakelocksPartialMs, end.wakelocksPartialMs); - delta.gpsMs = Differ.DigitDiffer.globalDiff(bgn.gpsMs, end.gpsMs); - delta.sensorsPowerMams = Differ.DigitDiffer.globalDiff(bgn.sensorsPowerMams, end.sensorsPowerMams); - delta.cameraMs = Differ.DigitDiffer.globalDiff(bgn.cameraMs, end.cameraMs); - delta.flashLightMs = Differ.DigitDiffer.globalDiff(bgn.flashLightMs, end.flashLightMs); + delta.realTimeMs = Differ.DigitDiffer.globalDiff(bgn.realTimeMs, end.realTimeMs); + delta.upTimeMs = Differ.DigitDiffer.globalDiff(bgn.upTimeMs, end.upTimeMs); delta.mobilePowerMams = Differ.DigitDiffer.globalDiff(bgn.mobilePowerMams, end.mobilePowerMams); delta.mobileRadioActiveMs = Differ.DigitDiffer.globalDiff(bgn.mobileRadioActiveMs, end.mobileRadioActiveMs); @@ -272,9 +292,18 @@ protected HealthStatsSnapshot computeDelta() { delta.blueToothRxMs = Differ.DigitDiffer.globalDiff(bgn.blueToothRxMs, end.blueToothRxMs); delta.blueToothTxMs = Differ.DigitDiffer.globalDiff(bgn.blueToothTxMs, end.blueToothTxMs); + delta.wakelocksPartialMs = Differ.DigitDiffer.globalDiff(bgn.wakelocksPartialMs, end.wakelocksPartialMs); + delta.gpsMs = Differ.DigitDiffer.globalDiff(bgn.gpsMs, end.gpsMs); + delta.sensorsPowerMams = Differ.DigitDiffer.globalDiff(bgn.sensorsPowerMams, end.sensorsPowerMams); + delta.cameraMs = Differ.DigitDiffer.globalDiff(bgn.cameraMs, end.cameraMs); + delta.flashLightMs = Differ.DigitDiffer.globalDiff(bgn.flashLightMs, end.flashLightMs); delta.audioMs = Differ.DigitDiffer.globalDiff(bgn.audioMs, end.audioMs); delta.videoMs = Differ.DigitDiffer.globalDiff(bgn.videoMs, end.videoMs); - delta.screenOnMs = Differ.DigitDiffer.globalDiff(bgn.screenOnMs, end.screenOnMs); + delta.jobsMs = Differ.DigitDiffer.globalDiff(bgn.jobsMs, end.jobsMs); + delta.syncMs = Differ.DigitDiffer.globalDiff(bgn.syncMs, end.syncMs); + + delta.topAppMs = Differ.DigitDiffer.globalDiff(bgn.topAppMs, end.topAppMs); + delta.fgActivityMs = Differ.DigitDiffer.globalDiff(bgn.fgActivityMs, end.fgActivityMs); return delta; } }; From 34129bdd7d3c50583614357ce4763cda734a5d88 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 20 Jul 2022 19:51:26 +0800 Subject: [PATCH 098/263] Add power profiler avg uni --- .../batterycanary/stats/HealthStatsTest.java | 22 +++++++++++ .../stats/HealthStatsHelper.java | 39 ++++++++++--------- .../batterycanary/utils/PowerProfile.java | 15 +++++++ 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 3d40b8cff..53645c650 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -189,6 +189,28 @@ public void testLiterateStats() { } } + @Test + public void getGetArrayItemAvgPower() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + for (String key : PowerProfile.getPowerItemMap().keySet()) { + Assert.assertEquals(powerProfile.getAveragePower(key), powerProfile.getAveragePowerUni(key), 0d); + } + + for (String key : PowerProfile.getPowerArrayMap().keySet()) { + Assert.assertEquals(powerProfile.getAveragePower(key, 0), powerProfile.getAveragePower(key), 0d); + + double sum = 0; + int num = powerProfile.getNumElements(key); + for (int i = 0; i < num; i++) { + sum += powerProfile.getAveragePower(key, i); + } + Assert.assertEquals(sum / num, powerProfile.getAveragePowerUni(key), 0d); + } + } + @Test public void testEstimateCpuPower() throws IOException { PowerProfile powerProfile = PowerProfile.init(mContext); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 5da046b09..0571111f6 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -188,7 +188,7 @@ public static double calcWakelocksPower(PowerProfile powerProfile, HealthStats h for (TimerStat item : timers.values()) { timeMs += item.getTime(); } - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_CPU_IDLE); power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } return power; @@ -200,7 +200,7 @@ public static double calcWakelocksPower(PowerProfile powerProfile, HealthStats h @RequiresApi(api = Build.VERSION_CODES.N) public static double calcMobilePowerByRadioActive(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_RADIO_ACTIVE); return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -216,17 +216,17 @@ public static double calcMobilePower(PowerProfile powerProfile, HealthStats heal if (power == 0) { { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_IDLE); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_MS); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_RX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_MS); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_TX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -245,20 +245,21 @@ public static double calcWifiPower(PowerProfile powerProfile, HealthStats health MatrixLog.i(TAG, "estimate WIFI by mams"); } if (power == 0) { + // calc from controller { - double wifiIdlePower = powerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE); + double wifiIdlePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_IDLE); long idleMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_IDLE_MS); UsageBasedPowerEstimator etmWifiIdlePower = new UsageBasedPowerEstimator(wifiIdlePower); power += etmWifiIdlePower.calculatePower(idleMs); } { - double wifiRxPower = powerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX); + double wifiRxPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_RX); UsageBasedPowerEstimator etmWifiRxPower = new UsageBasedPowerEstimator(wifiRxPower); long rxMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_MS); power += etmWifiRxPower.calculatePower(rxMs); } { - double wifiTxPower = powerProfile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX); + double wifiTxPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_TX); long txMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_MS); UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiTxPower); power += etmWifiTxPower.calculatePower(txMs); @@ -281,17 +282,17 @@ public static double calcBlueToothPower(PowerProfile powerProfile, HealthStats h if (power == 0) { { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } } @@ -306,7 +307,7 @@ public static double calcGpsPower(PowerProfile powerProfile, HealthStats healthS long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_GPS_SENSOR); double powerMa = 0; if (timeMs > 0) { - powerMa = powerProfile.getAveragePower(PowerProfile.POWER_GPS_ON); + powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_GPS_ON); if (powerMa <= 0) { int num = powerProfile.getNumElements(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED); double sumMa = 0; @@ -364,7 +365,7 @@ public static double calcSensorsPower(Context context, HealthStats healthStats) @RequiresApi(api = Build.VERSION_CODES.N) public static double calcCameraPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_CAMERA); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_CAMERA); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_CAMERA); return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -374,7 +375,7 @@ public static double calcCameraPower(PowerProfile powerProfile, HealthStats heal @RequiresApi(api = Build.VERSION_CODES.N) public static double calcFlashLightPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_FLASHLIGHT); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_FLASHLIGHT); return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -384,7 +385,7 @@ public static double calcFlashLightPower(PowerProfile powerProfile, HealthStats @RequiresApi(api = Build.VERSION_CODES.N) public static double calcAudioPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_AUDIO); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_AUDIO); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_AUDIO); return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -394,7 +395,7 @@ public static double calcAudioPower(PowerProfile powerProfile, HealthStats healt @RequiresApi(api = Build.VERSION_CODES.N) public static double calcVideoPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_VIDEO); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_VIDEO); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_VIDEO); return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -406,7 +407,7 @@ public static double calcScreenPower(PowerProfile powerProfile, HealthStats heal long topAppMs = getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_TOP_MS); long fgActivityMs = getTimerTime(healthStats, UidHealthStats.TIMER_FOREGROUND_ACTIVITY); long screenOnTimeMs = Math.min(topAppMs, fgActivityMs); - double powerMa = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_SCREEN_ON); return new UsageBasedPowerEstimator(powerMa).calculatePower(screenOnTimeMs); } @@ -438,8 +439,8 @@ public static double calcSystemServicePower(PowerProfile powerProfile, HealthSta public static double calcIdlePower(PowerProfile powerProfile, HealthStats healthStats) { long batteryRealtimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS); long batteryUptimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_UPTIME_BATTERY_MS); - double suspendPowerMah = new UsageBasedPowerEstimator(powerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND)).calculatePower(batteryRealtimeMs); - double idlePowerMah = new UsageBasedPowerEstimator(powerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE)).calculatePower(batteryUptimeMs); + double suspendPowerMah = new UsageBasedPowerEstimator(powerProfile.getAveragePowerUni(PowerProfile.POWER_CPU_SUSPEND)).calculatePower(batteryRealtimeMs); + double idlePowerMah = new UsageBasedPowerEstimator(powerProfile.getAveragePowerUni(PowerProfile.POWER_CPU_IDLE)).calculatePower(batteryUptimeMs); return suspendPowerMah + idlePowerMah; } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java index 7993d2f62..51b33bd47 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java @@ -67,6 +67,21 @@ public boolean isSupported() { } } + public double getAveragePowerUni(String type) { + int num = getNumElements(type); + if (num > 0) { + // Array + double sum = 0; + for (int i = 0; i < num; i++) { + sum += getAveragePower(type, i); + } + return sum / num; + } else { + // Item + return getAveragePower(type); + } + } + public int getCpuCoreNum() { int cpuCoreNumInProfile = 0; for (int i = 0; i < getNumCpuClusters(); i++) { From 1766a11cc78a82278fa898c83f17c324e36e930f Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 20 Jul 2022 20:00:09 +0800 Subject: [PATCH 099/263] Update battery power calculator --- .../stats/HealthStatsHelper.java | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 0571111f6..b449539cf 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -201,6 +201,15 @@ public static double calcWakelocksPower(PowerProfile powerProfile, HealthStats h public static double calcMobilePowerByRadioActive(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE); double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_RADIO_ACTIVE); + if (powerMa <= 0) { + double sum = 0; + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); + int num = powerProfile.getNumElements(PowerProfile.POWER_MODEM_CONTROLLER_TX); + for (int i = 0; i < num; i++) { + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i); + } + powerMa = sum / (num + 1); + } return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } @@ -229,8 +238,6 @@ public static double calcMobilePower(PowerProfile powerProfile, HealthStats heal double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_TX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - - // FIXME: calc with packets } return power; } @@ -264,8 +271,27 @@ public static double calcWifiPower(PowerProfile powerProfile, HealthStats health UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiTxPower); power += etmWifiTxPower.calculatePower(txMs); } - - // FIXME: calc without wifi-controller + } + if (power == 0) { + // calc from packets + MatrixLog.i(TAG, "estimate WIFI by packets"); + { + final long wifiBps = 1000000; + final double averageWifiActivePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ACTIVE) / 3600; + double powerMaPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); + long packets = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS); + power += powerMaPerPacket * packets; + } + { + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ON); + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + { + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_SCAN); + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_WIFI_SCAN); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } } return power; } From 6473cad9d14bb7afe7519fd4a28a5876a085b6ec Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 21 Jul 2022 13:06:21 +0800 Subject: [PATCH 100/263] Update healthstats snapshot meta data --- .../stats/HealthStatsFeature.java | 96 ++++++++++++++++--- 1 file changed, 83 insertions(+), 13 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 47e203d4a..d7f951ab3 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -6,6 +6,7 @@ import android.hardware.SensorManager; import android.os.Build; import android.os.health.HealthStats; +import android.os.health.PidHealthStats; import android.os.health.TimerStat; import android.os.health.UidHealthStats; @@ -98,6 +99,8 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.cpuSysTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS)); snapshot.realTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS)); snapshot.upTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_UPTIME_BATTERY_MS)); + snapshot.offRealTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS)); + snapshot.offUpTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS)); snapshot.mobilePowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS)); snapshot.mobileRadioActiveMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE)); @@ -109,19 +112,57 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.wifiIdleMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_IDLE_MS)); snapshot.wifiRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_MS)); snapshot.wifiTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_MS)); + snapshot.wifiRxBytes = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_BYTES)); + snapshot.wifiTxBytes = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_BYTES)); snapshot.blueToothPowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS)); snapshot.blueToothIdleMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS)); snapshot.blueToothRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS)); snapshot.blueToothTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS)); - if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL)) { - Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL); - long timeMs = 0; - for (TimerStat item : timers.values()) { - timeMs += item.getTime(); + { + if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_PARTIAL); + long timeMs = 0; + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + snapshot.wakelocksPartialMs = DigitEntry.of(timeMs); + } + if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_FULL)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_FULL); + long timeMs = 0; + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + snapshot.wakelocksFullMs = DigitEntry.of(timeMs); + } + if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_WINDOW)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_WINDOW); + long timeMs = 0; + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + snapshot.wakelocksWindowMs = DigitEntry.of(timeMs); + } + if (healthStats.hasTimers(UidHealthStats.TIMERS_WAKELOCKS_DRAW)) { + Map timers = healthStats.getTimers(UidHealthStats.TIMERS_WAKELOCKS_DRAW); + long timeMs = 0; + for (TimerStat item : timers.values()) { + timeMs += item.getTime(); + } + snapshot.wakelocksDrawMs = DigitEntry.of(timeMs); + } + if (healthStats.hasStats(UidHealthStats.STATS_PIDS)) { + long sum = 0; + Map pidStats = healthStats.getStats(UidHealthStats.STATS_PIDS); + for (HealthStats item : pidStats.values()) { + if (item.hasMeasurement(PidHealthStats.MEASUREMENT_WAKE_SUM_MS)) { + sum += item.getMeasurement(PidHealthStats.MEASUREMENT_WAKE_SUM_MS); + } + } + snapshot.wakelocksPidSum = DigitEntry.of(sum); } - snapshot.wakelocksPartialMs = DigitEntry.of(timeMs); } snapshot.gpsMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_GPS_SENSOR)); if (healthStats.hasTimers(UidHealthStats.TIMERS_SENSORS)) { @@ -177,8 +218,13 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.syncMs = DigitEntry.of(timeMs); } - snapshot.topAppMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_TOP_MS)); - snapshot.fgActivityMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_FOREGROUND_ACTIVITY)); + snapshot.fgActMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_FOREGROUND_ACTIVITY)); + snapshot.procTopAppMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_TOP_MS)); + snapshot.procTopSleepMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_TOP_SLEEPING_MS)); + snapshot.procFgMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_FOREGROUND_MS)); + snapshot.procFgSrvMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS)); + snapshot.procBgMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_BACKGROUND_MS)); + snapshot.procCacheMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_CACHED_MS)); } return snapshot; } @@ -213,6 +259,8 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry cpuSysTimeMs = DigitEntry.of(0L); public DigitEntry realTimeMs = DigitEntry.of(0L); public DigitEntry upTimeMs = DigitEntry.of(0L); + public DigitEntry offRealTimeMs = DigitEntry.of(0L); + public DigitEntry offUpTimeMs = DigitEntry.of(0L); // Network public DigitEntry mobilePowerMams = DigitEntry.of(0L); @@ -225,6 +273,8 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry wifiIdleMs = DigitEntry.of(0L); public DigitEntry wifiRxMs = DigitEntry.of(0L); public DigitEntry wifiTxMs = DigitEntry.of(0L); + public DigitEntry wifiRxBytes = DigitEntry.of(0L); + public DigitEntry wifiTxBytes = DigitEntry.of(0L); public DigitEntry blueToothPowerMams = DigitEntry.of(0L); public DigitEntry blueToothIdleMs = DigitEntry.of(0L); @@ -233,6 +283,10 @@ public static class HealthStatsSnapshot extends Snapshot { // SystemService & Media public DigitEntry wakelocksPartialMs = DigitEntry.of(0L); + public DigitEntry wakelocksFullMs = DigitEntry.of(0L); + public DigitEntry wakelocksWindowMs = DigitEntry.of(0L); + public DigitEntry wakelocksDrawMs = DigitEntry.of(0L); + public DigitEntry wakelocksPidSum = DigitEntry.of(0L); public DigitEntry gpsMs = DigitEntry.of(0L); public DigitEntry sensorsPowerMams = DigitEntry.of(0L); public DigitEntry cameraMs = DigitEntry.of(0L); @@ -242,9 +296,14 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry jobsMs = DigitEntry.of(0L); public DigitEntry syncMs = DigitEntry.of(0L); - // Screen - public DigitEntry topAppMs = DigitEntry.of(0L); - public DigitEntry fgActivityMs = DigitEntry.of(0L); + // Foreground + public DigitEntry fgActMs = DigitEntry.of(0L); + public DigitEntry procTopAppMs = DigitEntry.of(0L); + public DigitEntry procTopSleepMs = DigitEntry.of(0L); + public DigitEntry procFgMs = DigitEntry.of(0L); + public DigitEntry procFgSrvMs = DigitEntry.of(0L); + public DigitEntry procBgMs = DigitEntry.of(0L); + public DigitEntry procCacheMs = DigitEntry.of(0L); @Override public Delta diff(HealthStatsSnapshot bgn) { @@ -286,6 +345,8 @@ protected HealthStatsSnapshot computeDelta() { delta.wifiIdleMs = Differ.DigitDiffer.globalDiff(bgn.wifiIdleMs, end.wifiIdleMs); delta.wifiRxMs = Differ.DigitDiffer.globalDiff(bgn.wifiRxMs, end.wifiRxMs); delta.wifiTxMs = Differ.DigitDiffer.globalDiff(bgn.wifiTxMs, end.wifiTxMs); + delta.wifiRxBytes = Differ.DigitDiffer.globalDiff(bgn.wifiRxBytes, end.wifiRxBytes); + delta.wifiTxBytes = Differ.DigitDiffer.globalDiff(bgn.wifiTxBytes, end.wifiTxBytes); delta.blueToothPowerMams = Differ.DigitDiffer.globalDiff(bgn.blueToothPowerMams, end.blueToothPowerMams); delta.blueToothIdleMs = Differ.DigitDiffer.globalDiff(bgn.blueToothIdleMs, end.blueToothIdleMs); @@ -293,6 +354,10 @@ protected HealthStatsSnapshot computeDelta() { delta.blueToothTxMs = Differ.DigitDiffer.globalDiff(bgn.blueToothTxMs, end.blueToothTxMs); delta.wakelocksPartialMs = Differ.DigitDiffer.globalDiff(bgn.wakelocksPartialMs, end.wakelocksPartialMs); + delta.wakelocksFullMs = Differ.DigitDiffer.globalDiff(bgn.wakelocksFullMs, end.wakelocksFullMs); + delta.wakelocksWindowMs = Differ.DigitDiffer.globalDiff(bgn.wakelocksWindowMs, end.wakelocksWindowMs); + delta.wakelocksDrawMs = Differ.DigitDiffer.globalDiff(bgn.wakelocksDrawMs, end.wakelocksDrawMs); + delta.wakelocksPidSum = Differ.DigitDiffer.globalDiff(bgn.wakelocksPidSum, end.wakelocksPidSum); delta.gpsMs = Differ.DigitDiffer.globalDiff(bgn.gpsMs, end.gpsMs); delta.sensorsPowerMams = Differ.DigitDiffer.globalDiff(bgn.sensorsPowerMams, end.sensorsPowerMams); delta.cameraMs = Differ.DigitDiffer.globalDiff(bgn.cameraMs, end.cameraMs); @@ -302,8 +367,13 @@ protected HealthStatsSnapshot computeDelta() { delta.jobsMs = Differ.DigitDiffer.globalDiff(bgn.jobsMs, end.jobsMs); delta.syncMs = Differ.DigitDiffer.globalDiff(bgn.syncMs, end.syncMs); - delta.topAppMs = Differ.DigitDiffer.globalDiff(bgn.topAppMs, end.topAppMs); - delta.fgActivityMs = Differ.DigitDiffer.globalDiff(bgn.fgActivityMs, end.fgActivityMs); + delta.fgActMs = Differ.DigitDiffer.globalDiff(bgn.fgActMs, end.fgActMs); + delta.procTopAppMs = Differ.DigitDiffer.globalDiff(bgn.procTopAppMs, end.procTopAppMs); + delta.procTopSleepMs = Differ.DigitDiffer.globalDiff(bgn.procTopSleepMs, end.procTopSleepMs); + delta.procFgMs = Differ.DigitDiffer.globalDiff(bgn.procFgMs, end.procFgMs); + delta.procFgSrvMs = Differ.DigitDiffer.globalDiff(bgn.procFgSrvMs, end.procFgSrvMs); + delta.procBgMs = Differ.DigitDiffer.globalDiff(bgn.procBgMs, end.procBgMs); + delta.procCacheMs = Differ.DigitDiffer.globalDiff(bgn.procCacheMs, end.procCacheMs); return delta; } }; From c6710f90a2b834d0e0fb1362ffcccbebafd11672 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 21 Jul 2022 21:26:30 +0800 Subject: [PATCH 101/263] Update battery event delegate with full charged --- .../batterycanary/BatteryEventDelegate.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java index 810e8c6b0..60cca6c3a 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java @@ -155,6 +155,17 @@ public void onReceive(Context context, final Intent intent) { // Received 'ACTION_BATTERY_CHANGED' frequently, // should be frequency-controlled & handled with worker thread if (mCore != null) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + if (status == BatteryManager.BATTERY_STATUS_FULL) { + mCore.getHandler().post(new Runnable() { + @Override + public void run() { + onBatteryFullCharged(); + } + }); + return; + } + boolean limited = false; long currMs = System.currentTimeMillis(); if (mLastBatteryChangedHandleMs > 0 && currMs - mLastBatteryChangedHandleMs < ONE_MIN) { @@ -343,6 +354,19 @@ public void run() { } } + private void onBatteryFullCharged() { + if (Looper.myLooper() == Looper.getMainLooper()) { + dispatchBatteryFullCharged(); + } else { + mUiHandler.post(new Runnable() { + @Override + public void run() { + dispatchBatteryFullCharged(); + } + }); + } + } + private void onBatteryTemperatureChanged(final int temp) { if (Looper.myLooper() == Looper.getMainLooper()) { dispatchBatteryTemperatureChanged(temp); @@ -423,6 +447,21 @@ void dispatchBatteryPowerChanged(int pct) { } } + @VisibleForTesting + void dispatchBatteryFullCharged() { + MatrixLog.i(TAG, "dispatchBatteryFullCharged"); + synchronized (mListenerList) { + BatteryState batteryState = currentState(); + for (Listener item : mListenerList) { + if (item instanceof Listener.ExListener) { + if (((Listener.ExListener) item).onBatteryFullCharged(batteryState)) { + removeListener(item); + } + } + } + } + } + @VisibleForTesting void dispatchBatteryTemperatureChanged(int temperature) { MatrixLog.i(TAG, "onBatteryTemperatureChanged >> " + (temperature / 10f) + "°C"); @@ -599,6 +638,15 @@ interface ExListener extends Listener { @UiThread boolean onBatteryPowerChanged(BatteryState batteryState, int levelPct); + /** + * On battery power full charged. + * + * @param batteryState {@link BatteryState} + * @return return true if your listening is done, thus we remove your listener + */ + @UiThread + boolean onBatteryFullCharged(BatteryState batteryState); + /** * On battery power low or ok. * @@ -644,6 +692,11 @@ public boolean onBatteryPowerChanged(BatteryState batteryState, int levelPct) { return !mKeepAlive; } + @Override + public boolean onBatteryFullCharged(BatteryState batteryState) { + return !mKeepAlive; + } + @Override public boolean onBatteryStateChanged(BatteryState batteryState, boolean isLowBattery) { return !mKeepAlive; From b8cd5c312923c39af8bf5a2af9085c4956442855 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 25 Jul 2022 16:07:32 +0800 Subject: [PATCH 102/263] Update mobile power calculator --- .../batterycanary/stats/HealthStatsTest.java | 5 +-- .../stats/HealthStatsFeature.java | 3 -- .../stats/HealthStatsHelper.java | 40 ++++++++++--------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 53645c650..3f9f6c848 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -352,9 +352,6 @@ public void testEstimateMobileRadioPower() throws IOException { } Assert.assertTrue(powerMahByRadio >= 0); - double calcPower = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats); - Assert.assertEquals(powerMahByRadio, calcPower, 1d); - double powerMahByTime = 0; if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS)) { long timeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); @@ -373,7 +370,7 @@ public void testEstimateMobileRadioPower() throws IOException { } Assert.assertTrue(powerMahByTime >= 0); - calcPower = HealthStatsHelper.calcMobilePower(powerProfile, healthStats); + double calcPower = HealthStatsHelper.calcMobilePower(powerProfile, healthStats); Assert.assertEquals(powerMahByTime, calcPower, 1d); } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index d7f951ab3..9aae22c69 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -89,7 +89,6 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { + snapshot.idlePower.get(); snapshot.totalPower = DigitEntry.of(total); - snapshot.radioActivePower = DigitEntry.of(HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats)); } } @@ -250,7 +249,6 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry idlePower = DigitEntry.of(0D); public DigitEntry totalPower = DigitEntry.of(0D); - public DigitEntry radioActivePower = DigitEntry.of(0D); // Meta Data: // CPU @@ -327,7 +325,6 @@ protected HealthStatsSnapshot computeDelta() { delta.idlePower = Differ.DigitDiffer.globalDiff(bgn.idlePower, end.idlePower); delta.totalPower = Differ.DigitDiffer.globalDiff(bgn.totalPower, end.totalPower); - delta.radioActivePower = Differ.DigitDiffer.globalDiff(bgn.radioActivePower, end.radioActivePower); delta.cpuPowerMams = Differ.DigitDiffer.globalDiff(bgn.cpuPowerMams, end.cpuPowerMams); delta.cpuUsrTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuUsrTimeMs, end.cpuUsrTimeMs); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index b449539cf..c29306529 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -194,25 +194,6 @@ public static double calcWakelocksPower(PowerProfile powerProfile, HealthStats h return power; } - /** - * @see com.android.internal.os.MobileRadioPowerCalculator - */ - @RequiresApi(api = Build.VERSION_CODES.N) - public static double calcMobilePowerByRadioActive(PowerProfile powerProfile, HealthStats healthStats) { - long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE); - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_RADIO_ACTIVE); - if (powerMa <= 0) { - double sum = 0; - sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); - int num = powerProfile.getNumElements(PowerProfile.POWER_MODEM_CONTROLLER_TX); - for (int i = 0; i < num; i++) { - sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i); - } - powerMa = sum / (num + 1); - } - return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - /** * @see com.android.internal.os.MobileRadioPowerCalculator */ @@ -223,6 +204,27 @@ public static double calcMobilePower(PowerProfile powerProfile, HealthStats heal MatrixLog.i(TAG, "estimate Mobile by mams"); } if (power == 0) { + // calc from radio active + // for some aosp mistakes, radio active timer was given in time unit us: + // https://cs.android.com/android/_/android/platform/frameworks/base/+/bee44ae8e5da109cd8273a057b566dc6925d6a71 + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE) / 1000; + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_RADIO_ACTIVE); + if (powerMa <= 0) { + double sum = 0; + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); + int num = powerProfile.getNumElements(PowerProfile.POWER_MODEM_CONTROLLER_TX); + for (int i = 0; i < num; i++) { + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i); + } + powerMa = sum / (num + 1); + } + power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + if (power > 0) { + MatrixLog.i(TAG, "estimate Mobile by radioActive"); + } + } + if (power == 0) { + // calc from controller { long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_IDLE); From d6d34116cd8b088cb0ae1e8539389f57ccc3200a Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 26 Jul 2022 16:56:20 +0800 Subject: [PATCH 103/263] rename module matrix-jectl -> matrix-mallctl --- .../{matrix-jectl => matrix-mallctl}/CMakeLists.txt | 0 .../{matrix-jectl => matrix-mallctl}/build.gradle | 0 .../{matrix-jectl => matrix-mallctl}/consumer-rules.pro | 0 .../{matrix-jectl => matrix-mallctl}/gradle.properties | 0 .../{matrix-jectl => matrix-mallctl}/proguard-rules.pro | 0 .../java/com/tencent/matrix/jectl/ExampleInstrumentedTest.java | 0 .../src/main/AndroidManifest.xml | 0 .../src/main/cpp/jectl/JeCtl.cpp | 0 .../src/main/cpp/jectl/JeHooks.cpp | 0 .../src/main/cpp/jectl/JeHooks.h | 0 .../{matrix-jectl => matrix-mallctl}/src/main/cpp/jectl/JeLog.h | 0 .../src/main/java/com/tencent/matrix/jectl/JeCtl.java | 0 .../src/test/java/com/tencent/matrix/jectl/ExampleUnitTest.java | 0 matrix/matrix-android/settings.gradle | 2 +- 14 files changed, 1 insertion(+), 1 deletion(-) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/CMakeLists.txt (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/build.gradle (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/consumer-rules.pro (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/gradle.properties (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/proguard-rules.pro (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/src/androidTest/java/com/tencent/matrix/jectl/ExampleInstrumentedTest.java (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/src/main/AndroidManifest.xml (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/src/main/cpp/jectl/JeCtl.cpp (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/src/main/cpp/jectl/JeHooks.cpp (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/src/main/cpp/jectl/JeHooks.h (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/src/main/cpp/jectl/JeLog.h (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/src/main/java/com/tencent/matrix/jectl/JeCtl.java (100%) rename matrix/matrix-android/{matrix-jectl => matrix-mallctl}/src/test/java/com/tencent/matrix/jectl/ExampleUnitTest.java (100%) diff --git a/matrix/matrix-android/matrix-jectl/CMakeLists.txt b/matrix/matrix-android/matrix-mallctl/CMakeLists.txt similarity index 100% rename from matrix/matrix-android/matrix-jectl/CMakeLists.txt rename to matrix/matrix-android/matrix-mallctl/CMakeLists.txt diff --git a/matrix/matrix-android/matrix-jectl/build.gradle b/matrix/matrix-android/matrix-mallctl/build.gradle similarity index 100% rename from matrix/matrix-android/matrix-jectl/build.gradle rename to matrix/matrix-android/matrix-mallctl/build.gradle diff --git a/matrix/matrix-android/matrix-jectl/consumer-rules.pro b/matrix/matrix-android/matrix-mallctl/consumer-rules.pro similarity index 100% rename from matrix/matrix-android/matrix-jectl/consumer-rules.pro rename to matrix/matrix-android/matrix-mallctl/consumer-rules.pro diff --git a/matrix/matrix-android/matrix-jectl/gradle.properties b/matrix/matrix-android/matrix-mallctl/gradle.properties similarity index 100% rename from matrix/matrix-android/matrix-jectl/gradle.properties rename to matrix/matrix-android/matrix-mallctl/gradle.properties diff --git a/matrix/matrix-android/matrix-jectl/proguard-rules.pro b/matrix/matrix-android/matrix-mallctl/proguard-rules.pro similarity index 100% rename from matrix/matrix-android/matrix-jectl/proguard-rules.pro rename to matrix/matrix-android/matrix-mallctl/proguard-rules.pro diff --git a/matrix/matrix-android/matrix-jectl/src/androidTest/java/com/tencent/matrix/jectl/ExampleInstrumentedTest.java b/matrix/matrix-android/matrix-mallctl/src/androidTest/java/com/tencent/matrix/jectl/ExampleInstrumentedTest.java similarity index 100% rename from matrix/matrix-android/matrix-jectl/src/androidTest/java/com/tencent/matrix/jectl/ExampleInstrumentedTest.java rename to matrix/matrix-android/matrix-mallctl/src/androidTest/java/com/tencent/matrix/jectl/ExampleInstrumentedTest.java diff --git a/matrix/matrix-android/matrix-jectl/src/main/AndroidManifest.xml b/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml similarity index 100% rename from matrix/matrix-android/matrix-jectl/src/main/AndroidManifest.xml rename to matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml diff --git a/matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/JeCtl.cpp b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp similarity index 100% rename from matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/JeCtl.cpp rename to matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp diff --git a/matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/JeHooks.cpp b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.cpp similarity index 100% rename from matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/JeHooks.cpp rename to matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.cpp diff --git a/matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/JeHooks.h b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.h similarity index 100% rename from matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/JeHooks.h rename to matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.h diff --git a/matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/JeLog.h b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeLog.h similarity index 100% rename from matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/JeLog.h rename to matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeLog.h diff --git a/matrix/matrix-android/matrix-jectl/src/main/java/com/tencent/matrix/jectl/JeCtl.java b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/jectl/JeCtl.java similarity index 100% rename from matrix/matrix-android/matrix-jectl/src/main/java/com/tencent/matrix/jectl/JeCtl.java rename to matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/jectl/JeCtl.java diff --git a/matrix/matrix-android/matrix-jectl/src/test/java/com/tencent/matrix/jectl/ExampleUnitTest.java b/matrix/matrix-android/matrix-mallctl/src/test/java/com/tencent/matrix/jectl/ExampleUnitTest.java similarity index 100% rename from matrix/matrix-android/matrix-jectl/src/test/java/com/tencent/matrix/jectl/ExampleUnitTest.java rename to matrix/matrix-android/matrix-mallctl/src/test/java/com/tencent/matrix/jectl/ExampleUnitTest.java diff --git a/matrix/matrix-android/settings.gradle b/matrix/matrix-android/settings.gradle index 3204b7166..f4e73e4fc 100644 --- a/matrix/matrix-android/settings.gradle +++ b/matrix/matrix-android/settings.gradle @@ -24,7 +24,7 @@ include ':matrix-traffic' include ':matrix-backtrace' include ':matrix-hooks' include ':matrix-memguard' -include ':matrix-jectl' +include ':matrix-mallctl' include ':matrix-fd' // Benchmark From c029184027fd8216c8e02c620842844200ceb1ce Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 26 Jul 2022 17:32:44 +0800 Subject: [PATCH 104/263] mallctl: remove useless code --- .../matrix-mallctl/CMakeLists.txt | 2 +- .../src/main/AndroidManifest.xml | 2 +- .../src/main/cpp/jectl/JeCtl.cpp | 258 +----------------- .../src/main/cpp/jectl/JeHooks.cpp | 106 ------- .../src/main/cpp/jectl/JeHooks.h | 106 ------- .../java/com/tencent/matrix/jectl/JeCtl.java | 97 ------- .../com/tencent/matrix/mallctl/MallCtl.java | 56 ++++ 7 files changed, 60 insertions(+), 567 deletions(-) delete mode 100644 matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.cpp delete mode 100644 matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.h delete mode 100644 matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/jectl/JeCtl.java create mode 100644 matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java diff --git a/matrix/matrix-android/matrix-mallctl/CMakeLists.txt b/matrix/matrix-android/matrix-mallctl/CMakeLists.txt index 931537f6f..a2995de97 100644 --- a/matrix/matrix-android/matrix-mallctl/CMakeLists.txt +++ b/matrix/matrix-android/matrix-mallctl/CMakeLists.txt @@ -10,7 +10,7 @@ cmake_minimum_required(VERSION 3.4.1) # and CMake builds them for you. When you build your app, Gradle # automatically packages shared libraries with your APK. -set(TARGET matrix-jectl) +set(TARGET matrix-mallctl) set(SOURCE_DIR src/main/cpp) diff --git a/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml b/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml index 1ad0a915f..37af2b71f 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ + package="com.tencent.matrix.mallctl"> \ No newline at end of file diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp index d79cd10c1..e7e7f808a 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp +++ b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp @@ -25,18 +25,7 @@ #include #include "EnhanceDlsym.h" #include "JeLog.h" -#include "JeHooks.h" #include -//#include "internal/arena_structs_b.h" - -#define JECTL_OK 0 -#define ERR_INIT_FAILED 1 -#define ERR_VERSION 2 -#define ERR_64_BIT 3 -#define ERR_CTL 4 -#define ERR_ALLOC_FAILED 5 - -#define CACHELINE 64 #define TAG "Matrix.JeCtl" @@ -78,14 +67,6 @@ arena_extent_dalloc_large_prep_t arena_extent_dalloc_large_prep = nullptr; arena_extents_dirty_dalloc_t arena_extents_dirty_dalloc = nullptr; bool * p_je_opt_retain = nullptr; - -static inline bool end_with(std::string const &value, std::string const &ending) { - if (ending.size() > value.size()) { - return false; - } - return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); -} - static bool init() { handle = enhance::dlopen("libc.so", 0); @@ -163,67 +144,8 @@ static void flush_decay_purge() { mallctl("arena.1.purge", nullptr, nullptr, nullptr, 0); } -static void enable_dss() { - int err = 0; - - char *stat_dss; - size_t stat_dss_size = sizeof(char *); - mallctl("stats.arenas.0.dss", &stat_dss, &stat_dss_size, nullptr, 0); - LOGD(TAG, "stat_dss.0 = %s", stat_dss); - - mallctl("stats.arenas.1.dss", &stat_dss, &stat_dss_size, nullptr, 0); - LOGD(TAG, "stat_dss.1 = %s", stat_dss); - -// *opt_retain = false; - const char *setting = "primary"; - size_t setting_size = sizeof(const char); - char *old_setting; - size_t old_setting_size = sizeof(char *); - mallctl("arena.0.dss", &old_setting, &old_setting_size, &setting, sizeof(const char *)); - mallctl("arena.1.dss", &old_setting, &old_setting_size, &setting, 8); - - mallctl("stats.arenas.0.dss", &stat_dss, &stat_dss_size, nullptr, 0); - LOGD(TAG, "after stat_dss.0 = %s", stat_dss); - - mallctl("stats.arenas.1.dss", &stat_dss, &stat_dss_size, nullptr, 0); - LOGD(TAG, "after stat_dss.1 = %s", stat_dss); - - bool old_val; - size_t old_val_size = sizeof(bool); - bool new_val = false; - mallctl("thread.tcache.enabled", &old_val, &old_val_size, &new_val, sizeof(new_val)); - LOGD(TAG, "thread.tcache.enabled: %d", old_val); - mallctl("thread.tcache.enabled", &old_val, &old_val_size, nullptr, 0); - LOGD(TAG, "thread.tcache.enabled: %d", old_val); - - ssize_t dirty_ms; - size_t dirty_ms_size = sizeof(ssize_t); - ssize_t new_dirty_ms = 0; - mallctl("arena.0.dirty_decay_ms", &dirty_ms, &dirty_ms_size, &new_dirty_ms, sizeof(ssize_t)); - LOGD(TAG, "arena.0.dirty_decay_ms: %zu", dirty_ms); - mallctl("arena.0.dirty_decay_ms", &dirty_ms, &dirty_ms_size, nullptr, 0); - LOGD(TAG, "arena.0.dirty_decay_ms: %zu", dirty_ms); - - bool background; - size_t background_size = sizeof(bool); - bool new_background = true; - err = mallctl("background_thread", &background, &background_size, &new_background, - background_size); - LOGD(TAG, "background_thread = %d, err = %d", background, err); - err = mallctl("background_thread", &background, &background_size, - nullptr, 0); - LOGD(TAG, "background_thread = %d, err = %d", background, err); - - bool opt_background; - size_t opt_background_size = sizeof(bool); - mallctl("opt.background_thread", &opt_background, &opt_background_size, nullptr, 0); - LOGD(TAG, "opt.background_thread = %d", opt_background); - - -} - JNIEXPORT void JNICALL -Java_com_tencent_matrix_jectl_JeCtl_initNative(JNIEnv *env, jclass clazz) { +Java_com_tencent_matrix_mallctl_MallCtl_initNative(JNIEnv *env, jclass clazz) { #ifdef __LP64__ return ; #else @@ -233,169 +155,8 @@ Java_com_tencent_matrix_jectl_JeCtl_initNative(JNIEnv *env, jclass clazz) { #endif } -JNIEXPORT jint JNICALL -Java_com_tencent_matrix_jectl_JeCtl_compactNative(JNIEnv *env, jclass clazz) { - -#ifdef __LP64__ - return ERR_64_BIT; -#else - - if (!initialized) { - return ERR_INIT_FAILED; - } - assert(mallctl != nullptr); - - flush_decay_purge(); - - return JECTL_OK; -#endif -} - -static void call_alloc_large_in_arena1(size_t __size) { - // 延迟时机, 失败也不影响 arena0 的预分配 - auto tsd_tsd = (pthread_t *) enhance::dlsym(handle, "je_tsd_tsd"); - if (!tsd_tsd) { - LOGE(TAG, "tsd_tsd not found"); - return; - } - - auto tsd = pthread_getspecific(*tsd_tsd); - if (tsd == nullptr) { - LOGE(TAG, "tsd id null"); - return; - } - - void *arena1 = arena_choose_hard(tsd, false); // choose 另一个 arena - - unsigned which_arena = 0; - size_t which_arena_size = sizeof(unsigned); - mallctl("thread.arena", &which_arena, &which_arena_size, nullptr, 0); - - bool zero = false; - LOGD(TAG, "args : tsd=%p, arena1=%p, size=%zu, align=%d, zero=%p", tsd, (void *) arena1, __size, - CACHELINE, &zero); - void *extent = arena_extent_alloc_large(tsd, (void *) arena1, __size, CACHELINE, &zero); -// large_dalloc(tsd, extent); - - arena_extent_dalloc_large_prep(tsd, arena1, extent); - extent_hooks_t *hooks = nullptr; - arena_extents_dirty_dalloc(tsd, arena1, &hooks, extent); -} - -static void *sub_routine(void *arg) { - LOGD(TAG, "arg = %zu ", *((size_t *) arg)); - - void *p = malloc(1024);// 确保当前线程的 tsd 已经初始化 - - unsigned which_arena = 0; - size_t which_arena_size = sizeof(unsigned); - - int ret = mallctl("thread.arena", &which_arena, &which_arena_size, nullptr, - 0); - LOGD(TAG, "thread.arena: which_arena = %u, ret = %d", which_arena, ret); - - if (which_arena == 0) { - call_alloc_large_in_arena1(*(size_t *) arg); - free(p); - free(arg); - flush_decay_purge(); - return nullptr; - } - - pthread_t next_thread; - pthread_create(&next_thread, nullptr, sub_routine, arg); - - pthread_join(next_thread, nullptr); - - free(p); - return nullptr; -} - -// Android: Force all huge allocations to always take place in the first arena. -// see: https://cs.android.com/android/platform/superproject/+/android-10.0.0_r30:external/jemalloc_new/src/large.c;l=46 -// so we have to hack jemalloc to make sure that the large allocation takes place in second arena -static int hack_prealloc_within_arena1(size_t size) { - LOGD(TAG, "hack_arena1"); - if (!initialized) { - LOGD(TAG, "hack_arena1:init fialed"); - return ERR_INIT_FAILED; - } - - LOGD(TAG, "size1 = %zu", size); - auto p_size = (size_t *) malloc(sizeof(size_t)); - *p_size = size; - - pthread_t next_thread; - pthread_create(&next_thread, nullptr, sub_routine, p_size); - - return JECTL_OK; -} - -void *arena0_alloc_opt_prevent; - -JNIEXPORT jint JNICALL -Java_com_tencent_matrix_jectl_JeCtl_preAllocRetainNative(JNIEnv *env, jclass clazz, jint __size0, - jint __size1, jint __limit0, - jint __limit1) { - -#ifdef __LP64__ - return ERR_64_BIT; -#else - if (!initialized) { - return ERR_INIT_FAILED; - } - assert(mallctl != nullptr); - - assert(__size0 > 0); - assert(__size1 > 0); - assert(__limit0 > 0); - assert(__limit1 > 0); - - int ctl_result = 0; - int ret_code = JECTL_OK; - - size_t dirty_ms; - size_t new_dirty_ms = 0; - size_t ms_size = sizeof(size_t); - ctl_result = mallctl("arena.0.muzzy_decay_ms", &dirty_ms, &ms_size, &new_dirty_ms, ms_size); - LOGD(TAG, "arena.0.muzzy_decay_ms ret = %d", ctl_result); - ctl_result = mallctl("arena.1.muzzy_decay_ms", &dirty_ms, &ms_size, &new_dirty_ms, ms_size); - LOGD(TAG, "arena.1.muzzy_decay_ms ret = %d", ctl_result); - -// ret = mallctl("arena.0.dirty_decay_ms", &dirty_ms, &dirty_ms_size, &new_dirty_ms, dirty_ms_size); -// LOGD(TAG, "arena.0.dirty_decay_ms ret = %d", ret); -// ret = mallctl("arena.1.dirty_decay_ms", &dirty_ms, &dirty_ms_size, &new_dirty_ms, dirty_ms_size); -// LOGD(TAG, "arena.1.dirty_decay_ms ret = %d", ret); - - size_t old_limit = 0; - size_t new_limit = __limit0; - size_t limit_size = sizeof(size_t); - ctl_result = mallctl("arena.0.retain_grow_limit", &old_limit, &limit_size, &new_limit, - limit_size); - LOGD(TAG, "arena.0.retain_grow_limit ret = %d, old limit = %zu", ctl_result, old_limit); - new_limit = __limit1; - ctl_result = mallctl("arena.1.retain_grow_limit", &old_limit, &limit_size, &new_limit, - limit_size); - LOGD(TAG, "arena.1.retain_grow_limit ret = %d, old limit = %zu", ctl_result, old_limit); - - LOGD(TAG, "prepare alloc"); - void *p = malloc(__size0); - if (!p) { - ret_code = ERR_ALLOC_FAILED; - } - arena0_alloc_opt_prevent = p; - LOGD(TAG, "prepare alloc arena0 done %p", p); - free(p); - hack_prealloc_within_arena1(__size1); - - flush_decay_purge(); - - return ret_code; -#endif -} - JNIEXPORT jstring JNICALL -Java_com_tencent_matrix_jectl_JeCtl_getVersionNative(JNIEnv *env, jclass clazz) { +Java_com_tencent_matrix_mallctl_MallCtl_getVersionNative(JNIEnv *env, jclass clazz) { #ifdef __LP64__ return env->NewStringUTF("64-bit"); #else @@ -412,21 +173,6 @@ Java_com_tencent_matrix_jectl_JeCtl_getVersionNative(JNIEnv *env, jclass clazz) #endif } -JNIEXPORT jboolean JNICALL -Java_com_tencent_matrix_jectl_JeCtl_setRetain(JNIEnv *env, jclass clazz, jboolean enable) { -#ifdef __LP64__ - return true; -#else - bool old = true; - if (initialized && p_je_opt_retain) { - old = *p_je_opt_retain; - *p_je_opt_retain = enable; - LOGD(TAG, "retain = %d", *p_je_opt_retain); - } - return old; -#endif -} - #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.cpp b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.cpp deleted file mode 100644 index 915a007d9..000000000 --- a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making wechat-matrix available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Created by Yves on 2020/8/20. -// - -#include -#include "JeHooks.h" -#include "JeLog.h" - -#define TAG "Matrix.JeCtl.Hooks" - -extent_hooks_t *origin_extent_hooks; -//bool arena_1 = false; - -void *hook_extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, unsigned arena_ind) { - if (arena_ind != 0) { -// arena_1 = true; - } - LOGD(TAG, "hook_extent_alloc: size = %zu, arena_ind = %u", size, arena_ind); // should not log here - return origin_extent_hooks->alloc(origin_extent_hooks, new_addr, size, alignment, zero, commit, arena_ind); -} - -bool hook_extent_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, - unsigned arena_ind) { - return origin_extent_hooks->dalloc(origin_extent_hooks, addr, size, committed, arena_ind); -} - - -void hook_extent_destroy(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, - unsigned arena_ind) { - origin_extent_hooks->destroy(origin_extent_hooks, addr, size, committed, arena_ind); -} - -bool hook_extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind) { - return origin_extent_hooks->commit(origin_extent_hooks, addr, size, offset, length, arena_ind); -} - - -bool hook_extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind) { - return origin_extent_hooks->decommit(origin_extent_hooks, addr, size, offset, length, arena_ind); -} - -bool hook_extent_purge_lazy(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind) { - if (origin_extent_hooks->purge_lazy) { - return origin_extent_hooks->purge_lazy(origin_extent_hooks, addr, size, offset, length, - arena_ind); - } - return true; // 当 default_extent_hooks->purge_lazy == NULL, 返回 true 以保持 jemalloc 的逻辑一致 -} - -bool hook_extent_purge_forced(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind) { - if (origin_extent_hooks->purge_forced) { - return origin_extent_hooks->purge_forced(origin_extent_hooks, addr, size, offset, length, - arena_ind); - } - return true; // 当 default_extent_hooks->purge_forced == NULL, 返回 true 以保持 jemalloc 的逻辑一致 -} - -extent_split_t *original_split; - -bool hook_extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t size_a, - size_t size_b, bool committed, unsigned arena_ind) { -// bool ret = original_split(origin_extent_hooks, addr, size, size_a, size_b, committed, arena_ind); -// LOGD(TAG, "hook_extent_split: arena_ind = %u, ret = %d", arena_ind, /*ret*/0); -// return ret; - return origin_extent_hooks->split(origin_extent_hooks, addr, size, size_a, size_b, committed, arena_ind); -} - - -bool hook_extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, void *addr_b, - size_t size_b, bool committed, unsigned arena_ind) { - return origin_extent_hooks->merge(origin_extent_hooks, addr_a, size_a, addr_b, size_b, committed, - arena_ind); -} - -extent_hooks_t extent_hooks = { - hook_extent_alloc, - hook_extent_dalloc, - hook_extent_destroy, - hook_extent_commit, - hook_extent_decommit, - hook_extent_purge_lazy, - hook_extent_purge_forced, - hook_extent_split, - hook_extent_merge -}; \ No newline at end of file diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.h b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.h deleted file mode 100644 index da5fac90f..000000000 --- a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeHooks.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making wechat-matrix available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Created by Yves on 2020/8/20. -// - -#ifndef LIBMATRIX_JNI_JEHOOKS_H -#define LIBMATRIX_JNI_JEHOOKS_H - -typedef struct extent_hooks_s extent_hooks_t; - -extern extent_hooks_t *origin_extent_hooks; -extern extent_hooks_t extent_hooks; - -/* - * void * - * extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size, - * size_t alignment, bool *zero, bool *commit, unsigned arena_ind); - */ -typedef void *(extent_alloc_t)(extent_hooks_t *, void *, size_t, size_t, bool *, - bool *, unsigned); - -/* - * bool - * extent_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size, - * bool committed, unsigned arena_ind); - */ -typedef bool (extent_dalloc_t)(extent_hooks_t *, void *, size_t, bool, - unsigned); - -/* - * void - * extent_destroy(extent_hooks_t *extent_hooks, void *addr, size_t size, - * bool committed, unsigned arena_ind); - */ -typedef void (extent_destroy_t)(extent_hooks_t *, void *, size_t, bool, - unsigned); - -/* - * bool - * extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, - * size_t offset, size_t length, unsigned arena_ind); - */ -typedef bool (extent_commit_t)(extent_hooks_t *, void *, size_t, size_t, size_t, - unsigned); - -/* - * bool - * extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, - * size_t offset, size_t length, unsigned arena_ind); - */ -typedef bool (extent_decommit_t)(extent_hooks_t *, void *, size_t, size_t, - size_t, unsigned); - -/* - * bool - * extent_purge(extent_hooks_t *extent_hooks, void *addr, size_t size, - * size_t offset, size_t length, unsigned arena_ind); - */ -typedef bool (extent_purge_t)(extent_hooks_t *, void *, size_t, size_t, size_t, - unsigned); - -/* - * bool - * extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, - * size_t size_a, size_t size_b, bool committed, unsigned arena_ind); - */ -typedef bool (extent_split_t)(extent_hooks_t *, void *, size_t, size_t, size_t, - bool, unsigned); - -/* - * bool - * extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, - * void *addr_b, size_t size_b, bool committed, unsigned arena_ind); - */ -typedef bool (extent_merge_t)(extent_hooks_t *, void *, size_t, void *, size_t, - bool, unsigned); - - -struct extent_hooks_s { - extent_alloc_t *alloc; - extent_dalloc_t *dalloc; - extent_destroy_t *destroy; - extent_commit_t *commit; - extent_decommit_t *decommit; - extent_purge_t *purge_lazy; - extent_purge_t *purge_forced; - extent_split_t *split; - extent_merge_t *merge; -}; - -#endif //LIBMATRIX_JNI_JEHOOKS_H diff --git a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/jectl/JeCtl.java b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/jectl/JeCtl.java deleted file mode 100644 index 2d7086954..000000000 --- a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/jectl/JeCtl.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making wechat-matrix available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.tencent.matrix.jectl; - - -import androidx.annotation.Keep; - -import com.tencent.matrix.util.MatrixLog; - -/** - * Created by Yves on 2020/7/15 - */ -public class JeCtl { - private static final String TAG = "Matrix.JeCtl"; - - private static boolean initialized = false; - - static { - try { - System.loadLibrary("matrix-jectl"); - initNative(); - initialized = true; - } catch (Throwable e) { - MatrixLog.printErrStackTrace(TAG, e, ""); - } - } - - // 必须和 native 保持一致 - public static final int JECTL_OK = 0; - public static final int ERR_INIT_FAILED = 1; - public static final int ERR_VERSION = 2; - public static final int ERR_64_BIT = 3; - public static final int ERR_CTL = 4; - public static final int ERR_ALLOC_FAILED = 5; - - public synchronized static int compact() { - if (!initialized) { - MatrixLog.e(TAG, "JeCtl init failed! check if so exists"); - return ERR_INIT_FAILED; - } - return compactNative(); - } - - private static boolean hasAllocated; - private static int sLastPreAllocRet; - - public synchronized static int preAllocRetain(int size0, int size1, int limit0, int limit1) { - if (!initialized) { - MatrixLog.e(TAG, "JeCtl init failed! check if so exists"); - return ERR_INIT_FAILED; - } - if (!hasAllocated) { - hasAllocated = true; - sLastPreAllocRet = preAllocRetainNative(size0, size1, limit0, limit1); - } - - return sLastPreAllocRet; - } - - public synchronized static String version() { - if (!initialized) { - MatrixLog.e(TAG, "JeCtl init failed! check if so exists"); - return "VER_UNKNOWN"; - } - - return getVersionNative(); - } - - @Keep - private static native void initNative(); - - @Keep - private static native int compactNative(); - - @Keep - private static native int preAllocRetainNative(int size0, int size1, int limit0, int limit1); - - @Keep - private static native String getVersionNative(); - - @Keep - public static native boolean setRetain(boolean enable); -} diff --git a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java new file mode 100644 index 000000000..84d3b475e --- /dev/null +++ b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java @@ -0,0 +1,56 @@ +/* + * Tencent is pleased to support the open source community by making wechat-matrix available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tencent.matrix.mallctl; + + +import androidx.annotation.Keep; + +import com.tencent.matrix.util.MatrixLog; + +/** + * Created by Yves on 2020/7/15 + */ +public class MallCtl { + private static final String TAG = "Matrix.JeCtl"; + + private static boolean initialized = false; + + static { + try { + System.loadLibrary("matrix-mallctl"); + initNative(); + initialized = true; + } catch (Throwable e) { + MatrixLog.printErrStackTrace(TAG, e, ""); + } + } + + public synchronized static String jeVersion() { + if (!initialized) { + MatrixLog.e(TAG, "JeCtl init failed! check if so exists"); + return "VER_UNKNOWN"; + } + + return getVersionNative(); + } + + @Keep + private static native void initNative(); + + @Keep + private static native String getVersionNative(); +} From a2abe1f349547252d3eda23a493a4aadd8ac44a1 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 26 Jul 2022 20:31:00 +0800 Subject: [PATCH 105/263] mallctl: add mallopt --- .../cpp/libenhance_dlsym/EnhanceDlsym.cpp | 7 +- .../matrix-mallctl/CMakeLists.txt | 3 +- .../src/main/AndroidManifest.xml | 2 +- .../src/main/cpp/jectl/JeCtl.cpp | 178 ------------------ .../src/main/cpp/jectl/MallCtl.cpp | 152 +++++++++++++++ .../src/main/cpp/jectl/{JeLog.h => MallLog.h} | 0 .../com/tencent/matrix/mallctl/MallCtl.java | 20 ++ 7 files changed, 180 insertions(+), 182 deletions(-) delete mode 100644 matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp create mode 100644 matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallCtl.cpp rename matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/{JeLog.h => MallLog.h} (100%) diff --git a/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/EnhanceDlsym.cpp b/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/EnhanceDlsym.cpp index 6eb5b0cd4..15c4fc7a4 100644 --- a/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/EnhanceDlsym.cpp +++ b/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/EnhanceDlsym.cpp @@ -32,10 +32,15 @@ #include #include #include "EnhanceDlsym.h" -#include "../../../../../matrix-jectl/src/main/cpp/jectl/JeLog.h" #define TAG "Matrix.EnhanceDl" +#include + +#define LOGD(TAG, FMT, args...) //__android_log_print(ANDROID_LOG_DEBUG, TAG, FMT, ##args) +#define LOGI(TAG, FMT, args...) //__android_log_print(ANDROID_LOG_INFO, TAG, FMT, ##args) +#define LOGE(TAG, FMT, args...) //__android_log_print(ANDROID_LOG_ERROR, TAG, FMT, ##args) + namespace enhance { static std::set m_opened_info; diff --git a/matrix/matrix-android/matrix-mallctl/CMakeLists.txt b/matrix/matrix-android/matrix-mallctl/CMakeLists.txt index a2995de97..762921f67 100644 --- a/matrix/matrix-android/matrix-mallctl/CMakeLists.txt +++ b/matrix/matrix-android/matrix-mallctl/CMakeLists.txt @@ -16,8 +16,7 @@ set(SOURCE_DIR src/main/cpp) set( SOURCE_FILES - ${SOURCE_DIR}/jectl/JeCtl.cpp - ${SOURCE_DIR}/jectl/JeHooks.cpp + ${SOURCE_DIR}/jectl/MallCtl.cpp ) add_library( # Specifies the name of the library. diff --git a/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml b/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml index 37af2b71f..3c14638b0 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ + package="com.tencent.matrix.je_mallctl"> \ No newline at end of file diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp deleted file mode 100644 index e7e7f808a..000000000 --- a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeCtl.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making wechat-matrix available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Created by Yves on 2020/7/15. -// - -#include -#include -#include -#include -#include -#include "EnhanceDlsym.h" -#include "JeLog.h" -#include - -#define TAG "Matrix.JeCtl" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef int (*mallctl_t)(const char *name, - void *oldp, - size_t *oldlenp, - void *newp, - size_t newlen); - -typedef void *(*arena_extent_alloc_large_t)(void *tsdn, - void *arena, - size_t usize, - size_t alignment, - bool *zero); - -typedef void (*large_dalloc_t)(void *tsdn, void *extent); - -typedef void *(*arena_choose_hard_t)(void *tsd, bool internal); - -typedef void (*arena_extent_dalloc_large_prep_t)(void *tsdn, void *arena, void *extent); - -typedef void (*arena_extents_dirty_dalloc_t)(void *tsdn, void *arena, - extent_hooks_t **r_extent_hooks, void *extent); - -#define MAX_RETRY_TIMES 10 - -void *handle = nullptr; -bool initialized = false; - -mallctl_t mallctl = nullptr; -arena_extent_alloc_large_t arena_extent_alloc_large = nullptr; -large_dalloc_t large_dalloc = nullptr; -arena_choose_hard_t arena_choose_hard = nullptr; -arena_extent_dalloc_large_prep_t arena_extent_dalloc_large_prep = nullptr; -arena_extents_dirty_dalloc_t arena_extents_dirty_dalloc = nullptr; -bool * p_je_opt_retain = nullptr; - -static bool init() { - - handle = enhance::dlopen("libc.so", 0); - - if (handle == nullptr) { - return false; - } - - mallctl = (mallctl_t) enhance::dlsym(handle, "je_mallctl"); - - if (!mallctl) { - return false; - } - - const char *version; - size_t size = sizeof(version); - mallctl("version", &version, &size, nullptr, 0); - LOGD(TAG, "jemalloc version: %s", version); - - if (0 != strncmp(version, "5.1.0", 5)) { - return false; - } - -// Dl_info mallctl_info{}; -// if (0 == dladdr((void *) mallctl, &mallctl_info) -// || !end_with(mallctl_info.dli_fname, "/libc.so")) { -// LOGD(TAG, "mallctl = %p, is a fault address, fname = %s, sname = %s", mallctl, -// mallctl_info.dli_fname, mallctl_info.dli_sname); -// mallctl = nullptr; -// return false; -// } - - p_je_opt_retain = (bool *) enhance::dlsym(handle, "je_opt_retain"); - if (!p_je_opt_retain) { - return false; - } - - arena_extent_alloc_large = - (arena_extent_alloc_large_t) enhance::dlsym(handle, "je_arena_extent_alloc_large"); - if (!arena_extent_alloc_large) { - return false; - } - - arena_choose_hard = (arena_choose_hard_t) enhance::dlsym(handle, "je_arena_choose_hard"); - if (!arena_choose_hard) { - return false; - } - - large_dalloc = (large_dalloc_t) enhance::dlsym(handle, "je_large_dalloc"); - if (!large_dalloc) { - return false; - } - - arena_extent_dalloc_large_prep = (arena_extent_dalloc_large_prep_t) enhance::dlsym(handle, - "je_arena_extent_dalloc_large_prep"); - if (!arena_extent_dalloc_large_prep) { - return false; - } - - arena_extents_dirty_dalloc = (arena_extents_dirty_dalloc_t) enhance::dlsym(handle, - "je_arena_extents_dirty_dalloc"); - if (!arena_extents_dirty_dalloc) { - return false; - } - - return true; -} - -static void flush_decay_purge() { - assert(mallctl != nullptr); - mallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0); - mallctl("arena.0.decay", nullptr, nullptr, nullptr, 0); - mallctl("arena.1.decay", nullptr, nullptr, nullptr, 0); - mallctl("arena.0.purge", nullptr, nullptr, nullptr, 0); - mallctl("arena.1.purge", nullptr, nullptr, nullptr, 0); -} - -JNIEXPORT void JNICALL -Java_com_tencent_matrix_mallctl_MallCtl_initNative(JNIEnv *env, jclass clazz) { -#ifdef __LP64__ - return ; -#else - if (!initialized) { - initialized = init(); - } -#endif -} - -JNIEXPORT jstring JNICALL -Java_com_tencent_matrix_mallctl_MallCtl_getVersionNative(JNIEnv *env, jclass clazz) { -#ifdef __LP64__ - return env->NewStringUTF("64-bit"); -#else - if (!mallctl) { - return env->NewStringUTF("Error"); - } - - const char *version; - size_t size = sizeof(version); - mallctl("version", &version, &size, nullptr, 0); - LOGD(TAG, "jemalloc version: %s", version); - - return env->NewStringUTF(version); -#endif -} - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallCtl.cpp b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallCtl.cpp new file mode 100644 index 000000000..5c39e1d8f --- /dev/null +++ b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallCtl.cpp @@ -0,0 +1,152 @@ +/* + * Tencent is pleased to support the open source community by making wechat-matrix available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Created by Yves on 2020/7/15. +// + +#include +#include +#include +#include +#include +#include "EnhanceDlsym.h" +#include "MallLog.h" +#include + +#define TAG "Matrix.JeCtl" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*je_mallctl_t)(const char *name, + void *oldp, + size_t *oldlenp, + void *newp, + size_t newlen); + +typedef void *(*je_arena_extent_alloc_large_t)(void *tsdn, + void *arena, + size_t usize, + size_t alignment, + bool *zero); + +typedef void (*je_large_dalloc_t)(void *tsdn, void *extent); + +typedef void *(*je_arena_choose_hard_t)(void *tsd, bool internal); + +typedef void (*je_arena_extent_dalloc_large_prep_t)(void *tsdn, void *arena, void *extent); + +typedef int (*mallopt_t)(int param, int value); + +#define MAX_RETRY_TIMES 10 + +void *handle = nullptr; +bool initialized = false; + +je_mallctl_t je_mallctl = nullptr; +je_arena_extent_alloc_large_t je_arena_extent_alloc_large = nullptr; +je_large_dalloc_t je_large_dalloc = nullptr; +je_arena_choose_hard_t je_arena_choose_hard = nullptr; +je_arena_extent_dalloc_large_prep_t je_arena_extent_dalloc_large_prep = nullptr; + +bool *je_opt_retain_ptr = nullptr; + +mallopt_t libc_mallopt = nullptr; + +static bool init() { + + handle = enhance::dlopen("libc.so", 0); + + if (handle == nullptr) { + return false; + } + + libc_mallopt = (mallopt_t) enhance::dlsym(handle, "mallopt"); + + je_mallctl = (je_mallctl_t) enhance::dlsym(handle, "je_mallctl"); + + if (!je_mallctl) { + return false; + } + + const char *version; + size_t size = sizeof(version); + je_mallctl("version", &version, &size, nullptr, 0); + LOGD(TAG, "jemalloc version: %s", version); + + je_opt_retain_ptr = (bool *) enhance::dlsym(handle, "je_opt_retain"); + if (!je_opt_retain_ptr) { + return false; + } + + return true; +} + +static void flush_decay_purge() { + assert(je_mallctl != nullptr); + je_mallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0); + je_mallctl("arena.0.decay", nullptr, nullptr, nullptr, 0); + je_mallctl("arena.1.decay", nullptr, nullptr, nullptr, 0); + je_mallctl("arena.0.purge", nullptr, nullptr, nullptr, 0); + je_mallctl("arena.1.purge", nullptr, nullptr, nullptr, 0); +} + +JNIEXPORT void JNICALL +Java_com_tencent_matrix_mallctl_MallCtl_initNative(JNIEnv *env, jclass clazz) { + if (!initialized) { + initialized = init(); + } +} + +JNIEXPORT jstring JNICALL +Java_com_tencent_matrix_mallctl_MallCtl_getVersionNative(JNIEnv *env, jclass clazz) { +#ifdef __LP64__ + return env->NewStringUTF("64-bit"); +#else + if (!je_mallctl) { + return env->NewStringUTF("Error"); + } + + const char *version; + size_t size = sizeof(version); + je_mallctl("version", &version, &size, nullptr, 0); + LOGD(TAG, "jemalloc version: %s", version); + + return env->NewStringUTF(version); +#endif +} + +#define MALLOPT_SYM_NOT_FOUND -1 + +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_mallctl_MallCtl_malloptNative(JNIEnv *env, jclass clazz) { + if (!libc_mallopt) { + return MALLOPT_SYM_NOT_FOUND; + } + // On success, mallopt() returns 1. On error, it returns 0. + int ret = libc_mallopt(M_PURGE, 0); + if (ret == 0) { + // try fallback je ctls + flush_decay_purge(); + } + return ret; +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeLog.h b/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallLog.h similarity index 100% rename from matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/JeLog.h rename to matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallLog.h diff --git a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java index 84d3b475e..b86d941e7 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java +++ b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java @@ -48,9 +48,29 @@ public synchronized static String jeVersion() { return getVersionNative(); } + public static final int MALLOPT_FAILED = 0; + public static final int MALLOPT_SUCCESS = 1; + public static final int MALLOPT_SYM_NOT_FOUND = -1; + public static final int MALLOPT_EXCEPTION = -2; + + /** + * @return On success, mallopt() returns 1. On error, it returns 0. + */ + public synchronized static int mallopt() { + try { + return malloptNative(); + } catch (Throwable e) { + MatrixLog.printErrStackTrace(TAG, e, "mallopt failed"); + } + return MALLOPT_EXCEPTION; + } + @Keep private static native void initNative(); @Keep private static native String getVersionNative(); + + @Keep + private static native int malloptNative(); } From 46fb9516341b1a2d929224191f3a57082ee53aa3 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 26 Jul 2022 20:33:35 +0800 Subject: [PATCH 106/263] mallctl: fix pkg name --- matrix/matrix-android/matrix-mallctl/CMakeLists.txt | 2 +- .../matrix-android/matrix-mallctl/src/main/AndroidManifest.xml | 2 +- .../matrix-mallctl/src/main/cpp/{jectl => mallctl}/MallCtl.cpp | 0 .../matrix-mallctl/src/main/cpp/{jectl => mallctl}/MallLog.h | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename matrix/matrix-android/matrix-mallctl/src/main/cpp/{jectl => mallctl}/MallCtl.cpp (100%) rename matrix/matrix-android/matrix-mallctl/src/main/cpp/{jectl => mallctl}/MallLog.h (100%) diff --git a/matrix/matrix-android/matrix-mallctl/CMakeLists.txt b/matrix/matrix-android/matrix-mallctl/CMakeLists.txt index 762921f67..cf1e64739 100644 --- a/matrix/matrix-android/matrix-mallctl/CMakeLists.txt +++ b/matrix/matrix-android/matrix-mallctl/CMakeLists.txt @@ -16,7 +16,7 @@ set(SOURCE_DIR src/main/cpp) set( SOURCE_FILES - ${SOURCE_DIR}/jectl/MallCtl.cpp + ${SOURCE_DIR}/mallctl/MallCtl.cpp ) add_library( # Specifies the name of the library. diff --git a/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml b/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml index 3c14638b0..37af2b71f 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-mallctl/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ + package="com.tencent.matrix.mallctl"> \ No newline at end of file diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallCtl.cpp b/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp similarity index 100% rename from matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallCtl.cpp rename to matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallLog.h b/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallLog.h similarity index 100% rename from matrix/matrix-android/matrix-mallctl/src/main/cpp/jectl/MallLog.h rename to matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallLog.h From d6aa3aa91d2e5bf506050a522eca1477f4bfa3db Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 26 Jul 2022 20:35:08 +0800 Subject: [PATCH 107/263] mallctl: fix module name --- matrix/matrix-android/matrix-mallctl/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-mallctl/gradle.properties b/matrix/matrix-android/matrix-mallctl/gradle.properties index f90e4fc10..3606fb76f 100644 --- a/matrix/matrix-android/matrix-mallctl/gradle.properties +++ b/matrix/matrix-android/matrix-mallctl/gradle.properties @@ -1,2 +1,2 @@ POM_NAME=Matrix jectl for jemalloc -POM_ARTIFACT_ID=matrix-jectl \ No newline at end of file +POM_ARTIFACT_ID=matrix-mallctl \ No newline at end of file From 4e067994fe126dc717b79bdec89c135ba54de77f Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 26 Jul 2022 20:53:39 +0800 Subject: [PATCH 108/263] Update power_profile.xml reading --- .../utils/BatteryMetricsTest.java | 56 +++++++++ .../utils/PowerManagerHookerTest.java | 52 +++++++++ .../stats/HealthStatsFeature.java | 67 +++++++++++ .../batterycanary/utils/PowerProfile.java | 107 ++++++++++++++++-- 4 files changed, 272 insertions(+), 10 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java index fa2ea8914..d0d207f06 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java @@ -23,6 +23,7 @@ import android.os.Looper; import android.os.Process; import android.os.SystemClock; +import android.system.Os; import android.text.TextUtils; import android.util.Log; @@ -34,9 +35,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserFactory; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Constructor; @@ -44,6 +47,7 @@ import java.util.Arrays; import java.util.List; import java.util.Stack; +import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -102,6 +106,58 @@ public void testReadPowerProfile() throws Exception { Assert.assertTrue(PowerProfile.getInstance().isSupported()); } + @Test + public void testReadPowerProfileTest() throws Exception { + Class clazz = Class.forName("com.android.internal.os.PowerProfile"); + Constructor constructor = clazz.getConstructor(Context.class); + Object obj = constructor.newInstance(mContext); + Assert.assertNotNull(obj); + + int id = mContext.getResources().getIdentifier("power_profile_test", "xml", "android"); + Assert.assertTrue(id > 0); + } + + @Test + public void testFindPowerProfileFile() throws Exception { + Callable findBlock = new Callable() { + @Override + public File call() { + String customDirs = Os.getenv("CUST_POLICY_DIRS"); + Assert.assertFalse(TextUtils.isEmpty(customDirs)); + for (String dir : customDirs.split(":")) { + // example: /hw_product/etc/xml/power_profile.xml + File file = new File(dir, "/xml/power_profile.xml"); + if (file.exists() && file.canRead()) { + return file; + } + } + return null; + } + }; + + + File file = findBlock.call(); + if (file != null) { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + factory.setNamespaceAware(true); + XmlPullParser parser = factory.newPullParser(); + parser.setInput(new FileInputStream(file), "UTF-8"); + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + if (parser.getEventType() == XmlPullParser.START_TAG) { + String tagName = parser.getName(); + String tagText = parser.getText(); + for (int i = 0; i < parser.getAttributeCount(); i++) { + String attrName = parser.getAttributeName(i); + String attrValue = parser.getAttributeValue(i); + if (attrValue.startsWith("cpu.core_speeds.cluster")) { + } + } + } + parser.nextToken(); + } + } + } + @Test public void testGetAppCpuCoreNumByTid() { StringBuilder tips = new StringBuilder("\n"); diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/PowerManagerHookerTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/PowerManagerHookerTest.java index 9f7efb31e..a4f73c639 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/PowerManagerHookerTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/PowerManagerHookerTest.java @@ -16,10 +16,14 @@ package com.tencent.matrix.batterycanary.utils; +import android.annotation.SuppressLint; import android.content.Context; import android.os.IBinder; import android.os.PowerManager; import android.os.WorkSource; +import android.text.TextUtils; +import android.util.Log; + import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -31,6 +35,7 @@ import org.junit.runner.RunWith; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -89,6 +94,8 @@ public void onReleaseWakeLock(IBinder token, int flags) { PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); wakLockRef.set(wakeLock); + String wakeLockTag = getWakeLockTag(wakeLock); + Assert.assertEquals(TAG, wakeLockTag); Assert.assertNotNull(wakeLock); wakeLock.acquire(); @@ -101,6 +108,51 @@ public void onReleaseWakeLock(IBinder token, int flags) { Assert.assertTrue(hasRelease.get()); } + private static String getWakeLockTag(PowerManager.WakeLock wakeLock) { + String tag = null; + try { + @SuppressWarnings("JavaReflectionMemberAccess") + @SuppressLint({"SoonBlockedPrivateApi"}) + Method method = wakeLock.getClass().getDeclaredMethod("getTag"); + method.setAccessible(true); + tag = (String) method.invoke(wakeLock); + } catch (Throwable e) { + Log.e(TAG, "getTag err: " + e); + } + if (TextUtils.isEmpty(tag)) { + try { + @SuppressWarnings("JavaReflectionMemberAccess") + @SuppressLint("DiscouragedPrivateApi") + Field field = wakeLock.getClass().getDeclaredField("mTag"); + field.setAccessible(true); + tag = (String) field.get(wakeLock); + } catch (Throwable e) { + Log.e(TAG, "mTag err: " + e); + } + } + if (TextUtils.isEmpty(tag)) { + try { + @SuppressWarnings("JavaReflectionMemberAccess") + @SuppressLint({"SoonBlockedPrivateApi"}) + Field field = wakeLock.getClass().getDeclaredField("mTraceName"); + field.setAccessible(true); + tag = (String) field.get(wakeLock); + if (tag != null && tag.startsWith("WakeLock (") && tag.endsWith(")")) { + int idxBgn = tag.indexOf("WakeLock (") + "WakeLock (".length(); + int idxEnd = tag.lastIndexOf(")"); + if (idxBgn < idxEnd) { + tag = tag.substring(idxBgn, idxEnd); + } + } + } catch (Throwable e) { + Log.e(TAG, "mTraceName err: " + e); + } + } + + Log.i(TAG, "getWakeLockTag: " + tag); + return tag; + } + @Ignore @Test public void testAcquireWakeupTimeout() throws Exception { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 9aae22c69..39b9480b7 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -7,6 +7,7 @@ import android.os.Build; import android.os.health.HealthStats; import android.os.health.PidHealthStats; +import android.os.health.ProcessHealthStats; import android.os.health.TimerStat; import android.os.health.UidHealthStats; @@ -17,6 +18,7 @@ import com.tencent.matrix.util.MatrixLog; import java.lang.reflect.Method; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -224,6 +226,32 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.procFgSrvMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS)); snapshot.procBgMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_BACKGROUND_MS)); snapshot.procCacheMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_PROCESS_STATE_CACHED_MS)); + + { + if (healthStats.hasStats(UidHealthStats.STATS_PROCESSES)) { + Map processes = healthStats.getStats(UidHealthStats.STATS_PROCESSES); + for (Map.Entry item : processes.entrySet()) { + String pkg = item.getKey(); + HealthStats procStats = item.getValue(); + if (procStats != null) { + if (snapshot.procStatsCpuUsrTimeMs.isEmpty()) { + snapshot.procStatsCpuUsrTimeMs = new HashMap<>(); + } + snapshot.procStatsCpuUsrTimeMs.put(pkg, DigitEntry.of(HealthStatsHelper.getMeasure(procStats, ProcessHealthStats.MEASUREMENT_USER_TIME_MS))); + + if (snapshot.procStatsCpuSysTimeMs.isEmpty()) { + snapshot.procStatsCpuSysTimeMs = new HashMap<>(); + } + snapshot.procStatsCpuSysTimeMs.put(pkg, DigitEntry.of(HealthStatsHelper.getMeasure(procStats, ProcessHealthStats.MEASUREMENT_SYSTEM_TIME_MS))); + + if (snapshot.procStatsCpuFgTimeMs.isEmpty()) { + snapshot.procStatsCpuFgTimeMs = new HashMap<>(); + } + snapshot.procStatsCpuFgTimeMs.put(pkg, DigitEntry.of(HealthStatsHelper.getMeasure(procStats, ProcessHealthStats.MEASUREMENT_FOREGROUND_MS))); + } + } + } + } } return snapshot; } @@ -303,6 +331,11 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry procBgMs = DigitEntry.of(0L); public DigitEntry procCacheMs = DigitEntry.of(0L); + // Process Stats + public Map> procStatsCpuUsrTimeMs = Collections.emptyMap(); + public Map> procStatsCpuSysTimeMs = Collections.emptyMap(); + public Map> procStatsCpuFgTimeMs = Collections.emptyMap(); + @Override public Delta diff(HealthStatsSnapshot bgn) { return new Delta(bgn, this) { @@ -371,6 +404,40 @@ protected HealthStatsSnapshot computeDelta() { delta.procFgSrvMs = Differ.DigitDiffer.globalDiff(bgn.procFgSrvMs, end.procFgSrvMs); delta.procBgMs = Differ.DigitDiffer.globalDiff(bgn.procBgMs, end.procBgMs); delta.procCacheMs = Differ.DigitDiffer.globalDiff(bgn.procCacheMs, end.procCacheMs); + + delta.procStatsCpuUsrTimeMs = new HashMap<>(); + for (Map.Entry> entry : end.procStatsCpuUsrTimeMs.entrySet()) { + String key = entry.getKey(); + DigitEntry endEntry = entry.getValue(); + long bgnValue = 0L; + DigitEntry bgnEntry = bgn.procStatsCpuUsrTimeMs.get(key); + if (bgnEntry != null) { + bgnValue = bgnEntry.get(); + } + delta.procStatsCpuUsrTimeMs.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); + } + delta.procStatsCpuSysTimeMs = new HashMap<>(); + for (Map.Entry> entry : end.procStatsCpuSysTimeMs.entrySet()) { + String key = entry.getKey(); + DigitEntry endEntry = entry.getValue(); + long bgnValue = 0L; + DigitEntry bgnEntry = bgn.procStatsCpuSysTimeMs.get(key); + if (bgnEntry != null) { + bgnValue = bgnEntry.get(); + } + delta.procStatsCpuSysTimeMs.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); + } + delta.procStatsCpuFgTimeMs = new HashMap<>(); + for (Map.Entry> entry : end.procStatsCpuFgTimeMs.entrySet()) { + String key = entry.getKey(); + DigitEntry endEntry = entry.getValue(); + long bgnValue = 0L; + DigitEntry bgnEntry = bgn.procStatsCpuFgTimeMs.get(key); + if (bgnEntry != null) { + bgnValue = bgnEntry.get(); + } + delta.procStatsCpuFgTimeMs.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); + } return delta; } }; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java index 51b33bd47..64a57f888 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java @@ -3,13 +3,20 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; +import android.os.Build; +import android.system.Os; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.Callable; import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; @@ -273,12 +280,11 @@ public int getClusterByCpuNum(int cpuCoreNum) { private static final Object sLock = new Object(); - @VisibleForTesting - public PowerProfile(Context context) { + private PowerProfile(Context context) { // Read the XML file for the given profile (normally only one per device) synchronized (sLock) { if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) { - readPowerValuesFromXml(context); + readPowerValuesCompat(context); } initCpuClusters(); } @@ -294,11 +300,94 @@ public static HashMap getPowerArrayMap() { return sPowerArrayMap; } + private static String mResType = "unknown"; + + public static String getResType() { + return mResType; + } + + private void readPowerValuesCompat(Context context) { + try { + readPowerValuesFromRes(context, "power_profile"); + initCpuClusters(); + smoke(); + mResType = "framework"; + } catch (Exception ignored) { + Callable findBlock = new Callable() { + @SuppressWarnings("checkstyle:RegexpSingleline") + @Override + public File call() throws FileNotFoundException { + String targetFileName = "/xml/power_profile.xml"; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + String customDirs = Os.getenv("CUST_POLICY_DIRS"); + for (String dir : customDirs.split(":")) { + // example: /hw_product/etc/xml/power_profile.xml + File file = new File(dir, targetFileName); + if (file.exists() && file.canRead()) { + return file; + } + } + } + throw new FileNotFoundException(targetFileName); + } + }; + try { + readPowerValuesFromFilePath(context, findBlock.call()); + initCpuClusters(); + smoke(); + mResType = "custom"; + } catch (Exception ignored2) { + readPowerValuesFromRes(context, "power_profile_test"); + initCpuClusters(); + mResType = "test"; + } + } + } + + private void readPowerValuesFromRes(Context context, String fileName) { + XmlResourceParser parser = null; + try { + final int id = context.getResources().getIdentifier(fileName, "xml", "android"); + final Resources resources = context.getResources(); + parser = resources.getXml(id); + readPowerValuesFromXml(context, parser); + } catch (Exception e) { + throw new RuntimeException("Error reading power values: " + fileName, e); + } finally { + if (parser != null) { + try { + parser.close(); + } catch (Exception e) { + // ignore + } + } + } + } + + private void readPowerValuesFromFilePath(Context context, File path) { + FileInputStream is = null; + try { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + factory.setNamespaceAware(true); + XmlPullParser parser = factory.newPullParser(); + is = new FileInputStream(path); + parser.setInput(is, null); + readPowerValuesFromXml(context, parser); + } catch (Exception e) { + throw new RuntimeException("Failed to read power values from file: " + path, e); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + // ignore + } + } + } + } + @SuppressWarnings({"ToArrayCallWithZeroLengthArrayArgument", "UnnecessaryBoxing", "CatchMayIgnoreException", "TryWithIdenticalCatches"}) - private void readPowerValuesFromXml(Context context) { - final int id = context.getResources().getIdentifier("power_profile", "xml", "android"); - final Resources resources = context.getResources(); - XmlResourceParser parser = resources.getXml(id); + private void readPowerValuesFromXml(Context context, XmlPullParser parser) { boolean parsingArray = false; ArrayList array = new ArrayList<>(); String arrayName = null; @@ -346,8 +435,6 @@ private void readPowerValuesFromXml(Context context) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); - } finally { - parser.close(); } // Now collect other config variables. @@ -372,7 +459,7 @@ private void readPowerValuesFromXml(Context context) { if ((sPowerItemMap.containsKey(key) && sPowerItemMap.get(key) > 0)) { continue; } - int value = resources.getInteger(configResIds[i]); + int value = context.getResources().getInteger(configResIds[i]); if (value > 0) { sPowerItemMap.put(key, (double) value); } From 1d0d58b81c578ef1bf7ca1df425814d9fc21e3d6 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 27 Jul 2022 11:31:30 +0800 Subject: [PATCH 109/263] mallctl: move setRetain back --- .../src/main/cpp/mallctl/MallCtl.cpp | 15 +++++++++++++++ .../java/com/tencent/matrix/mallctl/MallCtl.java | 12 ++++++++++++ 2 files changed, 27 insertions(+) diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp b/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp index 5c39e1d8f..8611bce9e 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp +++ b/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp @@ -147,6 +147,21 @@ Java_com_tencent_matrix_mallctl_MallCtl_malloptNative(JNIEnv *env, jclass clazz) return ret; } +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_mallctl_MallCtl_setRetainNative(JNIEnv *env, jclass clazz, jboolean enable) { +#ifdef __LP64__ + return true; +#else + bool old = true; + if (initialized && je_opt_retain_ptr) { + old = *je_opt_retain_ptr; + *je_opt_retain_ptr = enable; + LOGD(TAG, "retain = %d", *je_opt_retain_ptr); + } + return old; +#endif +} + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java index b86d941e7..93cf368cd 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java +++ b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java @@ -48,6 +48,15 @@ public synchronized static String jeVersion() { return getVersionNative(); } + public synchronized static boolean setRetain(boolean enable) { + try { + return setRetainNative(enable); + } catch (Throwable e) { + MatrixLog.printErrStackTrace(TAG, e, "set retain failed"); + } + return false; + } + public static final int MALLOPT_FAILED = 0; public static final int MALLOPT_SUCCESS = 1; public static final int MALLOPT_SYM_NOT_FOUND = -1; @@ -73,4 +82,7 @@ public synchronized static int mallopt() { @Keep private static native int malloptNative(); + + @Keep + private static native boolean setRetainNative(boolean enable); } From cc188a7eef0ec81dee04e4dbb062a827cad4e9b2 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 27 Jul 2022 11:33:21 +0800 Subject: [PATCH 110/263] mallctl: rename je setRetain api --- .../src/main/java/com/tencent/matrix/mallctl/MallCtl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java index 93cf368cd..104cb5b8d 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java +++ b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java @@ -48,7 +48,7 @@ public synchronized static String jeVersion() { return getVersionNative(); } - public synchronized static boolean setRetain(boolean enable) { + public synchronized static boolean jeSetRetain(boolean enable) { try { return setRetainNative(enable); } catch (Throwable e) { From 6493a108622acc71c695a6267233ead6c60fbbc7 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 27 Jul 2022 11:45:35 +0800 Subject: [PATCH 111/263] Update power profile logging --- .../batterycanary/utils/PowerProfile.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java index 64a57f888..77ddab4ac 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java @@ -6,6 +6,8 @@ import android.os.Build; import android.system.Os; +import com.tencent.matrix.util.MatrixLog; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; @@ -28,6 +30,7 @@ @RestrictTo(RestrictTo.Scope.LIBRARY) @SuppressWarnings({"JavadocReference", "ConstantConditions", "TryFinallyCanBeTryWithResources"}) public class PowerProfile { + private static final String TAG = "PowerProfile"; private static PowerProfile sInstance = null; @Nullable @@ -41,7 +44,7 @@ public static PowerProfile init(Context context) throws IOException { sInstance = new PowerProfile(context).smoke(); return sInstance; } catch (Throwable e) { - throw new IOException(e); + throw new IOException("Compat err: " + e.getMessage(), e); } } } @@ -312,7 +315,8 @@ private void readPowerValuesCompat(Context context) { initCpuClusters(); smoke(); mResType = "framework"; - } catch (Exception ignored) { + } catch (Exception e1) { + MatrixLog.w(TAG, "read from framework failed: " + e1); Callable findBlock = new Callable() { @SuppressWarnings("checkstyle:RegexpSingleline") @Override @@ -324,6 +328,7 @@ public File call() throws FileNotFoundException { // example: /hw_product/etc/xml/power_profile.xml File file = new File(dir, targetFileName); if (file.exists() && file.canRead()) { + MatrixLog.i(TAG, "find profile xml: " + file); return file; } } @@ -336,7 +341,8 @@ public File call() throws FileNotFoundException { initCpuClusters(); smoke(); mResType = "custom"; - } catch (Exception ignored2) { + } catch (Exception e2) { + MatrixLog.w(TAG, "read from framework failed: " + e1); readPowerValuesFromRes(context, "power_profile_test"); initCpuClusters(); mResType = "test"; @@ -352,7 +358,7 @@ private void readPowerValuesFromRes(Context context, String fileName) { parser = resources.getXml(id); readPowerValuesFromXml(context, parser); } catch (Exception e) { - throw new RuntimeException("Error reading power values: " + fileName, e); + throw new RuntimeException("Error reading res " + fileName + ": " + e.getMessage(), e); } finally { if (parser != null) { try { @@ -364,17 +370,17 @@ private void readPowerValuesFromRes(Context context, String fileName) { } } - private void readPowerValuesFromFilePath(Context context, File path) { + private void readPowerValuesFromFilePath(Context context, File xmlFile) { FileInputStream is = null; try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); factory.setNamespaceAware(true); XmlPullParser parser = factory.newPullParser(); - is = new FileInputStream(path); + is = new FileInputStream(xmlFile); parser.setInput(is, null); readPowerValuesFromXml(context, parser); } catch (Exception e) { - throw new RuntimeException("Failed to read power values from file: " + path, e); + throw new RuntimeException("Error reading file " + xmlFile + ": " + e.getMessage(), e); } finally { if (is != null) { try { From 8bf4c4e0021bb823cf48f4613a10d675d64b78e5 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 27 Jul 2022 17:05:44 +0800 Subject: [PATCH 112/263] Update battery capacity --- .../batterycanary/utils/CanaryUtilsTest.java | 2 +- .../monitor/feature/CompositeMonitors.java | 6 ++++ .../utils/BatteryCanaryUtil.java | 31 +++++++++++-------- .../batterycanary/utils/PowerProfile.java | 18 ++++++++++- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java index fa3c1a762..a8539be08 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/CanaryUtilsTest.java @@ -260,10 +260,10 @@ public void testGetBatteryPercentage() { @Test public void testGetBatteryCapacity() throws Exception { + PowerProfile powerProfile = PowerProfile.init(mContext); int capacity0 = BatteryCanaryUtil.getBatteryCapacityImmediately(mContext); Assert.assertTrue(capacity0 > 0); - PowerProfile powerProfile = PowerProfile.init(mContext); Assert.assertNotNull(powerProfile); Assert.assertTrue(powerProfile.isSupported()); double capacity1 = powerProfile.getBatteryCapacity(); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 5d02ff001..1efbf0068 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -461,6 +461,12 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas } return snapshot; } + if (snapshotClass == JiffiesMonitorFeature.UidJiffiesSnapshot.class) { + JiffiesMonitorFeature feat = getFeature(JiffiesMonitorFeature.class); + if (feat != null) { + return feat.currentUidJiffiesSnapshot(); + } + } if (snapshotClass == LocationMonitorFeature.LocationSnapshot.class) { LocationMonitorFeature feature = getFeature(LocationMonitorFeature.class); if (feature != null) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java index 7dc42f4c0..7e1f42763 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java @@ -669,17 +669,14 @@ public static int getBatteryCapacity(Context context) { @SuppressWarnings("ConstantConditions") @SuppressLint("PrivateApi") public static int getBatteryCapacityImmediately(Context context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - BatteryManager mBatteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE); - int chargeCounter = mBatteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER); - int capacity = mBatteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); - if (chargeCounter > 0 && capacity > 0) { - return (int) (((chargeCounter / (float) capacity) * 100) / 1000); + /* + * Matrix PowerProfile (static) >> OS PowerProfile (static) >> BatteryManager (dynamic) + */ + try { + if (PowerProfile.getResType().equals("framework") || PowerProfile.getResType().equals("custom")) { + return (int) PowerProfile.init(context).getBatteryCapacity(); } - } - - if (PowerProfile.getInstance() != null) { - return (int) PowerProfile.getInstance().getBatteryCapacity(); + } catch (Throwable ignored) { } try { @@ -688,14 +685,22 @@ public static int getBatteryCapacityImmediately(Context context) { Method method; try { method = profileClass.getMethod("getAveragePower", String.class); - return (int) method.invoke(profileObject, "battery.capacity"); + return (int) method.invoke(profileObject, PowerProfile.POWER_BATTERY_CAPACITY); } catch (Throwable e) { MatrixLog.w(TAG, "get PowerProfile failed: " + e.getMessage()); } method = profileClass.getMethod("getBatteryCapacity"); return (int) method.invoke(profileObject); - } catch (Throwable e) { - MatrixLog.w(TAG, "get PowerProfile failed: " + e.getMessage()); + } catch (Throwable ignored) { + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + BatteryManager mBatteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE); + int chargeCounter = mBatteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER); + int capacity = mBatteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); + if (chargeCounter > 0 && capacity > 0) { + return (int) (((chargeCounter / (float) capacity) * 100) / 1000); + } } return -1; } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java index 77ddab4ac..fbc79e1ae 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java @@ -16,12 +16,15 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.Callable; import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; +import androidx.annotation.StringDef; import androidx.annotation.VisibleForTesting; /** @@ -30,6 +33,16 @@ @RestrictTo(RestrictTo.Scope.LIBRARY) @SuppressWarnings({"JavadocReference", "ConstantConditions", "TryFinallyCanBeTryWithResources"}) public class PowerProfile { + @StringDef(value = { + "unknown", + "framework", + "custom", + "test" + }) + @Retention(RetentionPolicy.SOURCE) + @interface ResType { + } + private static final String TAG = "PowerProfile"; private static PowerProfile sInstance = null; @@ -41,7 +54,9 @@ public static PowerProfile getInstance() { public static PowerProfile init(Context context) throws IOException { synchronized (sLock) { try { - sInstance = new PowerProfile(context).smoke(); + if (sInstance == null) { + sInstance = new PowerProfile(context).smoke(); + } return sInstance; } catch (Throwable e) { throw new IOException("Compat err: " + e.getMessage(), e); @@ -305,6 +320,7 @@ public static HashMap getPowerArrayMap() { private static String mResType = "unknown"; + @ResType public static String getResType() { return mResType; } From f86184f473c05fe6e6ab132e853fcefa5f809a8b Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 28 Jul 2022 16:05:26 +0800 Subject: [PATCH 113/263] memory-canary: fix smaps entry pattern with no name entries --- .../com/tencent/matrix/memory/canary/MemInfoFactory.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt index 3d410960b..6116f654a 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt @@ -718,7 +718,7 @@ data class MergedSmapsInfo( private fun mergeSmaps(pid: Int): ArrayList { val pattern = - Pattern.compile("^[0-9a-f]+-[0-9a-f]+\\s+([rwxps-]{4})\\s+[0-9a-f]+\\s+[0-9a-f]+:[0-9a-f]+\\s+\\d+\\s+(.*)$") + Pattern.compile("^[0-9a-f]+-[0-9a-f]+\\s+([rwxps-]{4})\\s+[0-9a-f]+\\s+[0-9a-f]+:[0-9a-f]+\\s+\\d+\\s*(.*)$") val merged: HashMap = HashMap() var currentInfo: SmapsItem? = null @@ -784,7 +784,10 @@ data class MergedSmapsInfo( val matcher: Matcher = pattern.matcher(line) if (matcher.find()) { val permission = matcher.group(1) - val name = matcher.group(2) + var name = matcher.group(2) + if (name.isNullOrBlank()) { + name = "[no-name]" + } currentInfo = merged["$permission|$name"] if (currentInfo == null) { currentInfo = SmapsItem() From c16db559293d8ffeaa21f3b7952fa6f12268220d Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 28 Jul 2022 16:09:07 +0800 Subject: [PATCH 114/263] memory-canary: dump brief smaps info - break when pss < 1M --- .../java/com/tencent/matrix/memory/canary/MemInfoFactory.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt index 6116f654a..b3fc5076b 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt @@ -592,7 +592,7 @@ data class MergedSmapsInfo( ).append("\n") for ((name, permission, count, vmSize, rss, pss, sharedClean, sharedDirty, privateClean, privateDirty, swapPss) in list!!) { if (pss < 1024 /* K */) { - continue + break } sb.append( String.format( From b3b6fd09d879f9519722e375674a47ac078e730d Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 28 Jul 2022 16:24:57 +0800 Subject: [PATCH 115/263] Update composite monitors fork --- .../monitor/feature/CompositeMonitors.java | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 1efbf0068..ff1b7db33 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -95,12 +95,18 @@ public void clear() { mSampleResults.clear(); mTaskDeltas.clear(); mTaskDeltasCollect.clear(); + mExtras.clear(); + mStacks.clear(); } - @CallSuper public CompositeMonitors fork() { + return fork(new CompositeMonitors(mMonitor, mScope)); + } + + @CallSuper + protected CompositeMonitors fork(CompositeMonitors that) { MatrixLog.i(TAG, hashCode() + " #fork: " + mScope); - CompositeMonitors that = new CompositeMonitors(mMonitor, mScope); + that.clear(); that.mBgnMillis = this.mBgnMillis; that.mAppStats = this.mAppStats; @@ -108,12 +114,15 @@ public CompositeMonitors fork() { that.mBgnSnapshots.putAll(mBgnSnapshots); that.mDeltas.putAll(mDeltas); - that.mSampleRegs.putAll(mSampleRegs); - that.mSamplers.putAll(mSamplers); - that.mSampleResults.putAll(mSampleResults); + // Sampler can not be cloned. + // that.mSampleRegs.putAll(mSampleRegs); + // that.mSamplers.putAll(mSamplers); + // that.mSampleResults.putAll(mSampleResults); that.mTaskDeltas.putAll(this.mTaskDeltas); + that.mTaskDeltasCollect.putAll(this.mTaskDeltasCollect); that.mExtras.putAll(this.mExtras); + that.mStacks.putAll(this.mStacks); return that; } @@ -165,13 +174,19 @@ public int getCpuLoad() { MatrixLog.w(TAG, "AppStats should not be null to get CpuLoad"); return -1; } - Delta appJiffies = getDelta(JiffiesSnapshot.class); - if (appJiffies == null) { - MatrixLog.w(TAG, JiffiesSnapshot.class + " should be metrics to get CpuLoad"); - return -1; + long appJiffiesDelta; + Delta uidJiffies = getDelta(JiffiesMonitorFeature.UidJiffiesSnapshot.class); + if (uidJiffies != null) { + appJiffiesDelta = uidJiffies.dlt.totalUidJiffies.get(); + } else { + Delta pidJiffies = getDelta(JiffiesSnapshot.class); + if (pidJiffies == null) { + MatrixLog.w(TAG, JiffiesSnapshot.class + " should be metrics to get CpuLoad"); + return -1; + } + appJiffiesDelta = pidJiffies.dlt.totalJiffies.get(); } - long appJiffiesDelta = appJiffies.dlt.totalJiffies.get(); long cpuUptimeDelta = mAppStats.duringMillis; float cpuLoad = cpuUptimeDelta > 0 ? (float) (appJiffiesDelta * 10) / cpuUptimeDelta : 0; return (int) (cpuLoad * 100); @@ -806,6 +821,21 @@ public void getCollectedTaskDeltas(Consumer>> block) { + List> deltaList = getAllPidDeltaList(); + if (deltaList != null) { + block.accept(deltaList); + } + } + + public List> getAllPidDeltaList() { + Delta delta = getDelta(JiffiesMonitorFeature.UidJiffiesSnapshot.class); + if (delta == null) { + return Collections.emptyList(); + } + return delta.dlt.pidDeltaJiffiesList; + } + public Map getStacks() { return mStacks; } From 8c22e7b7f7a1b7dd3a3dec8404027f7b7b8849f6 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 29 Jul 2022 11:03:30 +0800 Subject: [PATCH 116/263] mallctl: add madvise api --- .../src/main/cpp/mallctl/MallCtl.cpp | 10 ++- .../com/tencent/matrix/mallctl/MallCtl.java | 70 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp b/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp index 8611bce9e..9ed4bc4bd 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp +++ b/matrix/matrix-android/matrix-mallctl/src/main/cpp/mallctl/MallCtl.cpp @@ -148,7 +148,8 @@ Java_com_tencent_matrix_mallctl_MallCtl_malloptNative(JNIEnv *env, jclass clazz) } JNIEXPORT jboolean JNICALL -Java_com_tencent_matrix_mallctl_MallCtl_setRetainNative(JNIEnv *env, jclass clazz, jboolean enable) { +Java_com_tencent_matrix_mallctl_MallCtl_setRetainNative(JNIEnv *env, jclass clazz, + jboolean enable) { #ifdef __LP64__ return true; #else @@ -162,6 +163,13 @@ Java_com_tencent_matrix_mallctl_MallCtl_setRetainNative(JNIEnv *env, jclass claz #endif } +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_mallctl_MallCtl_flushReadOnlyFilePagesNative(JNIEnv *env, jclass clazz, + jlong begin, jlong size) { + + return madvise((void *)begin, (size_t) size, MADV_DONTNEED); +} + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java index 104cb5b8d..57d310424 100644 --- a/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java +++ b/matrix/matrix-android/matrix-mallctl/src/main/java/com/tencent/matrix/mallctl/MallCtl.java @@ -21,6 +21,13 @@ import com.tencent.matrix.util.MatrixLog; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Created by Yves on 2020/7/15 */ @@ -74,6 +81,67 @@ public synchronized static int mallopt() { return MALLOPT_EXCEPTION; } + public interface TrimPrediction { + boolean canBeTrim(String pathName, String permission); + } + + public static class DefaultPrediction implements TrimPrediction { + @Override + public boolean canBeTrim(String pathName, String permission) { + if (pathName.endsWith(" (deleted)")) { + pathName = pathName.substring(0, pathName.length() - " (deleted)".length()); + } else if (pathName.endsWith("]")) { + pathName = pathName.substring(0, pathName.length() - "]".length()); + } + return !permission.contains("w") + && (pathName.endsWith(".so") + || pathName.endsWith(".dex") + || pathName.endsWith(".apk") + || pathName.endsWith(".vdex") + || pathName.endsWith(".odex") + || pathName.endsWith(".oat") + || pathName.endsWith(".art") + || pathName.endsWith(".ttf") + || pathName.endsWith(".otf") + || pathName.endsWith(".jar")); + } + } + + public synchronized static void flushReadOnlyFilePages(TrimPrediction prediction) { + if (prediction == null) { + prediction = new DefaultPrediction(); + } + Pattern pattern = Pattern.compile("^([0-9a-f]+)-([0-9a-f]+)\\s+([rwxps-]{4})\\s+[0-9a-f]+\\s+[0-9a-f]+:[0-9a-f]+\\s+\\d+\\s*(.*)$"); + try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/maps")))) { + String line = br.readLine(); + while (line != null) { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + String beginStr = matcher.group(1); + String endStr = matcher.group(2); + String permission = matcher.group(3); + String name = matcher.group(4); + if (name == null || name.isEmpty()) { + name = "[no-name]"; + } + if (prediction.canBeTrim(name, permission) && beginStr != null && endStr != null) { + try { + long beginPtr = Long.parseLong(beginStr, 16); + long endPtr = Long.parseLong(endStr, 16); + long size = endPtr - beginPtr; + flushReadOnlyFilePagesNative(beginPtr, size); + } catch (Throwable e) { + MatrixLog.printErrStackTrace(TAG, e, "%s-%s %s %s", beginStr, endStr, permission, name); + } + } + } + line = br.readLine(); + } + } catch (IOException e) { + MatrixLog.printErrStackTrace(TAG, e, ""); + } + } + @Keep private static native void initNative(); @@ -85,4 +153,6 @@ public synchronized static int mallopt() { @Keep private static native boolean setRetainNative(boolean enable); + + private static native int flushReadOnlyFilePagesNative(long begin, long size); } From 1cd67217bafe6e46af02d0d0c3c4c20e681b6a1f Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 1 Aug 2022 19:32:45 +0800 Subject: [PATCH 117/263] Update battery power profile compat --- .../monitor/feature/CompositeMonitors.java | 4 +++ .../batterycanary/utils/PowerProfile.java | 35 +++++++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index ff1b7db33..a1fec5b73 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -831,6 +831,10 @@ public void getAllPidDeltaList(Consumer>> block) { public List> getAllPidDeltaList() { Delta delta = getDelta(JiffiesMonitorFeature.UidJiffiesSnapshot.class); if (delta == null) { + Delta pidDelta = getDelta(JiffiesSnapshot.class); + if (pidDelta != null) { + return Collections.singletonList(pidDelta); + } return Collections.emptyList(); } return delta.dlt.pidDeltaJiffiesList; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java index fbc79e1ae..0a2b8e885 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java @@ -302,7 +302,11 @@ private PowerProfile(Context context) { // Read the XML file for the given profile (normally only one per device) synchronized (sLock) { if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) { - readPowerValuesCompat(context); + try { + readPowerValuesCompat(context); + } catch (IOException e) { + MatrixLog.w(TAG, "Failed to read power values: " + e); + } } initCpuClusters(); } @@ -325,14 +329,19 @@ public static String getResType() { return mResType; } - private void readPowerValuesCompat(Context context) { + private void readPowerValuesCompat(Context context) throws IOException { + Exception exception = null; try { readPowerValuesFromRes(context, "power_profile"); initCpuClusters(); smoke(); mResType = "framework"; - } catch (Exception e1) { - MatrixLog.w(TAG, "read from framework failed: " + e1); + } catch (Exception e) { + MatrixLog.w(TAG, "read from framework failed: " + e); + exception = e; + } + + if (exception != null) { Callable findBlock = new Callable() { @SuppressWarnings("checkstyle:RegexpSingleline") @Override @@ -357,13 +366,27 @@ public File call() throws FileNotFoundException { initCpuClusters(); smoke(); mResType = "custom"; - } catch (Exception e2) { - MatrixLog.w(TAG, "read from framework failed: " + e1); + } catch (Exception e) { + MatrixLog.w(TAG, "read from custom failed: " + e); + exception = e; + } + } + + if (exception != null) { + try { readPowerValuesFromRes(context, "power_profile_test"); initCpuClusters(); + smoke(); mResType = "test"; + } catch (Exception e) { + MatrixLog.w(TAG, "read from test failed: " + e); + exception = e; } } + + if (exception != null) { + throw new IOException("readPowerValuesCompat failed", exception); + } } private void readPowerValuesFromRes(Context context, String fileName) { From f189233f15ede9a966d5aa42c1b5c150919d7718 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 7 Jun 2022 17:09:47 +0800 Subject: [PATCH 118/263] lifecycle: add getMemInfo api for subordinate proceesses --- .../supervisor/ISubordinateProxy.aidl | 3 +- .../aidl/com/tencent/matrix/util/MemInfo.aidl | 6 + .../supervisor/ProcessSubordinate.kt | 12 +- .../lifecycle/supervisor/ProcessSupervisor.kt | 12 + .../tencent/matrix/util}/MemInfoFactory.kt | 272 ++++++++++++++++-- .../canary/monitor/AppBgSumPssMonitor.kt | 3 +- .../canary/monitor/ProcessBgMemoryMonitor.kt | 2 +- .../sample/tencent/matrix/MainActivity.java | 49 +++- .../sample/tencent/matrix/SplashActivity.java | 2 +- .../tencent/matrix/memory/MemInfoTest.java | 2 +- samples/sample-android/build.gradle | 2 +- .../kt/memory/canary/MemoryCanaryBoot.kt | 7 +- .../monitor/BackgroundMemoryMonitorBoot.kt | 38 ++- 13 files changed, 375 insertions(+), 35 deletions(-) create mode 100644 matrix/matrix-android/matrix-android-lib/src/main/aidl/com/tencent/matrix/util/MemInfo.aidl rename matrix/matrix-android/{matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary => matrix-android-lib/src/main/java/com/tencent/matrix/util}/MemInfoFactory.kt (78%) diff --git a/matrix/matrix-android/matrix-android-lib/src/main/aidl/com/tencent/matrix/lifecycle/supervisor/ISubordinateProxy.aidl b/matrix/matrix-android/matrix-android-lib/src/main/aidl/com/tencent/matrix/lifecycle/supervisor/ISubordinateProxy.aidl index b8b936da1..74e3fbd5b 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/aidl/com/tencent/matrix/lifecycle/supervisor/ISubordinateProxy.aidl +++ b/matrix/matrix-android/matrix-android-lib/src/main/aidl/com/tencent/matrix/lifecycle/supervisor/ISubordinateProxy.aidl @@ -2,11 +2,12 @@ package com.tencent.matrix.lifecycle.supervisor; // Declare any non-default types here with import statements +import com.tencent.matrix.util.MemInfo; interface ISubordinateProxy { void dispatchState(in String scene, in String stateName, in boolean state); void dispatchKill(in String scene, in String targetProcess, in int targetPid); void dispatchDeath(in String scene, in String targetProcess, in int targetPid, in boolean isLruKill); - int getPss(); + MemInfo getMemInfo(); } \ No newline at end of file diff --git a/matrix/matrix-android/matrix-android-lib/src/main/aidl/com/tencent/matrix/util/MemInfo.aidl b/matrix/matrix-android/matrix-android-lib/src/main/aidl/com/tencent/matrix/util/MemInfo.aidl new file mode 100644 index 000000000..653e6eb45 --- /dev/null +++ b/matrix/matrix-android/matrix-android-lib/src/main/aidl/com/tencent/matrix/util/MemInfo.aidl @@ -0,0 +1,6 @@ +// MemInfo.aidl +package com.tencent.matrix.util; + +// Declare any non-default types here with import statements + +parcelable MemInfo; \ No newline at end of file diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt index 4a76ff0ca..c841f8564 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt @@ -97,8 +97,12 @@ internal object ProcessSubordinate { } } - fun getPss(): Int { - return 0 + fun getMemInfo(): Array { + val memInfoList = ArrayList() + subordinateProxies.forEachSafe { + memInfoList.add(it.value.memInfo) + } + return memInfoList.toTypedArray() } } @@ -243,9 +247,7 @@ internal object ProcessSubordinate { } } - override fun getPss(): Int { - TODO("Not yet implemented") - } + override fun getMemInfo(): MemInfo = MemInfo.getCurrentProcessFullMemInfo() } diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSupervisor.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSupervisor.kt index 98daaacb1..5926389bf 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSupervisor.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSupervisor.kt @@ -239,4 +239,16 @@ object ProcessSupervisor : IProcessListener by ProcessSubordinate.processListene MatrixLog.i(tag, "inCharge") } + + fun getAllProcessMemInfo() : Array? { + if (application == null) { + MatrixLog.e(tag, "Supervisor NOT initialized yet or Supervisor is disabled!!!") + return null + } + if (!isSupervisor) { + MatrixLog.e(tag, "Only support for supervisor process") + return null + } + return ProcessSubordinate.manager.getMemInfo() + } } \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt similarity index 78% rename from matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt rename to matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt index b3fc5076b..3f3d3d62f 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemInfoFactory.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt @@ -1,28 +1,18 @@ -package com.tencent.matrix.memory.canary +package com.tencent.matrix.util import android.app.ActivityManager import android.app.Application import android.content.Context -import android.os.Build -import android.os.Debug -import android.os.Process +import android.os.* import android.text.TextUtils import com.tencent.matrix.Matrix import com.tencent.matrix.lifecycle.owners.ProcessUILifecycleOwner import com.tencent.matrix.lifecycle.owners.ProcessUIStartedStateOwner import com.tencent.matrix.lifecycle.supervisor.ProcessSupervisor -import com.tencent.matrix.util.MatrixLog -import com.tencent.matrix.util.MatrixUtil -import com.tencent.matrix.util.safeApply -import com.tencent.matrix.util.safeLet - import org.json.JSONObject import java.io.File -import java.lang.StringBuilder -import java.util.* import java.util.regex.Matcher import java.util.regex.Pattern -import kotlin.collections.ArrayList private const val TAG = "Matrix.MemoryInfoFactory" @@ -63,7 +53,15 @@ data class ProcessInfo( val activity: String = ProcessUILifecycleOwner.recentScene.substringAfterLast('.'), val isProcessFg: Boolean = ProcessUIStartedStateOwner.active(), val isAppFg: Boolean = ProcessSupervisor.isAppUIForeground -) { +) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readInt(), + parcel.readString() ?: "default", + parcel.readString() ?: "default", + parcel.readByte() != 0.toByte(), + parcel.readByte() != 0.toByte() + ) + override fun toString(): String { return String.format( "%-21s\t%-21s %-21s %-21s", @@ -83,6 +81,28 @@ data class ProcessInfo( put("isAppFg", isAppFg) } } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeInt(pid) + parcel.writeString(name) + parcel.writeString(activity) + parcel.writeByte(if (isProcessFg) 1 else 0) + parcel.writeByte(if (isAppFg) 1 else 0) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): ProcessInfo { + return ProcessInfo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } data class PssInfo( @@ -95,7 +115,19 @@ data class PssInfo( var pssCodeK: Int = -1, var pssStackK: Int = -1, var pssPrivateOtherK: Int = -1 -) { +) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt() + ) + override fun toString(): String { return String.format( "%-21s %-21s %-21s %-21s %-21s %-21s %-21s %-21s %-21s", @@ -173,6 +205,33 @@ data class PssInfo( } } } + + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): PssInfo { + return PssInfo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeInt(totalPssK) + parcel.writeInt(pssJavaK) + parcel.writeInt(pssNativeK) + parcel.writeInt(pssGraphicK) + parcel.writeInt(pssSystemK) + parcel.writeInt(pssSwapK) + parcel.writeInt(pssCodeK) + parcel.writeInt(pssStackK) + parcel.writeInt(pssPrivateOtherK) + } + + override fun describeContents(): Int { + return 0 } } @@ -185,7 +244,18 @@ data class StatusInfo( val threads: Int = -1, val oomAdj: Int = -1, val oomScoreAdj: Int = -1 -) { +) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString() ?: "default", + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt(), + parcel.readInt() + ) + override fun toString(): String { return String.format( "%-21s %-21s %-21s %-21s %-21s %-21s %-21s %-21s", @@ -271,6 +341,32 @@ data class StatusInfo( return emptyMap() } + + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): StatusInfo { + return StatusInfo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(state) + parcel.writeInt(fdSize) + parcel.writeInt(vmSizeK) + parcel.writeInt(vmRssK) + parcel.writeInt(vmSwapK) + parcel.writeInt(threads) + parcel.writeInt(oomAdj) + parcel.writeInt(oomScoreAdj) + } + + override fun describeContents(): Int { + return 0 } } @@ -281,7 +377,16 @@ data class JavaMemInfo( val maxByte: Long = Runtime.getRuntime().maxMemory(), val memClass: Int = MemInfoFactory.memClass, val largeMemClass: Int = MemInfoFactory.largeMemClass -) { +) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readLong(), + parcel.readLong(), + parcel.readLong(), + parcel.readLong(), + parcel.readInt(), + parcel.readInt() + ) + override fun toString(): String { return String.format( "%-21s %-21s %-21s %-21s %-21s %-21s", @@ -304,13 +409,42 @@ data class JavaMemInfo( put("largeMemClass", largeMemClass) } } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeLong(heapSizeByte) + parcel.writeLong(recycledByte) + parcel.writeLong(usedByte) + parcel.writeLong(maxByte) + parcel.writeInt(memClass) + parcel.writeInt(largeMemClass) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): JavaMemInfo { + return JavaMemInfo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } data class NativeMemInfo( val heapSizeByte: Long = Debug.getNativeHeapSize(), val recycledByte: Long = Debug.getNativeHeapFreeSize(), val usedByte: Long = Debug.getNativeHeapAllocatedSize() -) { +) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readLong(), + parcel.readLong(), + parcel.readLong() + ) + override fun toString(): String { return String.format( "%-21s %-21s %-21s", @@ -327,6 +461,26 @@ data class NativeMemInfo( put("heapSize", heapSizeByte) } } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeLong(heapSizeByte) + parcel.writeLong(recycledByte) + parcel.writeLong(usedByte) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): NativeMemInfo { + return NativeMemInfo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } data class SystemInfo( @@ -334,7 +488,7 @@ data class SystemInfo( val availMemByte: Long = -1, val lowMemory: Boolean = false, val thresholdByte: Long = -1 -) { +) : Parcelable { companion object { fun get(): SystemInfo { val info = ActivityManager.MemoryInfo() @@ -346,8 +500,26 @@ data class SystemInfo( thresholdByte = info.threshold ) } + + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): SystemInfo { + return SystemInfo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } + constructor(parcel: Parcel) : this( + parcel.readLong(), + parcel.readLong(), + parcel.readByte() != 0.toByte(), + parcel.readLong() + ) + override fun toString(): String { return String.format( "%-21s %-21s %-21s %-21s", @@ -366,6 +538,17 @@ data class SystemInfo( put("threshold", thresholdByte) } } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeLong(totalMemByte) + parcel.writeLong(availMemByte) + parcel.writeByte(if (lowMemory) 1 else 0) + parcel.writeLong(thresholdByte) + } + + override fun describeContents(): Int { + return 0 + } } data class FgServiceInfo(val fgServices: List = getRunningForegroundServices()) { @@ -374,7 +557,14 @@ data class FgServiceInfo(val fgServices: List = getRunningForegroundServ } companion object { - private fun getRunningForegroundServices(): List { + + @JvmStatic + fun getCurrentProcessFgServices() = FgServiceInfo(getRunningForegroundServices(false)) + + @JvmStatic + fun getAllProcessFgServices() = FgServiceInfo(getRunningForegroundServices(true)) + + private fun getRunningForegroundServices(allProcess: Boolean = false): List { val fgServices = ArrayList() val runningServiceInfoList: List = safeLet(TAG, true, defVal = emptyList()) { @@ -384,7 +574,7 @@ data class FgServiceInfo(val fgServices: List = getRunningForegroundServ if (serviceInfo.uid != Process.myUid()) { continue } - if (serviceInfo.pid != Process.myPid()) { + if (!allProcess && serviceInfo.pid != Process.myPid()) { continue } if (serviceInfo.foreground) { @@ -405,8 +595,22 @@ data class MemInfo( var amsPssInfo: PssInfo? = null, var debugPssInfo: PssInfo? = null, var fgServiceInfo: FgServiceInfo? = FgServiceInfo() -) { +) : Parcelable { var cost = 0L + + constructor(parcel: Parcel) : this( + parcel.readParcelable(ProcessInfo::class.java.classLoader), + parcel.readParcelable(StatusInfo::class.java.classLoader), + parcel.readParcelable(JavaMemInfo::class.java.classLoader), + parcel.readParcelable(NativeMemInfo::class.java.classLoader), + parcel.readParcelable(SystemInfo::class.java.classLoader), + parcel.readParcelable(PssInfo::class.java.classLoader), + parcel.readParcelable(PssInfo::class.java.classLoader), + null + ) { + cost = parcel.readLong() + } + override fun toString(): String { return "\n" + """ |>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MemInfo <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -535,6 +739,32 @@ data class MemInfo( } return memoryInfoList.toTypedArray() } + + @JvmField + val CREATOR = object : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): MemInfo { + return MemInfo(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeParcelable(processInfo, flags) + parcel.writeParcelable(statusInfo, flags) + parcel.writeParcelable(javaMemInfo, flags) + parcel.writeParcelable(nativeMemInfo, flags) + parcel.writeParcelable(systemInfo, flags) + parcel.writeParcelable(amsPssInfo, flags) + parcel.writeParcelable(debugPssInfo, flags) + parcel.writeLong(cost) + } + + override fun describeContents(): Int { + return 0 } } diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt index 326ab49c1..2e6f1aad1 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt @@ -3,7 +3,8 @@ package com.tencent.matrix.memory.canary.monitor import com.tencent.matrix.lifecycle.IBackgroundStatefulOwner import com.tencent.matrix.lifecycle.IStateObserver import com.tencent.matrix.lifecycle.supervisor.AppStagedBackgroundOwner -import com.tencent.matrix.memory.canary.MemInfo +import com.tencent.matrix.lifecycle.supervisor.ProcessSupervisor +import com.tencent.matrix.util.MemInfo import com.tencent.matrix.util.MatrixHandlerThread import com.tencent.matrix.util.MatrixLog import java.util.concurrent.TimeUnit diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/ProcessBgMemoryMonitor.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/ProcessBgMemoryMonitor.kt index bfcfc2a3f..dd76dcc20 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/ProcessBgMemoryMonitor.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/ProcessBgMemoryMonitor.kt @@ -3,7 +3,7 @@ package com.tencent.matrix.memory.canary.monitor import com.tencent.matrix.lifecycle.IStateObserver import com.tencent.matrix.lifecycle.IBackgroundStatefulOwner import com.tencent.matrix.lifecycle.owners.ProcessStagedBackgroundOwner -import com.tencent.matrix.memory.canary.MemInfo +import com.tencent.matrix.util.MemInfo import com.tencent.matrix.util.MatrixHandlerThread import com.tencent.matrix.util.MatrixLog import java.util.concurrent.TimeUnit diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/MainActivity.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/MainActivity.java index 66cbcab5a..5f240fc76 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/MainActivity.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/MainActivity.java @@ -31,12 +31,18 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import com.tencent.matrix.lifecycle.IMatrixForegroundCallback; import com.tencent.matrix.lifecycle.owners.OverlayWindowLifecycleOwner; -import com.tencent.matrix.memory.canary.MemInfo; +import com.tencent.matrix.lifecycle.supervisor.AppUIForegroundOwner; +import com.tencent.matrix.lifecycle.supervisor.ProcessSupervisor; +import com.tencent.matrix.util.MemInfo; import com.tencent.matrix.trace.view.FrameDecorator; import com.tencent.matrix.util.MatrixLog; import com.tencent.matrix.util.ViewDumper; +import org.json.JSONArray; +import org.json.JSONObject; + import sample.tencent.matrix.battery.TestBatteryActivity; import sample.tencent.matrix.hooks.TestHooksActivity; import sample.tencent.matrix.io.TestIOActivity; @@ -72,6 +78,20 @@ public void run() { } }, 3000); + + new Thread(new Runnable() { + @Override + public void run() { + MemInfo[] infoArr = ProcessSupervisor.INSTANCE.getAllProcessMemInfo(); + if (infoArr == null) { + MatrixLog.d(TAG, "main info == null"); + return; + } + for (MemInfo memInfo : infoArr) { + MatrixLog.d(TAG, "%s", memInfo); + } + } + }).start(); } @Override @@ -174,6 +194,33 @@ public static class StubService extends Service { public IBinder onBind(Intent intent) { return null; } + + @Override + public void onCreate() { + super.onCreate(); + AppUIForegroundOwner.INSTANCE.addLifecycleCallback(new IMatrixForegroundCallback() { + @Override + public void onEnterForeground() { + + } + + @Override + public void onExitForeground() { + MatrixLog.d(TAG, "dump mem info"); + MemInfo[] infoArr = ProcessSupervisor.INSTANCE.getAllProcessMemInfo(); + if (infoArr == null) { + MatrixLog.d(TAG, "supervisor info == null"); + return; + } + JSONArray array = new JSONArray(); + for (MemInfo memInfo : infoArr) { + MatrixLog.d(TAG, "%s", memInfo.toJson()); + array.put(memInfo.toJson()); + } + MatrixLog.d(TAG, "=====\n%s", array.toString()); + } + }); + } } public void testSupervisor(View view) { diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/SplashActivity.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/SplashActivity.java index 76126e1c2..eba6530ba 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/SplashActivity.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/SplashActivity.java @@ -24,7 +24,7 @@ import androidx.appcompat.app.AppCompatActivity; -import com.tencent.matrix.memory.canary.MemInfo; +import com.tencent.matrix.util.MemInfo; import com.tencent.matrix.util.MatrixLog; import sample.tencent.matrix.lifecycle.LifecycleTest; diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/memory/MemInfoTest.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/memory/MemInfoTest.java index 1ae05517c..a265657a5 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/memory/MemInfoTest.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/memory/MemInfoTest.java @@ -1,6 +1,6 @@ package sample.tencent.matrix.memory; -import com.tencent.matrix.memory.canary.MemInfo; +import com.tencent.matrix.util.MemInfo; import com.tencent.matrix.util.MatrixLog; import java.util.Arrays; diff --git a/samples/sample-android/build.gradle b/samples/sample-android/build.gradle index 40c5512de..1c9877c97 100644 --- a/samples/sample-android/build.gradle +++ b/samples/sample-android/build.gradle @@ -7,7 +7,7 @@ buildscript { buildToolsVersion = '29.0.2' javaVersion = JavaVersion.VERSION_1_8 - MATRIX_VERSION = "2.0.8" + MATRIX_VERSION = "2.0.8-SNAPSHOT" GROUP = 'com.tencent.matrix' VERSION_NAME = "${MATRIX_VERSION}" diff --git a/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/MemoryCanaryBoot.kt b/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/MemoryCanaryBoot.kt index 89815ccad..a08113869 100644 --- a/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/MemoryCanaryBoot.kt +++ b/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/MemoryCanaryBoot.kt @@ -21,7 +21,12 @@ class MemoryCanaryBoot { ), processBgMemoryMonitorConfigs = arrayOf( BackgroundMemoryMonitorBoot.procStagedBgMemoryMonitorConfig, - BackgroundMemoryMonitorBoot.procDeepBgMemoryMonitorConfig + BackgroundMemoryMonitorBoot.procDeepBgMemoryMonitorConfig, + + BackgroundMemoryMonitorBoot.procStagedBgMemoryMonitorConfig2, + BackgroundMemoryMonitorBoot.procStagedBgMemoryMonitorConfig3, + BackgroundMemoryMonitorBoot.procStagedBgMemoryMonitorConfig4, + BackgroundMemoryMonitorBoot.procStagedBgMemoryMonitorConfig5, ) ) } diff --git a/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/monitor/BackgroundMemoryMonitorBoot.kt b/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/monitor/BackgroundMemoryMonitorBoot.kt index e38385c21..38a7e398c 100644 --- a/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/monitor/BackgroundMemoryMonitorBoot.kt +++ b/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/monitor/BackgroundMemoryMonitorBoot.kt @@ -4,7 +4,7 @@ import com.tencent.matrix.lifecycle.owners.ProcessDeepBackgroundOwner import com.tencent.matrix.lifecycle.owners.ProcessStagedBackgroundOwner import com.tencent.matrix.lifecycle.supervisor.AppDeepBackgroundOwner import com.tencent.matrix.lifecycle.supervisor.AppStagedBackgroundOwner -import com.tencent.matrix.memory.canary.MemInfo +import com.tencent.matrix.util.MemInfo import com.tencent.matrix.memory.canary.monitor.AppBgSumPssMonitorConfig import com.tencent.matrix.memory.canary.monitor.ProcessBgMemoryMonitorConfig import com.tencent.matrix.util.MatrixLog @@ -45,6 +45,42 @@ object BackgroundMemoryMonitorBoot { bgStatefulOwner = ProcessStagedBackgroundOwner, checkInterval = 20 * 1000L, javaThresholdByte = 10 * 1000L, + nativeThresholdByte = Long.MAX_VALUE, + checkTimes = 1 + ) + + internal val procStagedBgMemoryMonitorConfig2 = ProcessBgMemoryMonitorConfig( + callback = procBgMemCallback, + bgStatefulOwner = ProcessStagedBackgroundOwner, + checkInterval = 20 * 1000L, + javaThresholdByte = Long.MAX_VALUE, + nativeThresholdByte = 10 * 1024L, + checkTimes = 1 + ) + + internal val procStagedBgMemoryMonitorConfig3 = ProcessBgMemoryMonitorConfig( + callback = procBgMemCallback, + bgStatefulOwner = ProcessStagedBackgroundOwner, + checkInterval = 30 * 1000L, + javaThresholdByte = 10 * 1000L, + nativeThresholdByte = Long.MAX_VALUE, + checkTimes = 1 + ) + + internal val procStagedBgMemoryMonitorConfig4 = ProcessBgMemoryMonitorConfig( + callback = procBgMemCallback, + bgStatefulOwner = ProcessStagedBackgroundOwner, + checkInterval = 30 * 1000L, + javaThresholdByte = Long.MAX_VALUE, + nativeThresholdByte = 10 * 1024L, + checkTimes = 1 + ) + + internal val procStagedBgMemoryMonitorConfig5 = ProcessBgMemoryMonitorConfig( + callback = procBgMemCallback, + bgStatefulOwner = ProcessStagedBackgroundOwner, + checkInterval = 40 * 1000L, + javaThresholdByte = Long.MAX_VALUE, nativeThresholdByte = 10 * 1024L, checkTimes = 1 ) From 0b399c3c26b66be70b0ebee01e370a9cbe65b1a2 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 7 Jun 2022 20:08:41 +0800 Subject: [PATCH 119/263] memory-canary: merge dumps of AppBgSumPssMonitor --- .../memory/canary/MemoryCanaryPlugin.kt | 4 +- .../canary/monitor/AppBgSumPssMonitor.kt | 85 ++++++++++++++----- 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemoryCanaryPlugin.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemoryCanaryPlugin.kt index d44283b70..7dc9a908e 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemoryCanaryPlugin.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/MemoryCanaryPlugin.kt @@ -47,9 +47,7 @@ class MemoryCanaryPlugin( if (isSupervisor) { MatrixLog.d(tag, "supervisor is ${MatrixUtil.getProcessName(application)}") - appBgSumPssMonitorConfigs.forEach { - AppBgSumPssMonitor(it).init() - } + AppBgSumPssMonitor.init(appBgSumPssMonitorConfigs) } processBgMemoryMonitorConfigs.forEach { ProcessBgMemoryMonitor(it).init() diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt index 2e6f1aad1..3f51defca 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt @@ -1,12 +1,12 @@ package com.tencent.matrix.memory.canary.monitor import com.tencent.matrix.lifecycle.IBackgroundStatefulOwner -import com.tencent.matrix.lifecycle.IStateObserver +import com.tencent.matrix.lifecycle.IMatrixBackgroundCallback import com.tencent.matrix.lifecycle.supervisor.AppStagedBackgroundOwner import com.tencent.matrix.lifecycle.supervisor.ProcessSupervisor -import com.tencent.matrix.util.MemInfo import com.tencent.matrix.util.MatrixHandlerThread import com.tencent.matrix.util.MatrixLog +import com.tencent.matrix.util.MemInfo import java.util.concurrent.TimeUnit private const val TAG = "Matrix.monitor.AppBgSumPssMonitor" @@ -18,58 +18,101 @@ class AppBgSumPssMonitorConfig( val enable: Boolean = true, val bgStatefulOwner: IBackgroundStatefulOwner = AppStagedBackgroundOwner, val checkInterval: Long = TimeUnit.MINUTES.toMillis(3), - thresholdKB: Long = 2 * 1024 * 1024L + 500 * 1024L, // 2.5G + amsPssThresholdKB: Long = 2 * 1024 * 1024L + 500 * 1024L, // 2.5G + debugPssThresholdKB: Long = 2 * 1024 * 1024L + 500 * 1024L, // 2.5G checkTimes: Int = 3, - val callback: (sumPssKB: Int, Array) -> Unit = { sumPssKB, memInfos -> + val callback: (amsPssSumKB: Int, debugPssSumKB: Int, amsMemInfos: Array, debugMemInfos: Array) -> Unit = { amsSumPssKB, debugSumPssKB, amsMemInfos, debugMemInfos -> MatrixLog.e( TAG, - "sum pss of all process over threshold: $sumPssKB KB, detail: ${memInfos.contentToString()}" + "sum pss of all process over threshold: amsSumPss = $amsSumPssKB KB, debugSumPss = $debugSumPssKB KB " + + "amsMemDetail: ${amsMemInfos.contentToString()}" + + "\n==========\n" + + "debugMemDetail: ${debugMemInfos.contentToString()}" ) } ) { - internal val thresholdKB = thresholdKB.asThreshold(checkTimes, TimeUnit.MINUTES.toMillis(5)) + internal val amsPssThresholdKB = + amsPssThresholdKB.asThreshold(checkTimes, TimeUnit.MINUTES.toMillis(5)) + internal val debugPssThresholdKB = debugPssThresholdKB.asThreshold(checkTimes) + + // internal val override fun toString(): String { - return "AppBgSumPssMonitorConfig(enable=$enable, bgStatefulOwner=$bgStatefulOwner, checkInterval=$checkInterval, callback=${callback.javaClass.name}, thresholdKB=$thresholdKB)" + return "AppBgSumPssMonitorConfig(enable=$enable, bgStatefulOwner=$bgStatefulOwner, checkInterval=$checkInterval, callback=${callback.javaClass.name}, thresholdKB=$amsPssThresholdKB)" } } internal class AppBgSumPssMonitor( - private val config: AppBgSumPssMonitorConfig + private val checkInterval: Long, + private val bgStatefulOwner: IBackgroundStatefulOwner, + private val configs: Array ) { + companion object { + fun init(configs: Array) { + configs.groupBy { cfg -> cfg.checkInterval }.forEach { e -> + e.value.groupBy { it.bgStatefulOwner }.forEach { e2 -> + AppBgSumPssMonitor(e.key, e2.key, e2.value.toTypedArray()).start() + } + } + } + } private val checkTask = Runnable { check() } private val runningHandler = MatrixHandlerThread.getDefaultHandler() - fun init() { - MatrixLog.i(TAG, "$config") - if (!config.enable) { + private fun start() { + MatrixLog.i(TAG, configs.contentToString()) + if (configs.none { it.enable }) { + MatrixLog.i(TAG, "none enabled") return } - config.bgStatefulOwner.observeForever(object : IStateObserver { - override fun off() { // app foreground - runningHandler.removeCallbacks(checkTask) + + bgStatefulOwner.addLifecycleCallback(object : IMatrixBackgroundCallback() { + override fun onEnterBackground() { + runningHandler.postDelayed(checkTask, checkInterval) } - override fun on() { // app background - runningHandler.postDelayed(checkTask, config.checkInterval) + override fun onExitBackground() { + runningHandler.removeCallbacks(checkTask) } }) } private fun check() { - val memInfos = MemInfo.getAllProcessPss() + val amsMemInfos = MemInfo.getAllProcessPss() + val debugMemInfos = ProcessSupervisor.getAllProcessMemInfo() ?: emptyArray() - val sum = memInfos.onEach { info -> + val amsPssSum = amsMemInfos.onEach { info -> MatrixLog.i( TAG, "${info.processInfo?.pid}-${info.processInfo?.name}: ${info.amsPssInfo!!.totalPssK} KB" ) }.sumBy { it.amsPssInfo!!.totalPssK }.also { MatrixLog.i(TAG, "sumPss = $it KB") } - MatrixLog.i(TAG, "check end sum = $sum ${memInfos.contentToString()}") + val debugPssSum = debugMemInfos.onEach { + MatrixLog.i( + TAG, + "${it.processInfo?.pid}-${it.processInfo?.name}: dbgPss = ${it.debugPssInfo!!.totalPssK} KB, amsPss = ${it.amsPssInfo!!.totalPssK} KB" + ) + }.sumBy { it.debugPssInfo!!.totalPssK }.also { MatrixLog.i(TAG, "ipc sumDbgPss = $it KB") } + + MatrixLog.i(TAG, "check with interval [$checkInterval] amsPssSum = $amsPssSum KB, ${amsMemInfos.contentToString()}") + MatrixLog.i(TAG, "check with interval [$checkInterval] debugPssSum = $debugPssSum KB, ${debugMemInfos.contentToString()}") - config.thresholdKB.check(sum.toLong()) { - config.callback.invoke(sum, memInfos) + configs.forEach { config -> + var shouldCallback = false + + val overThreshold = config.run { + // @formatter:off + arrayOf("amsPss" to amsPssThresholdKB.check(amsPssSum.toLong()) { shouldCallback = true }, + "debugPss" to debugPssThresholdKB.check(debugPssSum.toLong()) { shouldCallback = true } + ).onEach { MatrixLog.i(TAG, "is over threshold? $it") }.any { it.second } + // @formatter:on + } + + if (overThreshold && shouldCallback) { + MatrixLog.i(TAG, "report over threshold") + config.callback.invoke(amsPssSum, debugPssSum, amsMemInfos, debugMemInfos) + } } } } \ No newline at end of file From a9be8edb0d84cf586b1fb430ca9b5287ec2551dc Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 3 Aug 2022 16:01:41 +0800 Subject: [PATCH 120/263] Update battery cpu power calc --- .../stats/HealthStatsHelper.java | 160 +++++++++++++++--- 1 file changed, 137 insertions(+), 23 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index c29306529..f5870dddd 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -24,6 +24,7 @@ import androidx.annotation.ChecksSdkIntAtLeast; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import androidx.annotation.VisibleForTesting; /** * totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + @@ -128,42 +129,144 @@ public static double calcCpuPower(PowerProfile powerProfile, HealthStats healthS * + core_power.cluster1 * num running cores in cluster 1 */ long cpuTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); - power = estimateCpuPowerByCpuStats(powerProfile, cpuTimeMs); + power += estimateCpuActivePower(powerProfile, cpuTimeMs); + CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); + if (feat != null && feat.isSupported()) { + CpuStatFeature.CpuStateSnapshot snapshot = feat.currentCpuStateSnapshot(); + if (snapshot != null) { + power += estimateCpuClustersPowerByUidStats(powerProfile, snapshot, cpuTimeMs, false); + power += estimateCpuCoresPowerByUidStats(powerProfile, snapshot, cpuTimeMs, false); + } + } } return power; } - private static double estimateCpuPowerByCpuStats(PowerProfile powerProfile, long cpuTimeMs) { + @VisibleForTesting + public static double estimateCpuActivePower(PowerProfile powerProfile, long cpuTimeMs) { + //noinspection UnnecessaryLocalVariable + long timeMs = cpuTimeMs; + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_CPU_ACTIVE); + return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + + @VisibleForTesting + public static double estimateCpuClustersPowerByUidStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { if (cpuTimeMs > 0) { - CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); - if (feat != null && feat.isSupported()) { - CpuStatFeature.CpuStateSnapshot cpuStateSnapshot = feat.currentCpuStateSnapshot(); - if (cpuStateSnapshot != null) { - long jiffySum = 0; - for (MonitorFeature.Snapshot.Entry.ListEntry> stepJiffies : cpuStateSnapshot.procCpuCoreStates) { - for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies.getList()) { - jiffySum += item.get(); - } - } - double powerMah = 0; - for (int i = 0; i < cpuStateSnapshot.procCpuCoreStates.size(); i++) { - List> stepJiffies = cpuStateSnapshot.procCpuCoreStates.get(i).getList(); - for (int j = 0; j < stepJiffies.size(); j++) { - long jiffy = stepJiffies.get(j).get(); - long figuredCpuTimeMs = (long) ((jiffy * 1.0f / jiffySum) * cpuTimeMs); - double powerMa = powerProfile.getAveragePowerForCpuCore(i, j); - powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); - } + long jiffySum = 0; + for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { + List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); + int scale = scaled ? powerProfile.getNumCoresInCpuCluster(i) : 1; + for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies) { + jiffySum += item.get() * scale; + } + } + double powerMah = 0; + for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { + List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); + int scale = scaled ? powerProfile.getNumCoresInCpuCluster(i) : 1; + long jiffySumInCluster = 0; + for (int j = 0; j < stepJiffies.size(); j++) { + long jiffy = stepJiffies.get(j).get(); + jiffySumInCluster += jiffy * scale; + } + long figuredCpuTimeMs = (long) ((jiffySumInCluster * 1.0f / jiffySum) * cpuTimeMs); + double powerMa = powerProfile.getAveragePowerForCpuCluster(i); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); + } + return powerMah; + } + return 0; + } + + @VisibleForTesting + public static double estimateCpuCoresPowerByUidStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { + if (cpuTimeMs > 0) { + long jiffySum = 0; + for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { + List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); + int scale = scaled ? powerProfile.getNumCoresInCpuCluster(i) : 1; + for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies) { + jiffySum += item.get() * scale; + } + } + double powerMah = 0; + for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { + List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); + int scale = scaled ? powerProfile.getNumCoresInCpuCluster(i) : 1; + for (int j = 0; j < stepJiffies.size(); j++) { + long jiffy = stepJiffies.get(j).get(); + long figuredCpuTimeMs = (long) ((jiffy * scale * 1.0f / jiffySum) * cpuTimeMs); + double powerMa = powerProfile.getAveragePowerForCpuCore(i, j); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); + } + } + return powerMah; + } + return 0; + } + + @VisibleForTesting + public static double estimateCpuClustersPowerByDevStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs) { + if (cpuTimeMs > 0) { + long jiffySum = 0; + for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { + List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); + for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies) { + jiffySum += item.get(); + } + } + double powerMah = 0; + for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { + List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); + long jiffySumInCluster = 0; + for (int j = 0; j < stepJiffies.size(); j++) { + long jiffy = stepJiffies.get(j).get(); + jiffySumInCluster += jiffy; + } + long figuredCpuTimeMs = (long) ((jiffySumInCluster * 1.0f / jiffySum) * cpuTimeMs); + int clusterNum = powerProfile.getClusterByCpuNum(i); + if (clusterNum >= 0 && clusterNum < powerProfile.getNumCpuClusters()) { + double powerMa = powerProfile.getAveragePowerForCpuCluster(clusterNum); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); + } + } + return powerMah; + } + return 0; + } + + @VisibleForTesting + public static double estimateCpuCoresPowerByDevStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs) { + if (cpuTimeMs > 0) { + long jiffySum = 0; + for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { + List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); + for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies) { + jiffySum += item.get(); + } + } + double powerMah = 0; + for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { + List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); + for (int j = 0; j < stepJiffies.size(); j++) { + long jiffy = stepJiffies.get(j).get(); + long figuredCpuTimeMs = (long) ((jiffy * 1.0f / jiffySum) * cpuTimeMs); + int clusterNum = powerProfile.getClusterByCpuNum(i); + if (clusterNum >= 0 && clusterNum < powerProfile.getNumCpuClusters()) { + double powerMa = powerProfile.getAveragePowerForCpuCore(clusterNum, j); + powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); } - return powerMah; } } + return powerMah; } return 0; } /** * WIP + * * @see com.android.internal.os.MemoryPowerCalculator */ public static double calcMemoryPower(PowerProfile powerProfile) { @@ -444,6 +547,7 @@ public static double calcScreenPower(PowerProfile powerProfile, HealthStats heal */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcSystemServicePower(PowerProfile powerProfile, HealthStats healthStats) { + double power = 0; long timeMs = 0; if (healthStats.hasTimers(UidHealthStats.TIMERS_JOBS)) { Map timers = healthStats.getTimers(UidHealthStats.TIMERS_JOBS); @@ -457,7 +561,17 @@ public static double calcSystemServicePower(PowerProfile powerProfile, HealthSta timeMs += item.getTime(); } } - return estimateCpuPowerByCpuStats(powerProfile, timeMs); + + power += estimateCpuActivePower(powerProfile, timeMs); + CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); + if (feat != null && feat.isSupported()) { + CpuStatFeature.CpuStateSnapshot snapshot = feat.currentCpuStateSnapshot(); + if (snapshot != null) { + power += estimateCpuClustersPowerByUidStats(powerProfile, snapshot, timeMs, false); + power += estimateCpuCoresPowerByUidStats(powerProfile, snapshot, timeMs, false); + } + } + return power; } /** From 0383e2e7901e633bcf12ca56dd979f119bf03596 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 3 Aug 2022 17:33:52 +0800 Subject: [PATCH 121/263] Fix ams running procs null-check errs --- .../tencent/matrix/backtrace/ProcessUtil.java | 10 +++++++--- .../batterycanary/shell/TopThreadFeature.java | 8 +++++--- .../com/tencent/matrix/memguard/MemGuard.java | 16 +++++++++------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/matrix/matrix-android/matrix-backtrace/src/main/java/com/tencent/matrix/backtrace/ProcessUtil.java b/matrix/matrix-android/matrix-backtrace/src/main/java/com/tencent/matrix/backtrace/ProcessUtil.java index db8544186..3192b6d07 100644 --- a/matrix/matrix-android/matrix-backtrace/src/main/java/com/tencent/matrix/backtrace/ProcessUtil.java +++ b/matrix/matrix-android/matrix-backtrace/src/main/java/com/tencent/matrix/backtrace/ProcessUtil.java @@ -22,6 +22,7 @@ import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.InputStream; +import java.util.List; public class ProcessUtil { @@ -41,9 +42,12 @@ private static String getProcessNameByPidImpl(final Context context, final int p } try { final ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - for (final ActivityManager.RunningAppProcessInfo i : am.getRunningAppProcesses()) { - if (i.pid == pid && i.processName != null && !i.processName.equals("")) { - return i.processName; + List processes = am.getRunningAppProcesses(); + if (processes != null) { + for (final ActivityManager.RunningAppProcessInfo i : processes) { + if (i.pid == pid && i.processName != null && !i.processName.equals("")) { + return i.processName; + } } } } catch (Exception ignore) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/TopThreadFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/TopThreadFeature.java index b6d518050..6466e8a74 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/TopThreadFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/TopThreadFeature.java @@ -157,9 +157,11 @@ public static List> getProcList(Context context) { ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); if (am != null) { List processes = am.getRunningAppProcesses(); - for (ActivityManager.RunningAppProcessInfo item : processes) { - if (item.processName.contains(context.getPackageName())) { - list.add(new Pair<>(item.pid, item.processName)); + if (processes != null) { + for (ActivityManager.RunningAppProcessInfo item : processes) { + if (item.processName.contains(context.getPackageName())) { + list.add(new Pair<>(item.pid, item.processName)); + } } } } diff --git a/matrix/matrix-android/matrix-memguard/src/main/java/com/tencent/matrix/memguard/MemGuard.java b/matrix/matrix-android/matrix-memguard/src/main/java/com/tencent/matrix/memguard/MemGuard.java index 7829c8b16..39dd2a6e8 100644 --- a/matrix/matrix-android/matrix-memguard/src/main/java/com/tencent/matrix/memguard/MemGuard.java +++ b/matrix/matrix-android/matrix-memguard/src/main/java/com/tencent/matrix/memguard/MemGuard.java @@ -455,13 +455,15 @@ private static String getProcessSuffix(@NonNull Context context) { final List runningProcs = am.getRunningAppProcesses(); final int myUid = Process.myUid(); final int myPid = Process.myPid(); - for (ActivityManager.RunningAppProcessInfo procInfo : runningProcs) { - if (procInfo.uid == myUid && procInfo.pid == myPid) { - final int colIdx = procInfo.processName.lastIndexOf(':'); - if (colIdx >= 0) { - return procInfo.processName.substring(colIdx + 1); - } else { - return "main"; + if (runningProcs != null) { + for (ActivityManager.RunningAppProcessInfo procInfo : runningProcs) { + if (procInfo.uid == myUid && procInfo.pid == myPid) { + final int colIdx = procInfo.processName.lastIndexOf(':'); + if (colIdx >= 0) { + return procInfo.processName.substring(colIdx + 1); + } else { + return "main"; + } } } } From 2a36049ab9e406534a182618c5ca124b31d46bbc Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 3 Aug 2022 17:34:03 +0800 Subject: [PATCH 122/263] Update comments --- .../stats/HealthStatsHelper.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index f5870dddd..f2b5339eb 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -153,6 +153,14 @@ public static double estimateCpuActivePower(PowerProfile powerProfile, long cpuT @VisibleForTesting public static double estimateCpuClustersPowerByUidStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { if (cpuTimeMs > 0) { + /* + * procCpuCoreStates + * [ + * [step1Jiffies, step2Jiffies ...], // Cluster 1 + * [step1Jiffies, step2Jiffies ...], // Cluster 2 + * ... + * ] + */ long jiffySum = 0; for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); @@ -182,6 +190,14 @@ public static double estimateCpuClustersPowerByUidStats(PowerProfile powerProfil @VisibleForTesting public static double estimateCpuCoresPowerByUidStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { if (cpuTimeMs > 0) { + /* + * procCpuCoreStates + * [ + * [step1Jiffies, step2Jiffies ...], // Cluster 1 + * [step1Jiffies, step2Jiffies ...], // Cluster 2 + * ... + * ] + */ long jiffySum = 0; for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); @@ -209,6 +225,14 @@ public static double estimateCpuCoresPowerByUidStats(PowerProfile powerProfile, @VisibleForTesting public static double estimateCpuClustersPowerByDevStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs) { if (cpuTimeMs > 0) { + /* + * cpuCoreStates + * [ + * [step1Jiffies, step2Jiffies ...], // CpuCore 1 + * [step1Jiffies, step2Jiffies ...], // CpuCore 2 + * ... + * ] + */ long jiffySum = 0; for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); @@ -239,6 +263,14 @@ public static double estimateCpuClustersPowerByDevStats(PowerProfile powerProfil @VisibleForTesting public static double estimateCpuCoresPowerByDevStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs) { if (cpuTimeMs > 0) { + /* + * cpuCoreStates + * [ + * [step1Jiffies, step2Jiffies ...], // CpuCore 1 + * [step1Jiffies, step2Jiffies ...], // CpuCore 2 + * ... + * ] + */ long jiffySum = 0; for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); From 07cfe4c142f216493c12011305e6ce391510ce5d Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 3 Aug 2022 19:29:36 +0800 Subject: [PATCH 123/263] Update comments --- .../matrix/batterycanary/Examples.java | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java index 3abb5e8ac..96c50be21 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java @@ -77,6 +77,12 @@ public void exampleForCpuLoad() { if (Matrix.isInstalled()) { BatteryMonitorPlugin monitor = Matrix.with().getPluginByClass(BatteryMonitorPlugin.class); if (monitor != null) { + /* + * 注意: + * 1. CompositeMonitors 设计为非线程安全, 需要做好并发控制 + * 2. #start() 和 #finish() 必须成对调用, 以下代码监控了 doSomething() 这段时间内的功耗数据 + * 3. 监控结束后可通过 CompositeMonitors 实例访问功耗数据 + */ CompositeMonitors compositor = new CompositeMonitors(monitor.core()); compositor.metric(JiffiesMonitorFeature.JiffiesSnapshot.class); compositor.start(); @@ -104,8 +110,16 @@ public void exampleForCpuFreqSampling() { if (Matrix.isInstalled()) { BatteryMonitorPlugin monitor = Matrix.with().getPluginByClass(BatteryMonitorPlugin.class); if (monitor != null) { + /* + * 注意: + * 1. CompositeMonitors 设计为非线程安全, 需要做好并发控制 + * 2. #start() 和 #finish() 必须成对调用, 以下代码监控了 doSomething() 这段时间内的功耗数据 + * 3. 监控结束后可通过 CompositeMonitors 实例访问功耗数据 + * 4. samplingIntervalMs 为采样周期, 建议取值 1minute, 最低值不应低于 5s (此处 10ms 仅为单元测试) + */ CompositeMonitors compositor = new CompositeMonitors(monitor.core()); - compositor.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 10L); + long samplingIntervalMs = 10L; + compositor.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, samplingIntervalMs); compositor.start(); doSomething(); @@ -136,9 +150,17 @@ public void exampleForCpuLoadNormalize() { if (Matrix.isInstalled()) { BatteryMonitorPlugin monitor = Matrix.with().getPluginByClass(BatteryMonitorPlugin.class); if (monitor != null) { + /* + * 注意: + * 1. CompositeMonitors 设计为非线程安全, 需要做好并发控制 + * 2. #start() 和 #finish() 必须成对调用, 以下代码监控了 doSomething() 这段时间内的功耗数据 + * 3. 监控结束后可通过 CompositeMonitors 实例访问功耗数据 + * 4. samplingIntervalMs 为采样周期, 建议取值 1minute, 最低值不应低于 5s (此处 10ms 仅为单元测试) + */ CompositeMonitors compositor = new CompositeMonitors(monitor.core()); compositor.metric(JiffiesMonitorFeature.JiffiesSnapshot.class); - compositor.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 10L); + long samplingIntervalMs = 10L; + compositor.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, samplingIntervalMs); compositor.start(); doSomething(); @@ -185,8 +207,16 @@ public void exampleForTemperatureSampling() { if (Matrix.isInstalled()) { BatteryMonitorPlugin monitor = Matrix.with().getPluginByClass(BatteryMonitorPlugin.class); if (monitor != null) { + /* + * 注意: + * 1. CompositeMonitors 设计为非线程安全, 需要做好并发控制 + * 2. #start() 和 #finish() 必须成对调用, 以下代码监控了 doSomething() 这段时间内的功耗数据 + * 3. 监控结束后可通过 CompositeMonitors 实例访问功耗数据 + * 4. samplingIntervalMs 为采样周期, 建议取值 1minute, 最低值不应低于 5s (此处 10ms 仅为单元测试) + */ CompositeMonitors compositor = new CompositeMonitors(monitor.core()); - compositor.sample(DeviceStatMonitorFeature.BatteryTmpSnapshot.class, 10L); + long samplingIntervalMs = 10L; + compositor.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, samplingIntervalMs); compositor.start(); doSomething(); From 32d01542eedc37b4e6f38ec1c2e22aa881167c25 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 3 Aug 2022 20:19:07 +0800 Subject: [PATCH 124/263] Update cpuCalculator tests --- .../batterycanary/stats/HealthStatsTest.java | 52 +++++++------------ 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 3f9f6c848..c6f2e66bb 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -251,37 +251,26 @@ public void testEstimateCpuPowerByCpuStats() throws IOException { healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS); healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); long cpuTimeMs = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + healthStats.getMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); - double powerMah = estimateCpuPowerByCpuStats(feature, cpuTimeMs); - Assert.assertTrue(powerMah >= 0); - double calcCpuPower = HealthStatsHelper.calcCpuPower(feature.getPowerProfile(), healthStats); - Assert.assertEquals(powerMah, calcCpuPower, 1d); - } + double powerMahByUid = 0, powerMahByDev = 0; + double activePower = HealthStatsHelper.estimateCpuActivePower(feature.getPowerProfile(), cpuTimeMs); + Assert.assertTrue(activePower >= 0); + powerMahByUid += activePower; + powerMahByDev += activePower; - private static double estimateCpuPowerByCpuStats(CpuStatFeature feat, long cpuTimeMs) { - if (feat != null && feat.isSupported()) { - CpuStatFeature.CpuStateSnapshot cpuStateSnapshot = feat.currentCpuStateSnapshot(); - if (cpuStateSnapshot != null) { - long jiffySum = 0; - for (MonitorFeature.Snapshot.Entry.ListEntry> stepJiffies : cpuStateSnapshot.procCpuCoreStates) { - for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies.getList()) { - jiffySum += item.get(); - } - } - double powerMah = 0; - for (int i = 0; i < cpuStateSnapshot.procCpuCoreStates.size(); i++) { - List> stepJiffies = cpuStateSnapshot.procCpuCoreStates.get(i).getList(); - for (int j = 0; j < stepJiffies.size(); j++) { - long jiffy = stepJiffies.get(j).get(); - long figuredCpuTimeMs = (long) ((jiffy * 1.0f / jiffySum) * cpuTimeMs); - double powerMa = feat.getPowerProfile().getAveragePowerForCpuCore(i, j); - powerMah += new UsageBasedPowerEstimator(powerMa).calculatePower(figuredCpuTimeMs); - } - } - return powerMah; - } - } - return 0; + + powerMahByUid += HealthStatsHelper.estimateCpuClustersPowerByUidStats(feature.getPowerProfile(), cpuStateSnapshot, cpuTimeMs, false); + Assert.assertTrue(powerMahByUid >= 0); + powerMahByUid += HealthStatsHelper.estimateCpuCoresPowerByUidStats(feature.getPowerProfile(), cpuStateSnapshot, cpuTimeMs, false); + Assert.assertTrue(powerMahByUid >= 0); + + powerMahByDev += HealthStatsHelper.estimateCpuClustersPowerByDevStats(feature.getPowerProfile(), cpuStateSnapshot, cpuTimeMs); + Assert.assertTrue(powerMahByDev >= 0); + powerMahByDev += HealthStatsHelper.estimateCpuCoresPowerByDevStats(feature.getPowerProfile(), cpuStateSnapshot, cpuTimeMs); + Assert.assertTrue(powerMahByDev >= 0); + + double calcCpuPower = HealthStatsHelper.calcCpuPower(feature.getPowerProfile(), healthStats); + Assert.assertEquals(powerMahByDev, calcCpuPower, 1d); } @Test @@ -637,10 +626,7 @@ public void testEstimateSystemServicePower() throws IOException { } } - double calcPower = estimateCpuPowerByCpuStats(feature, timeMs); - Assert.assertTrue(calcPower >= 0); - - calcPower = HealthStatsHelper.calcSystemServicePower(powerProfile, healthStats); + double calcPower = HealthStatsHelper.calcSystemServicePower(powerProfile, healthStats); Assert.assertTrue(calcPower >= 0); } From 660f0f68f55450212fb87f1250eb27305b965fe2 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 4 Aug 2022 16:41:52 +0800 Subject: [PATCH 125/263] Update battery sampler invalid value --- .../monitor/feature/SamplerTest.java | 7 +++++++ .../monitor/BatteryMonitorCore.java | 2 +- .../monitor/feature/CompositeMonitors.java | 19 ++++++++++++++++++- .../monitor/feature/MonitorFeature.java | 2 +- .../utils/BatteryCanaryUtil.java | 6 +++--- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java index 0277bc189..3a2b9f199 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java @@ -84,6 +84,13 @@ private BatteryMonitorCore mockMonitor() { return new BatteryMonitorCore(config); } + @Test + public void testInvalidSamplingResult() { + Number result = Integer.MIN_VALUE; + Assert.assertTrue(result.equals(Integer.MIN_VALUE)); + Assert.assertEquals(Integer.MIN_VALUE, result); + } + @Test public void testSampling() throws InterruptedException { final BatteryMonitorCore monitor = mockMonitor(); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java index 8bc47bf45..2114f0f1d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java @@ -292,7 +292,7 @@ public int getCurrentBatteryTemperature(Context context) { return tmp; } catch (Throwable e) { MatrixLog.printErrStackTrace(TAG, e, "#currentBatteryTemperature error"); - return 0; + return -1; } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index a1fec5b73..d0d254b32 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -568,7 +568,9 @@ public Number apply(Snapshot.Sampler sampler) { List> list = snapshot.cpuFreqs.getList(); MatrixLog.i(TAG, CompositeMonitors.this.hashCode() + " #onSampling: " + mScope); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + list); - + if (list.isEmpty()) { + return Snapshot.Sampler.INVALID; + } // Better to use sum of all cpufreqs, rather than just use the max value? // Collections.sort(list, new Comparator>() { // @Override @@ -597,6 +599,9 @@ public Number apply(Snapshot.Sampler sampler) { DeviceStatMonitorFeature.BatteryTmpSnapshot snapshot = feature.currentBatteryTemperature(mMonitor.getContext()); Integer value = snapshot.temp.get(); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); + if (value == -1) { + return Snapshot.Sampler.INVALID; + } return value; } }); @@ -612,6 +617,9 @@ public Number apply(Snapshot.Sampler sampler) { public Number apply(Snapshot.Sampler sampler) { int value = BatteryCanaryUtil.getThermalStat(mMonitor.getContext()); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); + if (value == -1) { + return Snapshot.Sampler.INVALID; + } return value; } }); @@ -629,6 +637,9 @@ public Number apply(Snapshot.Sampler sampler) { public Number apply(Snapshot.Sampler sampler) { float value = BatteryCanaryUtil.getThermalHeadroom(mMonitor.getContext(), (int) (interval / 1000L)); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); + if (value == -1f) { + return Snapshot.Sampler.INVALID; + } return value; } }); @@ -645,6 +656,9 @@ public Number apply(Snapshot.Sampler sampler) { public Number apply(Snapshot.Sampler sampler) { int value = BatteryCanaryUtil.getChargingWatt(mMonitor.getContext()); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); + if (value == -1) { + return Snapshot.Sampler.INVALID; + } return value; } }); @@ -732,6 +746,9 @@ public Number apply(Snapshot.Sampler sampler) { DeviceStatMonitorFeature.BatteryCurrentSnapshot snapshot = feature.currentBatteryCurrency(mMonitor.getContext()); Long value = snapshot.stat.get(); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); + if (value == -1L) { + return Snapshot.Sampler.INVALID; + } return value; } }); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index 85d946deb..a8f374bf9 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -420,7 +420,7 @@ public Entry.ListEntry diff(@NonNull Entry.ListEntry bgn, @NonNull public static class Sampler { private static final String TAG = "Matrix.battery.Sampler"; - public static final Number INVALID = Integer.MIN_VALUE; + public static final Integer INVALID = Integer.MIN_VALUE; final String mTag; final Handler mHandler; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java index 7e1f42763..21adc3528 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java @@ -443,7 +443,7 @@ public static int getThermalStatImmediately(Context context) { MatrixLog.w(TAG, "getCurrentThermalStatus failed: " + e.getMessage()); } } - return 0; + return -1; } public static float getThermalHeadroom(Context context, @IntRange(from = 0, to = 60) int forecastSeconds) { @@ -459,7 +459,7 @@ public static float getThermalHeadroomImmediately(Context context, int forecastS MatrixLog.w(TAG, "getThermalHeadroom failed: " + e.getMessage()); } } - return 0f; + return -1f; } public static int getChargingWatt(Context context) { @@ -478,7 +478,7 @@ public static int getChargingWattImmediately(Context context) { return (maxCurrent / 1000) * (maxVoltage / 1000) / 1000000; } } - return 0; + return -1; } @AppStats.AppStatusDef From 6885c4d70f0df7c74d3916784126126c1f02378e Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 4 Aug 2022 16:44:19 +0800 Subject: [PATCH 126/263] memory-canary: add protection for getting mem info with ipc --- .../matrix/lifecycle/supervisor/ProcessSubordinate.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt index c841f8564..aa39c7f4d 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt @@ -247,7 +247,10 @@ internal object ProcessSubordinate { } } - override fun getMemInfo(): MemInfo = MemInfo.getCurrentProcessFullMemInfo() + override fun getMemInfo(): MemInfo = safeLet( + TAG, + defVal = MemInfo(amsPssInfo = PssInfo(), debugPssInfo = PssInfo()) + ) { MemInfo.getCurrentProcessFullMemInfo() } } From ad47c93603072acf0942e067598a336db25cdc48 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 4 Aug 2022 20:51:59 +0800 Subject: [PATCH 127/263] Update cpu power calculators --- .../batterycanary/stats/HealthStatsTest.java | 2 + .../stats/HealthStatsFeature.java | 38 ++++---- .../stats/HealthStatsHelper.java | 86 ++++++++++++++----- 3 files changed, 82 insertions(+), 44 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index c6f2e66bb..85b0e27d4 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -666,6 +666,8 @@ public void testGetCurrSnapshot() { Delta delta = end.diff(bgn); Assert.assertNotNull(delta); Assert.assertNull(delta.dlt.healthStats); + + Assert.assertEquals(delta.dlt.getTotalPower(), end.getTotalPower() - bgn.getTotalPower(), 0.001d); } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 39b9480b7..664f2cd0a 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -74,23 +74,6 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.screenPower = DigitEntry.of(HealthStatsHelper.calcScreenPower(powerProfile, healthStats)); snapshot.systemServicePower = DigitEntry.of(HealthStatsHelper.calcSystemServicePower(powerProfile, healthStats)); snapshot.idlePower = DigitEntry.of(HealthStatsHelper.calcIdlePower(powerProfile, healthStats)); - - double total = snapshot.cpuPower.get() - + snapshot.wakelocksPower.get() - + snapshot.mobilePower.get() - + snapshot.wifiPower.get() - + snapshot.blueToothPower.get() - + snapshot.gpsPower.get() - + snapshot.sensorsPower.get() - + snapshot.cameraPower.get() - + snapshot.flashLightPower.get() - + snapshot.audioPower.get() - + snapshot.videoPower.get() - + snapshot.screenPower.get() - + snapshot.systemServicePower.get() - + snapshot.idlePower.get(); - - snapshot.totalPower = DigitEntry.of(total); } } @@ -276,8 +259,6 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry systemServicePower = DigitEntry.of(0D); public DigitEntry idlePower = DigitEntry.of(0D); - public DigitEntry totalPower = DigitEntry.of(0D); - // Meta Data: // CPU public DigitEntry cpuPowerMams = DigitEntry.of(0L); @@ -336,6 +317,23 @@ public static class HealthStatsSnapshot extends Snapshot { public Map> procStatsCpuSysTimeMs = Collections.emptyMap(); public Map> procStatsCpuFgTimeMs = Collections.emptyMap(); + public double getTotalPower() { + return cpuPower.get() + + wakelocksPower.get() + + mobilePower.get() + + wifiPower.get() + + blueToothPower.get() + + gpsPower.get() + + sensorsPower.get() + + cameraPower.get() + + flashLightPower.get() + + audioPower.get() + + videoPower.get() + + screenPower.get() + + systemServicePower.get() + + idlePower.get(); + } + @Override public Delta diff(HealthStatsSnapshot bgn) { return new Delta(bgn, this) { @@ -357,8 +355,6 @@ protected HealthStatsSnapshot computeDelta() { delta.systemServicePower = Differ.DigitDiffer.globalDiff(bgn.systemServicePower, end.systemServicePower); delta.idlePower = Differ.DigitDiffer.globalDiff(bgn.idlePower, end.idlePower); - delta.totalPower = Differ.DigitDiffer.globalDiff(bgn.totalPower, end.totalPower); - delta.cpuPowerMams = Differ.DigitDiffer.globalDiff(bgn.cpuPowerMams, end.cpuPowerMams); delta.cpuUsrTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuUsrTimeMs, end.cpuUsrTimeMs); delta.cpuSysTimeMs = Differ.DigitDiffer.globalDiff(bgn.cpuSysTimeMs, end.cpuSysTimeMs); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index f2b5339eb..b9d3f26f1 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -12,7 +12,9 @@ import com.tencent.matrix.batterycanary.BatteryCanary; import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature; -import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature.CpuStateSnapshot; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.ListEntry; import com.tencent.matrix.batterycanary.utils.PowerProfile; import com.tencent.matrix.util.MatrixLog; @@ -132,10 +134,10 @@ public static double calcCpuPower(PowerProfile powerProfile, HealthStats healthS power += estimateCpuActivePower(powerProfile, cpuTimeMs); CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); if (feat != null && feat.isSupported()) { - CpuStatFeature.CpuStateSnapshot snapshot = feat.currentCpuStateSnapshot(); + CpuStateSnapshot snapshot = feat.currentCpuStateSnapshot(); if (snapshot != null) { - power += estimateCpuClustersPowerByUidStats(powerProfile, snapshot, cpuTimeMs, false); - power += estimateCpuCoresPowerByUidStats(powerProfile, snapshot, cpuTimeMs, false); + power += estimateCpuClustersPower(powerProfile, snapshot, cpuTimeMs, false); + power += estimateCpuCoresPower(powerProfile, snapshot, cpuTimeMs, false); } } } @@ -151,7 +153,45 @@ public static double estimateCpuActivePower(PowerProfile powerProfile, long cpuT } @VisibleForTesting - public static double estimateCpuClustersPowerByUidStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { + public static double estimateCpuClustersPower(PowerProfile powerProfile, CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { + boolean isUidStatsAvailable = false; + for (ListEntry> listEntry : snapshot.procCpuCoreStates) { + for (DigitEntry item : listEntry.getList()) { + if (item.get() > 0) { + isUidStatsAvailable = true; + break; + } + } + } + if (isUidStatsAvailable) { + return estimateCpuClustersPowerByUidStats(powerProfile, snapshot, cpuTimeMs, scaled); + } else { + MatrixLog.i(TAG, "estimate CPU by device stats"); + return estimateCpuClustersPowerByDevStats(powerProfile, snapshot, cpuTimeMs); + } + } + + @VisibleForTesting + public static double estimateCpuCoresPower(PowerProfile powerProfile, CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { + boolean isUidStatsAvailable = false; + for (ListEntry> listEntry : snapshot.procCpuCoreStates) { + for (DigitEntry item : listEntry.getList()) { + if (item.get() > 0) { + isUidStatsAvailable = true; + break; + } + } + } + if (isUidStatsAvailable) { + return estimateCpuCoresPowerByUidStats(powerProfile, snapshot, cpuTimeMs, scaled); + } else { + MatrixLog.i(TAG, "estimate CPU by device stats"); + return estimateCpuCoresPowerByDevStats(powerProfile, snapshot, cpuTimeMs); + } + } + + @VisibleForTesting + public static double estimateCpuClustersPowerByUidStats(PowerProfile powerProfile, CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { if (cpuTimeMs > 0) { /* * procCpuCoreStates @@ -163,15 +203,15 @@ public static double estimateCpuClustersPowerByUidStats(PowerProfile powerProfil */ long jiffySum = 0; for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { - List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); + List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); int scale = scaled ? powerProfile.getNumCoresInCpuCluster(i) : 1; - for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies) { + for (DigitEntry item : stepJiffies) { jiffySum += item.get() * scale; } } double powerMah = 0; for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { - List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); + List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); int scale = scaled ? powerProfile.getNumCoresInCpuCluster(i) : 1; long jiffySumInCluster = 0; for (int j = 0; j < stepJiffies.size(); j++) { @@ -188,7 +228,7 @@ public static double estimateCpuClustersPowerByUidStats(PowerProfile powerProfil } @VisibleForTesting - public static double estimateCpuCoresPowerByUidStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { + public static double estimateCpuCoresPowerByUidStats(PowerProfile powerProfile, CpuStateSnapshot snapshot, long cpuTimeMs, boolean scaled) { if (cpuTimeMs > 0) { /* * procCpuCoreStates @@ -200,15 +240,15 @@ public static double estimateCpuCoresPowerByUidStats(PowerProfile powerProfile, */ long jiffySum = 0; for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { - List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); + List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); int scale = scaled ? powerProfile.getNumCoresInCpuCluster(i) : 1; - for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies) { + for (DigitEntry item : stepJiffies) { jiffySum += item.get() * scale; } } double powerMah = 0; for (int i = 0; i < snapshot.procCpuCoreStates.size(); i++) { - List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); + List> stepJiffies = snapshot.procCpuCoreStates.get(i).getList(); int scale = scaled ? powerProfile.getNumCoresInCpuCluster(i) : 1; for (int j = 0; j < stepJiffies.size(); j++) { long jiffy = stepJiffies.get(j).get(); @@ -223,7 +263,7 @@ public static double estimateCpuCoresPowerByUidStats(PowerProfile powerProfile, } @VisibleForTesting - public static double estimateCpuClustersPowerByDevStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs) { + public static double estimateCpuClustersPowerByDevStats(PowerProfile powerProfile, CpuStateSnapshot snapshot, long cpuTimeMs) { if (cpuTimeMs > 0) { /* * cpuCoreStates @@ -235,14 +275,14 @@ public static double estimateCpuClustersPowerByDevStats(PowerProfile powerProfil */ long jiffySum = 0; for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { - List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); - for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies) { + List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); + for (DigitEntry item : stepJiffies) { jiffySum += item.get(); } } double powerMah = 0; for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { - List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); + List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); long jiffySumInCluster = 0; for (int j = 0; j < stepJiffies.size(); j++) { long jiffy = stepJiffies.get(j).get(); @@ -261,7 +301,7 @@ public static double estimateCpuClustersPowerByDevStats(PowerProfile powerProfil } @VisibleForTesting - public static double estimateCpuCoresPowerByDevStats(PowerProfile powerProfile, CpuStatFeature.CpuStateSnapshot snapshot, long cpuTimeMs) { + public static double estimateCpuCoresPowerByDevStats(PowerProfile powerProfile, CpuStateSnapshot snapshot, long cpuTimeMs) { if (cpuTimeMs > 0) { /* * cpuCoreStates @@ -273,14 +313,14 @@ public static double estimateCpuCoresPowerByDevStats(PowerProfile powerProfile, */ long jiffySum = 0; for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { - List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); - for (MonitorFeature.Snapshot.Entry.DigitEntry item : stepJiffies) { + List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); + for (DigitEntry item : stepJiffies) { jiffySum += item.get(); } } double powerMah = 0; for (int i = 0; i < snapshot.cpuCoreStates.size(); i++) { - List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); + List> stepJiffies = snapshot.cpuCoreStates.get(i).getList(); for (int j = 0; j < stepJiffies.size(); j++) { long jiffy = stepJiffies.get(j).get(); long figuredCpuTimeMs = (long) ((jiffy * 1.0f / jiffySum) * cpuTimeMs); @@ -597,10 +637,10 @@ public static double calcSystemServicePower(PowerProfile powerProfile, HealthSta power += estimateCpuActivePower(powerProfile, timeMs); CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); if (feat != null && feat.isSupported()) { - CpuStatFeature.CpuStateSnapshot snapshot = feat.currentCpuStateSnapshot(); + CpuStateSnapshot snapshot = feat.currentCpuStateSnapshot(); if (snapshot != null) { - power += estimateCpuClustersPowerByUidStats(powerProfile, snapshot, timeMs, false); - power += estimateCpuCoresPowerByUidStats(powerProfile, snapshot, timeMs, false); + power += estimateCpuClustersPower(powerProfile, snapshot, timeMs, false); + power += estimateCpuCoresPower(powerProfile, snapshot, timeMs, false); } } return power; From 118e436f7f01e51e461cc9159c3112223a43d8d9 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 10 Aug 2022 14:35:17 +0800 Subject: [PATCH 128/263] sample: fix compile error --- .../monitor/BackgroundMemoryMonitorBoot.kt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/monitor/BackgroundMemoryMonitorBoot.kt b/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/monitor/BackgroundMemoryMonitorBoot.kt index 38a7e398c..9ee77a8db 100644 --- a/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/monitor/BackgroundMemoryMonitorBoot.kt +++ b/samples/sample-android/libkt/src/main/java/sample/tencent/matrix/kt/memory/canary/monitor/BackgroundMemoryMonitorBoot.kt @@ -16,15 +16,22 @@ object BackgroundMemoryMonitorBoot { private const val TAG = "Matrix.sample.BackgroundMemoryMonitor" - private val appBgMemCallback: (Int, Array) -> Unit = { sumPssKB, memInfos -> - MatrixLog.i(TAG, "report : $sumPssKB, ${memInfos.contentToString()}") - } + private val appBgMemCallback: (amsPssSumKB: Int, debugPssSumKB: Int, amsMemInfos: Array, debugMemInfos: Array) -> Unit = + { amsSumPssKB, debugSumPssKB, amsMemInfos, debugMemInfos -> + MatrixLog.e( + TAG, + "sum pss of all process over threshold: amsSumPss = $amsSumPssKB KB, debugSumPss = $debugSumPssKB KB " + + "amsMemDetail: ${amsMemInfos.contentToString()}" + + "\n==========\n" + + "debugMemDetail: ${debugMemInfos.contentToString()}" + ) + } internal val appStagedBgMemoryMonitorConfig = AppBgSumPssMonitorConfig( callback = appBgMemCallback, bgStatefulOwner = AppStagedBackgroundOwner, - thresholdKB = 2 * 1024L, + amsPssThresholdKB = 2 * 1024L, checkInterval = 10 * 1000L, checkTimes = 1, ) @@ -32,7 +39,7 @@ object BackgroundMemoryMonitorBoot { AppBgSumPssMonitorConfig( callback = appBgMemCallback, bgStatefulOwner = AppDeepBackgroundOwner, - thresholdKB = 2 * 1024L, + amsPssThresholdKB = 2 * 1024L, checkInterval = 10 * 1000L ) From 68d18335dbc567d2cb3f2871d69d779002ffe02a Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 11 Aug 2022 16:14:27 +0800 Subject: [PATCH 129/263] memory-canary: add triggerTrim api --- .../tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt index 4ae2afc68..63c51f39b 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/trim/TrimMemoryNotifier.kt @@ -260,4 +260,9 @@ object TrimMemoryNotifier { appTrimCallbacks.remove(callback) } } + + fun triggerTrim() { + procTrimCallbacks.backgroundTrim() + appTrimCallbacks.backgroundTrim() + } } \ No newline at end of file From 84be67daafbafb9387287aacb29fc3738f4d1685 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 11 Aug 2022 16:20:35 +0800 Subject: [PATCH 130/263] Fix battery util casting issue --- .../tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java index 21adc3528..d6e162a08 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java @@ -685,7 +685,8 @@ public static int getBatteryCapacityImmediately(Context context) { Method method; try { method = profileClass.getMethod("getAveragePower", String.class); - return (int) method.invoke(profileObject, PowerProfile.POWER_BATTERY_CAPACITY); + double capacity = (double) method.invoke(profileObject, PowerProfile.POWER_BATTERY_CAPACITY); + return (int) capacity; } catch (Throwable e) { MatrixLog.w(TAG, "get PowerProfile failed: " + e.getMessage()); } From 691c599daae84afe930fe5d26bf9308c192584fc Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 15 Aug 2022 21:19:28 +0800 Subject: [PATCH 131/263] Update battery power calc for compare --- .../stats/HealthStatsFeature.java | 18 +- .../stats/HealthStatsHelper.java | 171 +++++++++++------- 2 files changed, 121 insertions(+), 68 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 664f2cd0a..35378182c 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -46,6 +46,7 @@ public HealthStats currHealthStats() { return HealthStatsHelper.getCurrStats(mCore.getContext()); } + @SuppressLint("VisibleForTests") public HealthStatsSnapshot currHealthStatsSnapshot() { HealthStatsSnapshot snapshot = new HealthStatsSnapshot(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { @@ -60,6 +61,11 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { if (cpuStatFeat != null) { PowerProfile powerProfile = cpuStatFeat.getPowerProfile(); if (powerProfile != null && powerProfile.isSupported()) { + snapshot.mobilePowerByRadioActive = DigitEntry.of(HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats)); + snapshot.mobilePowerByController = DigitEntry.of(HealthStatsHelper.calcMobilePowerByController(powerProfile, healthStats)); + snapshot.wifiPowerByController = DigitEntry.of(HealthStatsHelper.calcWifiPowerByController(powerProfile, healthStats)); + snapshot.wifiPowerByPackets = DigitEntry.of(HealthStatsHelper.calcWifiPowerByPackets(powerProfile, healthStats)); + snapshot.cpuPower = DigitEntry.of(HealthStatsHelper.calcCpuPower(powerProfile, healthStats)); snapshot.wakelocksPower = DigitEntry.of(HealthStatsHelper.calcWakelocksPower(powerProfile, healthStats)); snapshot.mobilePower = DigitEntry.of(HealthStatsHelper.calcMobilePower(powerProfile, healthStats)); @@ -240,8 +246,11 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { } public static class HealthStatsSnapshot extends Snapshot { - @VisibleForTesting - public HealthStats healthStats; + @VisibleForTesting public HealthStats healthStats; + @VisibleForTesting public DigitEntry mobilePowerByRadioActive = DigitEntry.of(0D); + @VisibleForTesting public DigitEntry mobilePowerByController = DigitEntry.of(0D); + @VisibleForTesting public DigitEntry wifiPowerByController = DigitEntry.of(0D); + @VisibleForTesting public DigitEntry wifiPowerByPackets = DigitEntry.of(0D); // Estimated Powers public DigitEntry cpuPower = DigitEntry.of(0D); @@ -340,6 +349,11 @@ public Delta diff(HealthStatsSnapshot bgn) { @Override protected HealthStatsSnapshot computeDelta() { HealthStatsSnapshot delta = new HealthStatsSnapshot(); + delta.mobilePowerByRadioActive = Differ.DigitDiffer.globalDiff(bgn.mobilePowerByRadioActive, end.mobilePowerByRadioActive); + delta.mobilePowerByController = Differ.DigitDiffer.globalDiff(bgn.mobilePowerByController, end.mobilePowerByController); + delta.wifiPowerByController = Differ.DigitDiffer.globalDiff(bgn.wifiPowerByController, end.wifiPowerByController); + delta.wifiPowerByPackets = Differ.DigitDiffer.globalDiff(bgn.wifiPowerByPackets, end.wifiPowerByPackets); + delta.cpuPower = Differ.DigitDiffer.globalDiff(bgn.cpuPower, end.cpuPower); delta.wakelocksPower = Differ.DigitDiffer.globalDiff(bgn.wakelocksPower, end.wakelocksPower); delta.mobilePower = Differ.DigitDiffer.globalDiff(bgn.mobilePower, end.mobilePower); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index b9d3f26f1..79fe96db4 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -379,46 +379,63 @@ public static double calcMobilePower(PowerProfile powerProfile, HealthStats heal MatrixLog.i(TAG, "estimate Mobile by mams"); } if (power == 0) { - // calc from radio active - // for some aosp mistakes, radio active timer was given in time unit us: - // https://cs.android.com/android/_/android/platform/frameworks/base/+/bee44ae8e5da109cd8273a057b566dc6925d6a71 - long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE) / 1000; - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_RADIO_ACTIVE); - if (powerMa <= 0) { - double sum = 0; - sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); - int num = powerProfile.getNumElements(PowerProfile.POWER_MODEM_CONTROLLER_TX); - for (int i = 0; i < num; i++) { - sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i); - } - powerMa = sum / (num + 1); - } - power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + power = calcMobilePowerByRadioActive(powerProfile, healthStats); if (power > 0) { MatrixLog.i(TAG, "estimate Mobile by radioActive"); } } if (power == 0) { - // calc from controller - { - long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_IDLE); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - { - long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_MS); - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_RX); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - { - long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_MS); - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_TX); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + power = calcMobilePowerByController(powerProfile, healthStats); + if (power > 0) { + MatrixLog.i(TAG, "estimate Mobile by controller"); } } return power; } + @RequiresApi(api = Build.VERSION_CODES.N) + @VisibleForTesting + public static double calcMobilePowerByRadioActive(PowerProfile powerProfile, HealthStats healthStats) { + // calc from radio active + // for some aosp mistakes, radio active timer was given in time unit us: + // https://cs.android.com/android/_/android/platform/frameworks/base/+/bee44ae8e5da109cd8273a057b566dc6925d6a71 + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE) / 1000; + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_RADIO_ACTIVE); + if (powerMa <= 0) { + double sum = 0; + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); + int num = powerProfile.getNumElements(PowerProfile.POWER_MODEM_CONTROLLER_TX); + for (int i = 0; i < num; i++) { + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i); + } + powerMa = sum / (num + 1); + } + return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @VisibleForTesting + public static double calcMobilePowerByController(PowerProfile powerProfile, HealthStats healthStats) { + // calc from controller + double power = 0; + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_IDLE); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_MS); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_RX); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_MS); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_TX); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + return power; + } + /** * @see com.android.internal.os.WifiPowerCalculator */ @@ -429,50 +446,72 @@ public static double calcWifiPower(PowerProfile powerProfile, HealthStats health MatrixLog.i(TAG, "estimate WIFI by mams"); } if (power == 0) { - // calc from controller - { - double wifiIdlePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_IDLE); - long idleMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_IDLE_MS); - UsageBasedPowerEstimator etmWifiIdlePower = new UsageBasedPowerEstimator(wifiIdlePower); - power += etmWifiIdlePower.calculatePower(idleMs); - } - { - double wifiRxPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_RX); - UsageBasedPowerEstimator etmWifiRxPower = new UsageBasedPowerEstimator(wifiRxPower); - long rxMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_MS); - power += etmWifiRxPower.calculatePower(rxMs); - } - { - double wifiTxPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_TX); - long txMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_MS); - UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiTxPower); - power += etmWifiTxPower.calculatePower(txMs); + power = calcWifiPowerByController(powerProfile, healthStats); + if (power > 0) { + MatrixLog.i(TAG, "estimate WIFI by controller"); } } if (power == 0) { - // calc from packets - MatrixLog.i(TAG, "estimate WIFI by packets"); - { - final long wifiBps = 1000000; - final double averageWifiActivePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ACTIVE) / 3600; - double powerMaPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); - long packets = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS); - power += powerMaPerPacket * packets; - } - { - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ON); - long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - { - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_SCAN); - long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_WIFI_SCAN); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + power = calcWifiPowerByPackets(powerProfile, healthStats); + if (power > 0) { + MatrixLog.i(TAG, "estimate WIFI by packets"); } } return power; } + @RequiresApi(api = Build.VERSION_CODES.N) + @VisibleForTesting + public static double calcWifiPowerByController(PowerProfile powerProfile, HealthStats healthStats) { + // calc from controller + double power = 0; + { + double wifiIdlePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_IDLE); + long idleMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_IDLE_MS); + UsageBasedPowerEstimator etmWifiIdlePower = new UsageBasedPowerEstimator(wifiIdlePower); + power += etmWifiIdlePower.calculatePower(idleMs); + } + { + double wifiRxPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_RX); + UsageBasedPowerEstimator etmWifiRxPower = new UsageBasedPowerEstimator(wifiRxPower); + long rxMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_MS); + power += etmWifiRxPower.calculatePower(rxMs); + } + { + double wifiTxPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_TX); + long txMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_MS); + UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiTxPower); + power += etmWifiTxPower.calculatePower(txMs); + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @VisibleForTesting + public static double calcWifiPowerByPackets(PowerProfile powerProfile, HealthStats healthStats) { + // calc from packets + double power = 0; + MatrixLog.i(TAG, "estimate WIFI by packets"); + { + final long wifiBps = 1000000; + final double averageWifiActivePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ACTIVE) / 3600; + double powerMaPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); + long packets = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS); + power += powerMaPerPacket * packets; + } + { + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ON); + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + { + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_SCAN); + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_WIFI_SCAN); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + return power; + } + /** * @see com.android.internal.os.BluetoothPowerCalculator */ From 6bbc01f461a285641504c109e66064e39431ed3e Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 16 Aug 2022 16:32:37 +0800 Subject: [PATCH 132/263] Update battery power calculator --- .../batterycanary/stats/HealthStatsTest.java | 44 ++++- .../stats/HealthStatsFeature.java | 14 +- .../stats/HealthStatsHelper.java | 165 +++++++++--------- 3 files changed, 134 insertions(+), 89 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 85b0e27d4..4a8f3deba 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -20,6 +20,7 @@ import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorManager; +import android.os.Debug; import android.os.health.HealthStats; import android.os.health.SystemHealthManager; import android.os.health.TimerStat; @@ -34,6 +35,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; import com.tencent.matrix.batterycanary.stats.HealthStatsFeature.HealthStatsSnapshot; import com.tencent.matrix.batterycanary.utils.PowerProfile; +import com.tencent.matrix.util.MatrixLog; import org.junit.After; import org.junit.Assert; @@ -54,6 +56,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; +import static com.tencent.matrix.batterycanary.stats.HealthStatsHelper.getMeasure; +import static com.tencent.matrix.batterycanary.stats.HealthStatsHelper.getTimerTime; import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.JIFFY_MILLIS; import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_HOR; @@ -89,6 +93,17 @@ private BatteryMonitorCore mockMonitor() { return new BatteryMonitorCore(config); } + @Test + public void testRoundDecimalPlace() { + Assert.assertEquals(1.1d, HealthStatsHelper.round(1.12345d, 1), 0.00001d); + Assert.assertEquals(1.2d, HealthStatsHelper.round(1.19945d, 1), 0.00001d); + Assert.assertEquals(1.12d, HealthStatsHelper.round(1.12345d, 2), 0.00001d); + Assert.assertEquals(1.13d, HealthStatsHelper.round(1.12945d, 2), 0.00001d); + Assert.assertEquals(1.1234d, HealthStatsHelper.round(1.12341d, 4), 0.00001d); + Assert.assertEquals(1.1235d, HealthStatsHelper.round(1.12345d, 4), 0.00001d); + Assert.assertEquals(1.1200d, HealthStatsHelper.round(1.12d, 2), 0.00001d); + Assert.assertEquals(1.1200d, HealthStatsHelper.round(1.1245d, 2), 0.00001d); + } @Test public void testGetSenorsHandle() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { @@ -371,19 +386,42 @@ public void testEstimateWifiPower() throws IOException { double wifiIdlePower = powerProfile.getAveragePower("wifi.controller.idle"); - Assert.assertTrue(wifiIdlePower > 0); + Assert.assertTrue(wifiIdlePower >= 0); UsageBasedPowerEstimator etmWifiIdlePower = new UsageBasedPowerEstimator(wifiIdlePower); double wifiRxPower = powerProfile.getAveragePower("wifi.controller.rx"); - Assert.assertTrue(wifiRxPower > 0); + Assert.assertTrue(wifiRxPower >= 0); UsageBasedPowerEstimator etmWifiRxPower = new UsageBasedPowerEstimator(wifiIdlePower); double wifiTxPower = powerProfile.getAveragePower("wifi.controller.tx"); - Assert.assertTrue(wifiTxPower > 0); + Assert.assertTrue(wifiTxPower >= 0); UsageBasedPowerEstimator etmWifiTxPower = new UsageBasedPowerEstimator(wifiIdlePower); SystemHealthManager manager = (SystemHealthManager) mContext.getSystemService(Context.SYSTEM_HEALTH_SERVICE); HealthStats healthStats = manager.takeMyUidSnapshot(); Assert.assertNotNull(healthStats); + // calc from packets + // double power = 0; + // double powerMaPerPacket = 0; + // MatrixLog.i(TAG, "estimate WIFI by packets"); + // { + // final long wifiBps = 1000000; + // final double averageWifiActivePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ACTIVE) / 3600; + // powerMaPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); + // long packets = 1213737 + 244433; + // power += powerMaPerPacket * packets; + // } + // { + // double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ON); + // long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS); + // power += new HealthStatsHelper.UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + // } + // { + // double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_SCAN); + // long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_WIFI_SCAN); + // power += new HealthStatsHelper.UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + // } + // Assert.fail("power: " + power + ", watt: " + powerMaPerPacket); + if (healthStats.hasMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS)) { double powerMahByHealthStats = healthStats.getMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS) / (1000.0 * 60 * 60); Assert.assertTrue(powerMahByHealthStats >= 0); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 35378182c..48a9b6d20 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -93,7 +93,7 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.offUpTimeMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS)); snapshot.mobilePowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS)); - snapshot.mobileRadioActiveMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE)); + snapshot.mobileRadioActiveMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE) / 1000L); snapshot.mobileIdleMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS)); snapshot.mobileRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_MS)); snapshot.mobileTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_MS)); @@ -102,8 +102,8 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.wifiIdleMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_IDLE_MS)); snapshot.wifiRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_MS)); snapshot.wifiTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_MS)); - snapshot.wifiRxBytes = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_BYTES)); - snapshot.wifiTxBytes = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_BYTES)); + snapshot.wifiRxPackets = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS)); + snapshot.wifiTxPackets = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS)); snapshot.blueToothPowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS)); snapshot.blueToothIdleMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS)); @@ -289,8 +289,8 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry wifiIdleMs = DigitEntry.of(0L); public DigitEntry wifiRxMs = DigitEntry.of(0L); public DigitEntry wifiTxMs = DigitEntry.of(0L); - public DigitEntry wifiRxBytes = DigitEntry.of(0L); - public DigitEntry wifiTxBytes = DigitEntry.of(0L); + public DigitEntry wifiRxPackets = DigitEntry.of(0L); + public DigitEntry wifiTxPackets = DigitEntry.of(0L); public DigitEntry blueToothPowerMams = DigitEntry.of(0L); public DigitEntry blueToothIdleMs = DigitEntry.of(0L); @@ -385,8 +385,8 @@ protected HealthStatsSnapshot computeDelta() { delta.wifiIdleMs = Differ.DigitDiffer.globalDiff(bgn.wifiIdleMs, end.wifiIdleMs); delta.wifiRxMs = Differ.DigitDiffer.globalDiff(bgn.wifiRxMs, end.wifiRxMs); delta.wifiTxMs = Differ.DigitDiffer.globalDiff(bgn.wifiTxMs, end.wifiTxMs); - delta.wifiRxBytes = Differ.DigitDiffer.globalDiff(bgn.wifiRxBytes, end.wifiRxBytes); - delta.wifiTxBytes = Differ.DigitDiffer.globalDiff(bgn.wifiTxBytes, end.wifiTxBytes); + delta.wifiRxPackets = Differ.DigitDiffer.globalDiff(bgn.wifiRxPackets, end.wifiRxPackets); + delta.wifiTxPackets = Differ.DigitDiffer.globalDiff(bgn.wifiTxPackets, end.wifiTxPackets); delta.blueToothPowerMams = Differ.DigitDiffer.globalDiff(bgn.blueToothPowerMams, end.blueToothPowerMams); delta.blueToothIdleMs = Differ.DigitDiffer.globalDiff(bgn.blueToothIdleMs, end.blueToothIdleMs); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 79fe96db4..5dbd93a25 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -68,6 +68,11 @@ public double calculatePower(long durationMs) { } } + public static double round(double input, int decimalPlace) { + double decimal = Math.pow(10.0, decimalPlace); + return Math.round(input * decimal) / decimal; + } + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N) public static boolean isSupported() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; @@ -108,40 +113,44 @@ static long getTimerTime(HealthStats healthStats, int key) { */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcCpuPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_CPU_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; - if (power > 0) { - MatrixLog.i(TAG, "estimate CPU by mams"); - } else if (power == 0) { - /* - * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode. - * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should - * be zero on devices that can go into full CPU power collapse even when a wake - * lock is held. Otherwise, this is the power consumption in addition to - * POWER_CPU_SUSPEND due to a wake lock being held but with no CPU activity. - * POWER_CPU_ACTIVE: Power consumption when CPU is running, excluding power consumed by clusters - * and cores. - * - * CPU Power Equation (assume two clusters): - * Total power = POWER_CPU_SUSPEND (always added) - * + POWER_CPU_IDLE (skip this and below if in power collapse mode) - * + POWER_CPU_ACTIVE (skip this and below if CPU is not running, but a wakelock - * is held) - * + cluster_power.cluster0 + cluster_power.cluster1 (skip cluster not running) - * + core_power.cluster0 * num running cores in cluster 0 - * + core_power.cluster1 * num running cores in cluster 1 - */ - long cpuTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); - power += estimateCpuActivePower(powerProfile, cpuTimeMs); - CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); - if (feat != null && feat.isSupported()) { - CpuStateSnapshot snapshot = feat.currentCpuStateSnapshot(); - if (snapshot != null) { - power += estimateCpuClustersPower(powerProfile, snapshot, cpuTimeMs, false); - power += estimateCpuCoresPower(powerProfile, snapshot, cpuTimeMs, false); - } + // double mams = getMeasure(healthStats, UidHealthStats.MEASUREMENT_CPU_POWER_MAMS) / (UsageBasedPowerEstimator.MILLIS_IN_HOUR * 1000L); + // if (mams > 0) { + // MatrixLog.i(TAG, "estimate CPU by mams"); + // return mams; + // } + double power = 0; + /* + * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode. + * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should + * be zero on devices that can go into full CPU power collapse even when a wake + * lock is held. Otherwise, this is the power consumption in addition to + * POWER_CPU_SUSPEND due to a wake lock being held but with no CPU activity. + * POWER_CPU_ACTIVE: Power consumption when CPU is running, excluding power consumed by clusters + * and cores. + * + * CPU Power Equation (assume two clusters): + * Total power = POWER_CPU_SUSPEND (always added) + * + POWER_CPU_IDLE (skip this and below if in power collapse mode) + * + POWER_CPU_ACTIVE (skip this and below if CPU is not running, but a wakelock + * is held) + * + cluster_power.cluster0 + cluster_power.cluster1 (skip cluster not running) + * + core_power.cluster0 * num running cores in cluster 0 + * + core_power.cluster1 * num running cores in cluster 1 + */ + long cpuTimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS); + power += estimateCpuActivePower(powerProfile, cpuTimeMs); + CpuStatFeature feat = BatteryCanary.getMonitorFeature(CpuStatFeature.class); + if (feat != null && feat.isSupported()) { + CpuStateSnapshot snapshot = feat.currentCpuStateSnapshot(); + if (snapshot != null) { + power += estimateCpuClustersPower(powerProfile, snapshot, cpuTimeMs, false); + power += estimateCpuCoresPower(powerProfile, snapshot, cpuTimeMs, false); } } - return power; + if (power > 0) { + return power; + } + return 0; } @VisibleForTesting @@ -374,23 +383,22 @@ public static double calcWakelocksPower(PowerProfile powerProfile, HealthStats h */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcMobilePower(PowerProfile powerProfile, HealthStats healthStats) { - double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + // double mams = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + // if (mams > 0) { + // MatrixLog.i(TAG, "estimate Mobile by mams"); + // return mams; + // } + double power = calcMobilePowerByRadioActive(powerProfile, healthStats); if (power > 0) { - MatrixLog.i(TAG, "estimate Mobile by mams"); + MatrixLog.i(TAG, "estimate Mobile by radioActive"); + return power; } - if (power == 0) { - power = calcMobilePowerByRadioActive(powerProfile, healthStats); - if (power > 0) { - MatrixLog.i(TAG, "estimate Mobile by radioActive"); - } - } - if (power == 0) { - power = calcMobilePowerByController(powerProfile, healthStats); - if (power > 0) { - MatrixLog.i(TAG, "estimate Mobile by controller"); - } + power = calcMobilePowerByController(powerProfile, healthStats); + if (power > 0) { + MatrixLog.i(TAG, "estimate Mobile by controller"); + return power; } - return power; + return 0; } @RequiresApi(api = Build.VERSION_CODES.N) @@ -441,23 +449,22 @@ public static double calcMobilePowerByController(PowerProfile powerProfile, Heal */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcWifiPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + // double mams = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + // if (mams > 0) { + // MatrixLog.i(TAG, "estimate WIFI by mams"); + // return mams; + // } + double power = calcWifiPowerByController(powerProfile, healthStats); if (power > 0) { - MatrixLog.i(TAG, "estimate WIFI by mams"); - } - if (power == 0) { - power = calcWifiPowerByController(powerProfile, healthStats); - if (power > 0) { - MatrixLog.i(TAG, "estimate WIFI by controller"); - } + MatrixLog.i(TAG, "estimate WIFI by controller"); + return power; } - if (power == 0) { - power = calcWifiPowerByPackets(powerProfile, healthStats); - if (power > 0) { - MatrixLog.i(TAG, "estimate WIFI by packets"); - } + power = calcWifiPowerByPackets(powerProfile, healthStats); + if (power > 0) { + MatrixLog.i(TAG, "estimate WIFI by packets"); + return power; } - return power; + return 0; } @RequiresApi(api = Build.VERSION_CODES.N) @@ -517,26 +524,26 @@ public static double calcWifiPowerByPackets(PowerProfile powerProfile, HealthSta */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcBlueToothPower(PowerProfile powerProfile, HealthStats healthStats) { - double power = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; - if (power > 0) { - MatrixLog.i(TAG, "etmMobilePower BLE by mams"); + // double mams = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS) / UsageBasedPowerEstimator.MILLIS_IN_HOUR; + // if (mams > 0) { + // MatrixLog.i(TAG, "etmMobilePower BLE by mams"); + // return mams; + // } + double power = 0; + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - if (power == 0) { - { - long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS); - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - { - long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS); - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - { - long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS); - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + { + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS); + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } return power; } From abc89e01a8e3dd53c8b2747803e5b42713d2e681 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 16 Aug 2022 16:37:19 +0800 Subject: [PATCH 133/263] Power must not be negative --- .../stats/HealthStatsHelper.java | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 5dbd93a25..64dd74c59 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -545,7 +545,10 @@ public static double calcBlueToothPower(PowerProfile powerProfile, HealthStats h double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX); power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); } - return power; + if (power > 0) { + return power; + } + return 0; } /** @@ -566,7 +569,11 @@ public static double calcGpsPower(PowerProfile powerProfile, HealthStats healthS powerMa = sumMa / num; } } - return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + double power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + if (power > 0) { + return power; + } + return 0; } /** @@ -605,7 +612,10 @@ public static double calcSensorsPower(Context context, HealthStats healthStats) } } } - return power; + if (power > 0) { + return power; + } + return 0; } /** @@ -615,7 +625,11 @@ public static double calcSensorsPower(Context context, HealthStats healthStats) public static double calcCameraPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_CAMERA); double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_CAMERA); - return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + double power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + if (power > 0) { + return power; + } + return 0; } /** @@ -625,7 +639,11 @@ public static double calcCameraPower(PowerProfile powerProfile, HealthStats heal public static double calcFlashLightPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_FLASHLIGHT); double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_FLASHLIGHT); - return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + double power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + if (power > 0) { + return power; + } + return 0; } /** @@ -635,7 +653,11 @@ public static double calcFlashLightPower(PowerProfile powerProfile, HealthStats public static double calcAudioPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_AUDIO); double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_AUDIO); - return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + double power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + if (power > 0) { + return power; + } + return 0; } /** @@ -645,7 +667,11 @@ public static double calcAudioPower(PowerProfile powerProfile, HealthStats healt public static double calcVideoPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_VIDEO); double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_VIDEO); - return new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + double power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + if (power > 0) { + return power; + } + return 0; } /** @@ -657,7 +683,11 @@ public static double calcScreenPower(PowerProfile powerProfile, HealthStats heal long fgActivityMs = getTimerTime(healthStats, UidHealthStats.TIMER_FOREGROUND_ACTIVITY); long screenOnTimeMs = Math.min(topAppMs, fgActivityMs); double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_SCREEN_ON); - return new UsageBasedPowerEstimator(powerMa).calculatePower(screenOnTimeMs); + double power = new UsageBasedPowerEstimator(powerMa).calculatePower(screenOnTimeMs); + if (power > 0) { + return power; + } + return 0; } /** @@ -689,7 +719,10 @@ public static double calcSystemServicePower(PowerProfile powerProfile, HealthSta power += estimateCpuCoresPower(powerProfile, snapshot, timeMs, false); } } - return power; + if (power > 0) { + return power; + } + return 0; } /** @@ -701,6 +734,10 @@ public static double calcIdlePower(PowerProfile powerProfile, HealthStats health long batteryUptimeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_UPTIME_BATTERY_MS); double suspendPowerMah = new UsageBasedPowerEstimator(powerProfile.getAveragePowerUni(PowerProfile.POWER_CPU_SUSPEND)).calculatePower(batteryRealtimeMs); double idlePowerMah = new UsageBasedPowerEstimator(powerProfile.getAveragePowerUni(PowerProfile.POWER_CPU_IDLE)).calculatePower(batteryUptimeMs); - return suspendPowerMah + idlePowerMah; + double power = suspendPowerMah + idlePowerMah; + if (power > 0) { + return power; + } + return 0; } } From 760a5a80a54a339724a215e70ac05c2d5a35a792 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 16 Aug 2022 18:46:43 +0800 Subject: [PATCH 134/263] ActivityLeakFixer: remove contentView only for devices that is split-supported --- .../com/tencent/matrix/resource/ActivityLeakFixer.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ActivityLeakFixer.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ActivityLeakFixer.java index 46b93ce8e..4e8a0f703 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ActivityLeakFixer.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ActivityLeakFixer.java @@ -130,12 +130,17 @@ public static void fixInputMethodManagerLeak(Context destContext) { MatrixLog.i(TAG, "fixInputMethodManagerLeak done, cost: %s ms.", System.currentTimeMillis() - startTick); } + public static boolean sSupportSplit = false; + public static void unbindDrawables(Activity ui) { final long startTick = System.currentTimeMillis(); if (ui != null && ui.getWindow() != null && ui.getWindow().peekDecorView() != null) { - final View viewRoot = ui.getWindow().peekDecorView().getRootView(); + View viewRoot = ui.getWindow().peekDecorView().getRootView(); try { unbindDrawablesAndRecycle(viewRoot); + if (Build.VERSION.SDK_INT >= 31 && sSupportSplit) { + viewRoot = ui.getWindow().getDecorView().findViewById(android.R.id.content); + } if (viewRoot instanceof ViewGroup) { ((ViewGroup) viewRoot).removeAllViews(); } From 21144c1ce55b433b4fa6110ac1b3e01140a03ce6 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 18 Aug 2022 14:02:46 +0800 Subject: [PATCH 135/263] Fix battery power profile paring for custom path --- .../utils/BatteryMetricsTest.java | 38 ++++++++++--------- .../batterycanary/utils/PowerProfile.java | 10 +++-- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java index d0d207f06..27d0345bb 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryMetricsTest.java @@ -29,6 +29,7 @@ import com.tencent.matrix.batterycanary.TestUtils; +import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -135,29 +136,30 @@ public File call() { } }; - File file = findBlock.call(); if (file != null) { - XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); - factory.setNamespaceAware(true); - XmlPullParser parser = factory.newPullParser(); - parser.setInput(new FileInputStream(file), "UTF-8"); - while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { - if (parser.getEventType() == XmlPullParser.START_TAG) { - String tagName = parser.getName(); - String tagText = parser.getText(); - for (int i = 0; i < parser.getAttributeCount(); i++) { - String attrName = parser.getAttributeName(i); - String attrValue = parser.getAttributeValue(i); - if (attrValue.startsWith("cpu.core_speeds.cluster")) { - } - } - } - parser.nextToken(); - } + PowerProfile powerProfile = new PowerProfile(mContext); + Assert.fail(PowerProfile.getResType()); + powerProfile.readPowerValuesFromFilePath(mContext, file); + powerProfile.initCpuClusters(); + powerProfile.smoke(); } } + @Test + public void KernelCpuUidFreqTimeReaderCompat() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + int[] clusterSteps = new int[powerProfile.getNumCpuClusters()]; + for (int i = 0; i < clusterSteps.length; i++) { + clusterSteps[i] = powerProfile.getNumSpeedStepsInCpuCluster(i); + } + KernelCpuUidFreqTimeReader reader = new KernelCpuUidFreqTimeReader(Process.myPid(), clusterSteps); + reader.smoke(); + } + @Test public void testGetAppCpuCoreNumByTid() { StringBuilder tips = new StringBuilder("\n"); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java index 0a2b8e885..5e89aa15b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java @@ -64,7 +64,7 @@ public static PowerProfile init(Context context) throws IOException { } } - public PowerProfile smoke() throws IOException { + PowerProfile smoke() throws IOException { if (getNumCpuClusters() <= 0) { throw new IOException("Invalid cpu clusters: " + getNumCpuClusters()); } @@ -298,7 +298,7 @@ public int getClusterByCpuNum(int cpuCoreNum) { private static final Object sLock = new Object(); - private PowerProfile(Context context) { + PowerProfile(Context context) { // Read the XML file for the given profile (normally only one per device) synchronized (sLock) { if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) { @@ -362,6 +362,7 @@ public File call() throws FileNotFoundException { } }; try { + exception = null; readPowerValuesFromFilePath(context, findBlock.call()); initCpuClusters(); smoke(); @@ -374,6 +375,7 @@ public File call() throws FileNotFoundException { if (exception != null) { try { + exception = null; readPowerValuesFromRes(context, "power_profile_test"); initCpuClusters(); smoke(); @@ -409,7 +411,7 @@ private void readPowerValuesFromRes(Context context, String fileName) { } } - private void readPowerValuesFromFilePath(Context context, File xmlFile) { + void readPowerValuesFromFilePath(Context context, File xmlFile) { FileInputStream is = null; try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); @@ -518,7 +520,7 @@ private void readPowerValuesFromXml(Context context, XmlPullParser parser) { private static final String CPU_CORE_SPEED_PREFIX = "cpu.core_speeds.cluster"; private static final String CPU_CORE_POWER_PREFIX = "cpu.core_power.cluster"; - private void initCpuClusters() { + void initCpuClusters() { if (sPowerArrayMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) { final Double[] data = sPowerArrayMap.get(CPU_PER_CLUSTER_CORE_COUNT); mCpuClusters = new CpuClusterKey[data.length]; From 7e179f2da2acb58c1ae9f9c28ac12f4c89a501b9 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 19 Aug 2022 14:38:17 +0800 Subject: [PATCH 136/263] Update powerprofile parsing --- .../monitor/feature/DeviceStatMonitorFeature.java | 2 +- .../matrix/batterycanary/utils/PowerProfile.java | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java index 03a691ad3..1c8c1eb59 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java @@ -188,7 +188,7 @@ public ChargeWattageSnapshot currentChargeWattage(Context context) { public BatteryCurrentSnapshot currentBatteryCurrency(Context context) { BatteryCurrentSnapshot snapshot = new BatteryCurrentSnapshot(); - snapshot.stat = Snapshot.Entry.DigitEntry.of(BatteryCanaryUtil.getBatteryCurrency(context)); + snapshot.stat = Snapshot.Entry.DigitEntry.of(BatteryCanaryUtil.getBatteryCurrencyImmediately(context)); return snapshot; } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java index 5e89aa15b..d2a73256d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java @@ -338,6 +338,7 @@ private void readPowerValuesCompat(Context context) throws IOException { mResType = "framework"; } catch (Exception e) { MatrixLog.w(TAG, "read from framework failed: " + e); + clear(); exception = e; } @@ -369,6 +370,7 @@ public File call() throws FileNotFoundException { mResType = "custom"; } catch (Exception e) { MatrixLog.w(TAG, "read from custom failed: " + e); + clear(); exception = e; } } @@ -382,6 +384,7 @@ public File call() throws FileNotFoundException { mResType = "test"; } catch (Exception e) { MatrixLog.w(TAG, "read from test failed: " + e); + clear(); exception = e; } } @@ -391,7 +394,8 @@ public File call() throws FileNotFoundException { } } - private void readPowerValuesFromRes(Context context, String fileName) { + @VisibleForTesting + public void readPowerValuesFromRes(Context context, String fileName) { XmlResourceParser parser = null; try { final int id = context.getResources().getIdentifier(fileName, "xml", "android"); @@ -411,7 +415,8 @@ private void readPowerValuesFromRes(Context context, String fileName) { } } - void readPowerValuesFromFilePath(Context context, File xmlFile) { + @VisibleForTesting + public void readPowerValuesFromFilePath(Context context, File xmlFile) { FileInputStream is = null; try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); @@ -433,6 +438,12 @@ void readPowerValuesFromFilePath(Context context, File xmlFile) { } } + @VisibleForTesting + public void clear() { + sPowerItemMap.clear(); + sPowerArrayMap.clear(); + } + @SuppressWarnings({"ToArrayCallWithZeroLengthArrayArgument", "UnnecessaryBoxing", "CatchMayIgnoreException", "TryWithIdenticalCatches"}) private void readPowerValuesFromXml(Context context, XmlPullParser parser) { boolean parsingArray = false; From 25697c011d285e222b72de6524cab6904c02f251 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 22 Aug 2022 15:35:08 +0800 Subject: [PATCH 137/263] Fix battery lifecycle listener --- .../com/tencent/matrix/batterycanary/BatteryEventDelegate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java index 60cca6c3a..3f7219f0c 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java @@ -669,7 +669,7 @@ public DefaultListenerImpl(boolean keepAlive) { @Override public boolean onStateChanged(String event) { - return !mKeepAlive; + throw new RuntimeException("Use #onStateChanged(BatteryState, String) instead"); } @Override From 353fed4ff99fbaa72ce480fd229004952def0032 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Mon, 22 Aug 2022 17:32:39 +0800 Subject: [PATCH 138/263] memory-canary: fix NPE --- .../tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt index aa39c7f4d..7faf4563f 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/ProcessSubordinate.kt @@ -100,7 +100,9 @@ internal object ProcessSubordinate { fun getMemInfo(): Array { val memInfoList = ArrayList() subordinateProxies.forEachSafe { - memInfoList.add(it.value.memInfo) + it.value.memInfo?.let { m-> + memInfoList.add(m) + } } return memInfoList.toTypedArray() } From 2c008b876e7190fa647288bf96f94fdd69c0353b Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 22 Aug 2022 19:23:23 +0800 Subject: [PATCH 139/263] Add battery cpufreq sampler --- .../matrix-battery-canary/build.gradle | 5 +- .../src/androidTest/AndroidManifest.xml | 2 +- .../matrix/batterycanary/DebugApp.java | 18 +++++ .../utils/BatteryMetricsTest.java | 33 +++++++- .../monitor/feature/CompositeMonitors.java | 78 ++++++++++++++++++- .../feature/DeviceStatMonitorFeature.java | 11 ++- 6 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/DebugApp.java diff --git a/matrix/matrix-android/matrix-battery-canary/build.gradle b/matrix/matrix-android/matrix-battery-canary/build.gradle index f888d207e..721d0a13d 100644 --- a/matrix/matrix-android/matrix-battery-canary/build.gradle +++ b/matrix/matrix-android/matrix-battery-canary/build.gradle @@ -10,7 +10,9 @@ android { versionCode 1 versionName rootProject.ext.VERSION_NAME + multiDexEnabled true testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + // testInstrumentationRunner "com.android.test.runner.MultiDexTestRunner" consumerProguardFiles 'consumer-rules.pro' } @@ -39,7 +41,8 @@ dependencies { androidTestImplementation 'commons-io:commons-io:2.6' // androidTestImplementation 'androidx.core:core:1.3.2' androidTestImplementation 'androidx.annotation:annotation:1.0.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation('androidx.multidex:multidex-instrumentation:2.0.0') androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' androidTestImplementation "org.mockito:mockito-core:2.8.9" androidTestImplementation "org.mockito:mockito-android:2.8.9" diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml index 1e6c6be76..e02acdf6a 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml @@ -15,7 +15,7 @@ android:minSdkVersion="21" android:targetSdkVersion="28" /> - + cpuFreqSteps = BatteryCanaryUtil.getCpuFreqSteps(); + int[] cpuCurrentFreq = BatteryCanaryUtil.getCpuCurrentFreq(); + Assert.assertNotNull(cpuFreqSteps); + Assert.assertNotNull(cpuCurrentFreq); + + new Thread(new Runnable() { + @Override + public void run() { + while (true) { + } + } + }).start(); + + CompositeMonitors.CpuFreqSampler sampler = new CompositeMonitors.CpuFreqSampler(BatteryCanaryUtil.getCpuFreqSteps()); + Assert.assertTrue(sampler.isCompat(powerProfile)); + if (!TestUtils.isAssembleTest()) { + while (true) { + sampler.count(BatteryCanaryUtil.getCpuCurrentFreq()); + Thread.sleep(5000L); + } + } + } + @Test public void testGetAppCpuCoreNumByTid() { StringBuilder tips = new StringBuilder("\n"); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index d0d254b32..390f02208 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -17,6 +17,7 @@ import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.Consumer; import com.tencent.matrix.batterycanary.utils.Function; +import com.tencent.matrix.batterycanary.utils.PowerProfile; import com.tencent.matrix.util.MatrixLog; import java.util.ArrayList; @@ -69,6 +70,9 @@ public class CompositeMonitors { protected BatteryMonitorCore mMonitor; @Nullable protected AppStats mAppStats; + @Nullable + protected CpuFreqSampler mCpuFreqSampler; + protected long mBgnMillis = SystemClock.uptimeMillis(); protected String mScope; @@ -97,6 +101,7 @@ public void clear() { mTaskDeltasCollect.clear(); mExtras.clear(); mStacks.clear(); + mCpuFreqSampler = null; } public CompositeMonitors fork() { @@ -123,6 +128,7 @@ protected CompositeMonitors fork(CompositeMonitors that) { that.mTaskDeltasCollect.putAll(this.mTaskDeltasCollect); that.mExtras.putAll(this.mExtras); that.mStacks.putAll(this.mStacks); + that.mCpuFreqSampler = this.mCpuFreqSampler; return that; } @@ -561,10 +567,22 @@ protected Snapshot.Sampler statSampler(Class> snapshotClas if (snapshotClass == DeviceStatMonitorFeature.CpuFreqSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { + final CpuStatFeature cpuStatsFeat = getFeature(CpuStatFeature.class); + if (cpuStatsFeat != null) { + if (cpuStatsFeat.isSupported()) { + mCpuFreqSampler = new CpuFreqSampler(BatteryCanaryUtil.getCpuFreqSteps()); + } + } sampler = new Snapshot.Sampler("cpufreq", mMonitor.getHandler(), new Function() { @Override public Number apply(Snapshot.Sampler sampler) { - DeviceStatMonitorFeature.CpuFreqSnapshot snapshot = feature.currentCpuFreq(); + int[] cpuFreqs = BatteryCanaryUtil.getCpuCurrentFreq(); + if (cpuStatsFeat != null && cpuStatsFeat.isSupported()) { + if (mCpuFreqSampler != null && mCpuFreqSampler.isCompat(cpuStatsFeat.getPowerProfile())) { + mCpuFreqSampler.count(cpuFreqs); + } + } + DeviceStatMonitorFeature.CpuFreqSnapshot snapshot = feature.currentCpuFreq(cpuFreqs); List> list = snapshot.cpuFreqs.getList(); MatrixLog.i(TAG, CompositeMonitors.this.hashCode() + " #onSampling: " + mScope); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + list); @@ -865,6 +883,11 @@ public Bundle getExtras() { return mExtras; } + @Nullable + public CpuFreqSampler getCpuFreqSampler() { + return mCpuFreqSampler; + } + @Override @NonNull public String toString() { @@ -892,4 +915,57 @@ static Map sortMapByValue(Map map, Comparator cpuFreqSteps; + public final List cpuFreqCounters; + + public CpuFreqSampler(List cpuFreqSteps) { + this.cpuFreqSteps = cpuFreqSteps; + this.cpuFreqCounters = new ArrayList<>(cpuFreqSteps.size()); + for (int[] item : cpuFreqSteps) { + this.cpuFreqCounters.add(new int[item.length]); + } + } + + public boolean isCompat(PowerProfile powerProfile) { + if (cpuFreqSteps.size() == powerProfile.getCpuCoreNum()) { + for (int i = 0; i < cpuFreqSteps.size(); i++) { + int clusterByCpuNum = powerProfile.getClusterByCpuNum(i); + int steps = powerProfile.getNumSpeedStepsInCpuCluster(clusterByCpuNum); + if (cpuFreqSteps.get(i).length != steps) { + return false; + } + } + return true; + } + return false; + } + + public void count(int[] cpuCurrentFreq) { + this.cpuCurrentFreq = BatteryCanaryUtil.getCpuCurrentFreq(); + for (int i = 0; i < cpuCurrentFreq.length; i++) { + int speed = cpuCurrentFreq[i]; + int[] steps = cpuFreqSteps.get(i); + if (speed < steps[0]) { + cpuFreqCounters.get(i)[0]++; + continue; + } + boolean found = false; + for (int j = 0; j < steps.length; j++) { + if (speed <= steps[j]) { + cpuFreqCounters.get(i)[j]++; + found = true; + break; + } + } + if (!found) { + if (speed > steps[steps.length - 1]) { + cpuFreqCounters.get(i)[steps.length - 1]++; + } + } + } + } + } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java index 1c8c1eb59..a22c3b581 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/DeviceStatMonitorFeature.java @@ -117,13 +117,18 @@ public int weight() { } public CpuFreqSnapshot currentCpuFreq() { - CpuFreqSnapshot snapshot = new CpuFreqSnapshot(); try { - snapshot.cpuFreqs = Snapshot.Entry.ListEntry.ofDigits(BatteryCanaryUtil.getCpuCurrentFreq()); + int[] cpuFreqs = BatteryCanaryUtil.getCpuCurrentFreq(); + return currentCpuFreq(cpuFreqs); } catch (Throwable e) { MatrixLog.printErrStackTrace(TAG, e, "#currentCpuFreq error"); - snapshot.cpuFreqs = Snapshot.Entry.ListEntry.ofDigits(new int[]{}); + return currentCpuFreq(new int[]{}); } + } + + public CpuFreqSnapshot currentCpuFreq(int[] cpuFreqs) { + CpuFreqSnapshot snapshot = new CpuFreqSnapshot(); + snapshot.cpuFreqs = Snapshot.Entry.ListEntry.ofDigits(cpuFreqs); return snapshot; } From cc19ed8c6758dc430a2e87e30ff5866d70b7dede Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 23 Aug 2022 20:54:01 +0800 Subject: [PATCH 140/263] Update cpuPower calc --- .../monitor/feature/CompositeMonitors.java | 25 +++-- .../stats/HealthStatsFeature.java | 93 +++++++++++++------ .../stats/HealthStatsHelper.java | 2 + .../utils/BatteryCanaryUtil.java | 15 +++ 4 files changed, 92 insertions(+), 43 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 390f02208..aaf67d7a5 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -14,6 +14,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; import com.tencent.matrix.batterycanary.stats.HealthStatsFeature; +import com.tencent.matrix.batterycanary.stats.HealthStatsFeature.HealthStatsSnapshot; import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.Consumer; import com.tencent.matrix.batterycanary.utils.Function; @@ -25,7 +26,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -387,6 +387,14 @@ public void finish() { collectStacks(); configureSampleResults(); mAppStats = AppStats.current(SystemClock.uptimeMillis() - mBgnMillis); + + // For further procedures + // getDelta(HealthStatsSnapshot.class, new Consumer>() { + // @Override + // public void accept(Delta delta) { + // delta.dlt.estimateTestsPowers(CompositeMonitors.this); + // } + // }); } protected void configureBgnSnapshots() { @@ -530,7 +538,7 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas } return snapshot; } - if (snapshotClass == HealthStatsFeature.HealthStatsSnapshot.class) { + if (snapshotClass == HealthStatsSnapshot.class) { HealthStatsFeature feature = getFeature(HealthStatsFeature.class); if (feature != null) { snapshot = feature.currHealthStatsSnapshot(); @@ -833,7 +841,7 @@ public Map, Delta, Delta>>>>() { + return BatteryCanaryUtil.sortMapByValue(mTaskDeltasCollect, new Comparator, Delta>>>>() { @SuppressWarnings("ConstantConditions") @Override public int compare(Map.Entry, Delta>>> o1, Map.Entry, Delta>>> o2) { @@ -905,17 +913,6 @@ public String toString() { '}'; } - static Map sortMapByValue(Map map, Comparator> comparator) { - List> list = new ArrayList<>(map.entrySet()); - Collections.sort(list, comparator); - - Map result = new LinkedHashMap<>(); - for (Map.Entry entry : list) { - result.put(entry.getKey(), entry.getValue()); - } - return result; - } - public static class CpuFreqSampler { public int[] cpuCurrentFreq; public final List cpuFreqSteps; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 48a9b6d20..d0fb9c736 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -14,11 +14,13 @@ import com.tencent.matrix.batterycanary.monitor.feature.AbsMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; +import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.PowerProfile; import com.tencent.matrix.util.MatrixLog; import java.lang.reflect.Method; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -252,6 +254,8 @@ public static class HealthStatsSnapshot extends Snapshot { @VisibleForTesting public DigitEntry wifiPowerByController = DigitEntry.of(0D); @VisibleForTesting public DigitEntry wifiPowerByPackets = DigitEntry.of(0D); + public Map extras = Collections.emptyMap(); + // Estimated Powers public DigitEntry cpuPower = DigitEntry.of(0D); public DigitEntry wakelocksPower = DigitEntry.of(0D); @@ -265,7 +269,7 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry audioPower = DigitEntry.of(0D); public DigitEntry videoPower = DigitEntry.of(0D); public DigitEntry screenPower = DigitEntry.of(0D); - public DigitEntry systemServicePower = DigitEntry.of(0D); + public DigitEntry systemServicePower = DigitEntry.of(0D); // WIP public DigitEntry idlePower = DigitEntry.of(0D); // Meta Data: @@ -339,7 +343,7 @@ public double getTotalPower() { + audioPower.get() + videoPower.get() + screenPower.get() - + systemServicePower.get() + // + systemServicePower.get() + idlePower.get(); } @@ -349,11 +353,19 @@ public Delta diff(HealthStatsSnapshot bgn) { @Override protected HealthStatsSnapshot computeDelta() { HealthStatsSnapshot delta = new HealthStatsSnapshot(); + + // For test delta.mobilePowerByRadioActive = Differ.DigitDiffer.globalDiff(bgn.mobilePowerByRadioActive, end.mobilePowerByRadioActive); delta.mobilePowerByController = Differ.DigitDiffer.globalDiff(bgn.mobilePowerByController, end.mobilePowerByController); delta.wifiPowerByController = Differ.DigitDiffer.globalDiff(bgn.wifiPowerByController, end.wifiPowerByController); delta.wifiPowerByPackets = Differ.DigitDiffer.globalDiff(bgn.wifiPowerByPackets, end.wifiPowerByPackets); + delta.extras = new HashMap<>(); + delta.extras.put("power-mobile-radio", mobilePowerByRadioActive.get()); + delta.extras.put("power-mobile-controller", mobilePowerByController.get()); + delta.extras.put("power-wifi-controller", wifiPowerByController.get()); + delta.extras.put("power-wifi-packets", wifiPowerByPackets.get()); + // UID delta.cpuPower = Differ.DigitDiffer.globalDiff(bgn.cpuPower, end.cpuPower); delta.wakelocksPower = Differ.DigitDiffer.globalDiff(bgn.wakelocksPower, end.wakelocksPower); delta.mobilePower = Differ.DigitDiffer.globalDiff(bgn.mobilePower, end.mobilePower); @@ -415,41 +427,64 @@ protected HealthStatsSnapshot computeDelta() { delta.procBgMs = Differ.DigitDiffer.globalDiff(bgn.procBgMs, end.procBgMs); delta.procCacheMs = Differ.DigitDiffer.globalDiff(bgn.procCacheMs, end.procCacheMs); - delta.procStatsCpuUsrTimeMs = new HashMap<>(); - for (Map.Entry> entry : end.procStatsCpuUsrTimeMs.entrySet()) { - String key = entry.getKey(); - DigitEntry endEntry = entry.getValue(); - long bgnValue = 0L; - DigitEntry bgnEntry = bgn.procStatsCpuUsrTimeMs.get(key); - if (bgnEntry != null) { - bgnValue = bgnEntry.get(); + // PID + { + Map> map = new HashMap<>(); + for (Map.Entry> entry : end.procStatsCpuUsrTimeMs.entrySet()) { + String key = entry.getKey(); + DigitEntry endEntry = entry.getValue(); + long bgnValue = 0L; + DigitEntry bgnEntry = bgn.procStatsCpuUsrTimeMs.get(key); + if (bgnEntry != null) { + bgnValue = bgnEntry.get(); + } + map.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); } - delta.procStatsCpuUsrTimeMs.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); + delta.procStatsCpuUsrTimeMs = decrease(map); } - delta.procStatsCpuSysTimeMs = new HashMap<>(); - for (Map.Entry> entry : end.procStatsCpuSysTimeMs.entrySet()) { - String key = entry.getKey(); - DigitEntry endEntry = entry.getValue(); - long bgnValue = 0L; - DigitEntry bgnEntry = bgn.procStatsCpuSysTimeMs.get(key); - if (bgnEntry != null) { - bgnValue = bgnEntry.get(); + { + Map> map = new HashMap<>(); + for (Map.Entry> entry : end.procStatsCpuSysTimeMs.entrySet()) { + String key = entry.getKey(); + DigitEntry endEntry = entry.getValue(); + long bgnValue = 0L; + DigitEntry bgnEntry = bgn.procStatsCpuSysTimeMs.get(key); + if (bgnEntry != null) { + bgnValue = bgnEntry.get(); + } + map.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); } - delta.procStatsCpuSysTimeMs.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); + delta.procStatsCpuSysTimeMs = decrease(map); } - delta.procStatsCpuFgTimeMs = new HashMap<>(); - for (Map.Entry> entry : end.procStatsCpuFgTimeMs.entrySet()) { - String key = entry.getKey(); - DigitEntry endEntry = entry.getValue(); - long bgnValue = 0L; - DigitEntry bgnEntry = bgn.procStatsCpuFgTimeMs.get(key); - if (bgnEntry != null) { - bgnValue = bgnEntry.get(); + { + Map> map = new HashMap<>(); + for (Map.Entry> entry : end.procStatsCpuFgTimeMs.entrySet()) { + String key = entry.getKey(); + DigitEntry endEntry = entry.getValue(); + long bgnValue = 0L; + DigitEntry bgnEntry = bgn.procStatsCpuFgTimeMs.get(key); + if (bgnEntry != null) { + bgnValue = bgnEntry.get(); + } + map.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); } - delta.procStatsCpuFgTimeMs.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); + delta.procStatsCpuFgTimeMs = decrease(map); } return delta; } + + private Map> decrease(Map> input) { + return BatteryCanaryUtil.sortMapByValue(input, new Comparator>>() { + @Override + public int compare(Map.Entry> o1, Map.Entry> o2) { + long sumLeft = o1.getValue().get(), sumRight = o2.getValue().get(); + long minus = sumLeft - sumRight; + if (minus == 0) return 0; + if (minus > 0) return -1; + return 1; + } + }); + } }; } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 64dd74c59..3d3c6cffc 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -691,6 +691,8 @@ public static double calcScreenPower(PowerProfile powerProfile, HealthStats heal } /** + * WIP + * * @see com.android.internal.os.SystemServicePowerCalculator */ @RequiresApi(api = Build.VERSION_CODES.N) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java index d6e162a08..f1f609d7d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCanaryUtil.java @@ -40,8 +40,11 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; import java.util.List; import java.util.ListIterator; +import java.util.Map; import java.util.regex.Pattern; import androidx.annotation.IntRange; @@ -78,6 +81,7 @@ public final class BatteryCanaryUtil { public static final int JIFFY_MILLIS = 1000 / JIFFY_HZ; public interface Proxy { + String getProcessName(); String getPackageName(); int getBatteryTemperature(Context context); @@ -790,4 +794,15 @@ public static long computeAvgByMinute(long input, long millis) { return input / Math.max(1, (millis) / ONE_MIN); } } + + public static Map sortMapByValue(Map map, Comparator> comparator) { + List> list = new ArrayList<>(map.entrySet()); + Collections.sort(list, comparator); + + Map result = new LinkedHashMap<>(); + for (Map.Entry entry : list) { + result.put(entry.getKey(), entry.getValue()); + } + return result; + } } From dae47c82316da05663618caca8811ab67bcdc72f Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 24 Aug 2022 18:12:11 +0800 Subject: [PATCH 141/263] Add battery cpuState uid snapshot --- .../monitor/BatteryMonitorConfig.java | 2 + .../monitor/feature/CompositeMonitors.java | 7 + .../monitor/feature/CpuStatFeature.java | 152 +++++++++++++++++- .../stats/HealthStatsHelper.java | 2 +- 4 files changed, 161 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java index 81992180d..1f3b19130 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java @@ -3,6 +3,7 @@ import android.app.ActivityManager; import com.tencent.matrix.batterycanary.BuildConfig; +import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature.UidCpuStateSnapshot.IpcCpuStat.RemoteStat; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.UidJiffiesSnapshot.IpcJiffies.IpcProcessJiffies; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; import com.tencent.matrix.batterycanary.stats.BatteryRecorder; @@ -68,6 +69,7 @@ public class BatteryMonitorConfig { public BatteryStats batteryStats; public CallStackCollector callStackCollector; public Function, IpcProcessJiffies> ipcJiffiesCollector; + public Function, RemoteStat> ipcCpuStatCollector; private BatteryMonitorConfig() { } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index aaf67d7a5..2f4decf14 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -531,6 +531,13 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas } return snapshot; } + if (snapshotClass == CpuStatFeature.UidCpuStateSnapshot.class) { + CpuStatFeature feature = getFeature(CpuStatFeature.class); + if (feature != null && feature.isSupported()) { + snapshot = feature.currentUidCpuStateSnapshot(); + } + return snapshot; + } if (snapshotClass == AppStatMonitorFeature.AppStatSnapshot.class) { AppStatMonitorFeature feature = getFeature(AppStatMonitorFeature.class); if (feature != null) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java index 2b05065bb..a0fa12a7d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java @@ -1,9 +1,16 @@ package com.tencent.matrix.batterycanary.monitor.feature; +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; import android.os.Process; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.ListEntry; +import com.tencent.matrix.batterycanary.shell.TopThreadFeature; +import com.tencent.matrix.batterycanary.shell.ui.TopThreadIndicator; +import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.KernelCpuSpeedReader; import com.tencent.matrix.batterycanary.utils.KernelCpuUidFreqTimeReader; import com.tencent.matrix.batterycanary.utils.PowerProfile; @@ -15,6 +22,7 @@ import java.util.List; import androidx.annotation.WorkerThread; +import androidx.core.util.Pair; import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.JIFFY_MILLIS; import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_HOR; @@ -24,7 +32,7 @@ * @since 2021/9/10 */ @SuppressWarnings("SpellCheckingInspection") -public class CpuStatFeature extends AbsTaskMonitorFeature { +public class CpuStatFeature extends AbsTaskMonitorFeature { private static final String TAG = "Matrix.battery.CpuStatFeature"; private PowerProfile mPowerProfile; @@ -137,6 +145,10 @@ public CpuStateSnapshot currentCpuStateSnapshot() { return snapshot; } + public UidCpuStateSnapshot currentUidCpuStateSnapshot() { + return UidCpuStateSnapshot.of(mCore.getContext(), mCore.getConfig()); + } + public static final class CpuStateSnapshot extends Snapshot { /* * cpuCoreStates @@ -155,6 +167,8 @@ public static final class CpuStateSnapshot extends Snapshot { */ public List>> cpuCoreStates = Collections.emptyList(); public List>> procCpuCoreStates = Collections.emptyList(); + public int pid = Process.myPid(); + public String name = BatteryCanaryUtil.getProcessName(); public long totalCpuJiffies() { long sum = 0; @@ -227,6 +241,8 @@ public Delta diff(CpuStateSnapshot bgn) { @Override protected CpuStateSnapshot computeDelta() { CpuStateSnapshot delta = new CpuStateSnapshot(); + delta.pid = end.pid; + delta.name = end.name; if (bgn.cpuCoreStates.size() != end.cpuCoreStates.size()) { delta.setValid(false); } else { @@ -244,4 +260,138 @@ protected CpuStateSnapshot computeDelta() { }; } } + + public static final class UidCpuStateSnapshot extends Snapshot { + public static UidCpuStateSnapshot of(Context context, BatteryMonitorConfig config) { + UidCpuStateSnapshot curr = new UidCpuStateSnapshot(); + try { + List> procList = TopThreadFeature.getProcList(context); + curr.pidCurrCupSateList = new ArrayList<>(procList.size()); + + for (Pair item : procList) { + //noinspection ConstantConditions + int pid = item.first; + String procName = String.valueOf(item.second); + if (config.ipcCpuStatCollector != null) { + IpcCpuStat.RemoteStat remote = config.ipcCpuStatCollector.apply(item); + if (remote != null) { + CpuStateSnapshot snapshot = IpcCpuStat.toLocal(remote); + snapshot.pid = pid; + snapshot.name = TopThreadIndicator.getProcSuffix(procName); + curr.pidCurrCupSateList.add(snapshot); + } + } + } + } catch (Exception e) { + MatrixLog.w(TAG, "get curr UidCpuStatSnapshot failed: " + e.getMessage()); + curr.setValid(false); + } + return curr; + } + + public List pidCurrCupSateList = Collections.emptyList(); + public List> pidDeltaCpuSateList = Collections.emptyList(); + + @Override + public Delta diff(UidCpuStateSnapshot bgn) { + return new Delta(bgn, this) { + @Override + protected UidCpuStateSnapshot computeDelta() { + UidCpuStateSnapshot delta = new UidCpuStateSnapshot(); + if (end.pidCurrCupSateList.size() > 0) { + delta.pidDeltaCpuSateList = new ArrayList<>(); + for (CpuStateSnapshot end : end.pidCurrCupSateList) { + CpuStateSnapshot last = null; + for (CpuStateSnapshot bgn : bgn.pidCurrCupSateList) { + if (bgn.pid == end.pid) { + last = bgn; + break; + } + } + if (last == null) { + // newAdded Pid + CpuStateSnapshot empty = new CpuStateSnapshot(); + empty.pid = end.pid; + empty.name = end.name; + empty.procCpuCoreStates = new ArrayList<>(end.procCpuCoreStates.size()); + for (ListEntry> item : end.procCpuCoreStates) { + long[] emptyStats = new long[item.getList().size()]; + empty.procCpuCoreStates.add(ListEntry.ofDigits(emptyStats)); + } + last = empty; + } + Delta deltaPidCpuState = end.diff(last); + delta.pidDeltaCpuSateList.add(deltaPidCpuState); + } + } + return delta; + } + }; + } + + + public static class IpcCpuStat { + public static RemoteStat toIpc(CpuStateSnapshot local) { + RemoteStat remote = new RemoteStat(); + remote.procCpuCoreStates = new ArrayList<>(local.procCpuCoreStates.size()); + for (ListEntry> item : local.procCpuCoreStates) { + long[] stats = new long[item.getList().size()]; + for (int i = 0; i < stats.length; i++) { + stats[i] = item.getList().get(i).get(); + } + remote.procCpuCoreStates.add(stats); + } + return remote; + } + + public static CpuStateSnapshot toLocal(RemoteStat remote) { + CpuStateSnapshot local = new CpuStateSnapshot(); + local.procCpuCoreStates = new ArrayList<>(remote.procCpuCoreStates.size()); + for (long[] item : remote.procCpuCoreStates) { + local.procCpuCoreStates.add(ListEntry.ofDigits(item)); + } + return local; + } + + public static class RemoteStat implements Parcelable { + public List procCpuCoreStates = Collections.emptyList(); + + public RemoteStat() { + } + + protected RemoteStat(Parcel in) { + int size = in.readInt(); + procCpuCoreStates = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + procCpuCoreStates.add(in.createLongArray()); + } + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + int numOfArrays = procCpuCoreStates.size(); + dest.writeInt(numOfArrays); + for (int i = 0; i < numOfArrays; i++) { + dest.writeLongArray(procCpuCoreStates.get(i)); + } + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public RemoteStat createFromParcel(Parcel in) { + return new RemoteStat(in); + } + @Override + public RemoteStat[] newArray(int size) { + return new RemoteStat[size]; + } + }; + } + } + } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 3d3c6cffc..58bf20830 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -728,7 +728,7 @@ public static double calcSystemServicePower(PowerProfile powerProfile, HealthSta } /** - * @see com.android.internal.os.IdlePowerCalculator#IdlePowerCalculator + * @see com.android.internal.os.IdlePowerCalculator */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcIdlePower(PowerProfile powerProfile, HealthStats healthStats) { From fc3a0e0b3a4fde2918da021ae91e76b1651a93b4 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 24 Aug 2022 18:33:04 +0800 Subject: [PATCH 142/263] Fix import compile issues --- .../batterycanary/monitor/feature/CpuStatFeature.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java index a0fa12a7d..e04b5ee75 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java @@ -261,7 +261,7 @@ protected CpuStateSnapshot computeDelta() { } } - public static final class UidCpuStateSnapshot extends Snapshot { + public static final class UidCpuStateSnapshot extends MonitorFeature.Snapshot { public static UidCpuStateSnapshot of(Context context, BatteryMonitorConfig config) { UidCpuStateSnapshot curr = new UidCpuStateSnapshot(); try { @@ -290,11 +290,11 @@ public static UidCpuStateSnapshot of(Context context, BatteryMonitorConfig confi } public List pidCurrCupSateList = Collections.emptyList(); - public List> pidDeltaCpuSateList = Collections.emptyList(); + public List> pidDeltaCpuSateList = Collections.emptyList(); @Override - public Delta diff(UidCpuStateSnapshot bgn) { - return new Delta(bgn, this) { + public MonitorFeature.Snapshot.Delta diff(UidCpuStateSnapshot bgn) { + return new MonitorFeature.Snapshot.Delta(bgn, this) { @Override protected UidCpuStateSnapshot computeDelta() { UidCpuStateSnapshot delta = new UidCpuStateSnapshot(); @@ -320,7 +320,7 @@ protected UidCpuStateSnapshot computeDelta() { } last = empty; } - Delta deltaPidCpuState = end.diff(last); + MonitorFeature.Snapshot.Delta deltaPidCpuState = end.diff(last); delta.pidDeltaCpuSateList.add(deltaPidCpuState); } } From a619bb331ec606eb059ba3fc31a34f75b82b291f Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 24 Aug 2022 19:20:10 +0800 Subject: [PATCH 143/263] Update powerProfile with dsp audio/video --- .../matrix/batterycanary/stats/HealthStatsHelper.java | 6 ++++++ .../tencent/matrix/batterycanary/utils/PowerProfile.java | 2 ++ 2 files changed, 8 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 58bf20830..e447a03a9 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -653,6 +653,9 @@ public static double calcFlashLightPower(PowerProfile powerProfile, HealthStats public static double calcAudioPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_AUDIO); double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_AUDIO); + if (powerMa == 0) { + powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_AUDIO_DSP); + } double power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); if (power > 0) { return power; @@ -667,6 +670,9 @@ public static double calcAudioPower(PowerProfile powerProfile, HealthStats healt public static double calcVideoPower(PowerProfile powerProfile, HealthStats healthStats) { long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_VIDEO); double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_VIDEO); + if (powerMa == 0) { + powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_VIDEO_DSP); + } double power = new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); if (power > 0) { return power; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java index d2a73256d..6b38c364b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/PowerProfile.java @@ -244,12 +244,14 @@ public int getClusterByCpuNum(int cpuCoreNum) { * to the CPU power, probably due to a DSP and / or amplifier. */ public static final String POWER_AUDIO = "audio"; + public static final String POWER_AUDIO_DSP = "dsp.audio"; /** * Power consumed by any media hardware when playing back video content. This is in addition * to the CPU power, probably due to a DSP. */ public static final String POWER_VIDEO = "video"; + public static final String POWER_VIDEO_DSP = "dsp.video"; /** * Average power consumption when camera flashlight is on. From 7a25bd9cadab23b6c60ae8b4862fc8351cfe897e Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 24 Aug 2022 21:09:00 +0800 Subject: [PATCH 144/263] Update uid cpustate cfg --- .../monitor/feature/CompositeMonitors.java | 250 +++++++++++++++++- .../monitor/feature/CpuStatFeature.java | 92 ++++--- 2 files changed, 297 insertions(+), 45 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 2f4decf14..9b0acdb6f 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -1,5 +1,6 @@ package com.tencent.matrix.batterycanary.monitor.feature; +import android.annotation.SuppressLint; import android.os.Build; import android.os.Bundle; import android.os.SystemClock; @@ -15,6 +16,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; import com.tencent.matrix.batterycanary.stats.HealthStatsFeature; import com.tencent.matrix.batterycanary.stats.HealthStatsFeature.HealthStatsSnapshot; +import com.tencent.matrix.batterycanary.stats.HealthStatsHelper; import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.Consumer; import com.tencent.matrix.batterycanary.utils.Function; @@ -389,12 +391,7 @@ public void finish() { mAppStats = AppStats.current(SystemClock.uptimeMillis() - mBgnMillis); // For further procedures - // getDelta(HealthStatsSnapshot.class, new Consumer>() { - // @Override - // public void accept(Delta delta) { - // delta.dlt.estimateTestsPowers(CompositeMonitors.this); - // } - // }); + polishEstimatedPower(); } protected void configureBgnSnapshots() { @@ -972,4 +969,245 @@ public void count(int[] cpuCurrentFreq) { } } } + + + protected void polishEstimatedPower() { + getDelta(HealthStatsFeature.HealthStatsSnapshot.class, new Consumer>() { + @Override + public void accept(Delta healthStatsDelta) { + // Reset cpuPower if exists + tuningPowers(healthStatsDelta.dlt); + double cpuPower = 0; + Object powers = healthStatsDelta.dlt.extras.get("JiffyUid"); + if (powers instanceof Map) { + // Take power-cpu-uidDiff or 0 as default + Object val = ((Map) powers).get("power-cpu-uidDiff"); + if (val instanceof Double) { + cpuPower = (double) val; + } + } + healthStatsDelta.dlt.cpuPower = DigitEntry.of(cpuPower); + } + }); + } + + protected void tuningPowers(final HealthStatsFeature.HealthStatsSnapshot snapshot) { + if (!snapshot.isDelta) { + throw new IllegalStateException("Only support delta snapshot"); + } + final Tuner tuner = new Tuner(); + getFeature(CpuStatFeature.class, new Consumer() { + @Override + public void accept(CpuStatFeature feat) { + if (feat.isSupported()) { + final PowerProfile powerProfile = feat.getPowerProfile(); + getDelta(CpuStatFeature.CpuStateSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta cpuStatDelta) { + // CpuTimeMs + getDelta(HealthStatsFeature.HealthStatsSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta healthStats) { + healthStats.dlt.extras.put("TimeUid", tuner.tuningCpuPowers(powerProfile, CompositeMonitors.this, new Tuner.CpuTime() { + @Override + public long getBgnMs(String procSuffix) { + return getCpuTimeMs(procSuffix, healthStats.bgn); + } + + @Override + public long getEndMs(String procSuffix) { + return getCpuTimeMs(procSuffix, healthStats.end); + } + + @Override + public long getDltMs(String procSuffix) { + return getCpuTimeMs(procSuffix, healthStats.dlt); + } + + private long getCpuTimeMs(String procSuffix, HealthStatsFeature.HealthStatsSnapshot healthStatsSnapshot) { + if (procSuffix == null) { + return healthStatsSnapshot.cpuUsrTimeMs.get() + + healthStatsSnapshot.cpuSysTimeMs.get(); + } else { + if (mMonitor != null) { + String procName = mMonitor.getContext().getPackageName(); + if ("main".equals(procSuffix)) { + procName = mMonitor.getContext().getPackageName() + ":" + procSuffix; + } + DigitEntry usrTime = healthStatsSnapshot.procStatsCpuUsrTimeMs.get(procName); + DigitEntry sysTime = healthStatsSnapshot.procStatsCpuSysTimeMs.get(procName); + return (usrTime == null ? 0 : usrTime.get()) + (sysTime == null ? 0 : sysTime.get()); + } + } + return 0L; + } + })); + } + }); + + // CpuTimeJiffies + getDelta(JiffiesMonitorFeature.UidJiffiesSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta delta) { + snapshot.extras.put("JiffyUid", tuner.tuningCpuPowers(powerProfile, CompositeMonitors.this, new Tuner.CpuTime() { + @Override + public long getBgnMs(String procSuffix) { + if (procSuffix == null) { + // All + return delta.bgn.totalUidJiffies.get() * 10L; + } else { + for (JiffiesSnapshot item : delta.bgn.pidCurrJiffiesList) { + if (item.name.equals(procSuffix)) { + return item.totalJiffies.get() * 10L; + } + } + } + return 0L; + } + @Override + public long getEndMs(String procSuffix) { + if (procSuffix == null) { + // All + return delta.end.totalUidJiffies.get() * 10L; + } else { + for (JiffiesSnapshot item : delta.end.pidCurrJiffiesList) { + if (item.name.equals(procSuffix)) { + return item.totalJiffies.get() * 10L; + } + } + } + return 0L; + } + @Override + public long getDltMs(String procSuffix) { + if (procSuffix == null) { + // All + return delta.dlt.totalUidJiffies.get() * 10L; + } else { + for (Delta item : delta.dlt.pidDeltaJiffiesList) { + if (item.dlt.name.equals(procSuffix)) { + return item.dlt.totalJiffies.get() * 10L; + } + } + } + return 0L; + } + })); + } + }); + } + }); + } + } + }); + } + + + @SuppressLint("RestrictedApi") + static class Tuner { + interface CpuTime { + long getBgnMs(String procSuffix); + long getEndMs(String procSuffix); + long getDltMs(String procSuffix); + } + + public Map tuningCpuPowers(final PowerProfile powerProfile, final CompositeMonitors monitors, final CpuTime cpuTime) { + final Map dict = new HashMap<>(); + monitors.getDelta(CpuStatFeature.UidCpuStateSnapshot.class, new Consumer>() { + @SuppressLint("VisibleForTests") + @Override + public void accept(Delta uidCpuStatDelta) { + // Calc by DIff + { + // UID Diff + double cpuPower = 0; + boolean scaled = false; + for (Delta cpuStateDelta : uidCpuStatDelta.dlt.pidDeltaCpuSateList) { + CpuStatFeature.CpuStateSnapshot cpuStatsSnapshot = cpuStateDelta.dlt; + long cpuTimeMs = cpuTime.getDltMs(cpuStatsSnapshot.name); + cpuPower += HealthStatsHelper.estimateCpuActivePower(powerProfile, cpuTimeMs) + + HealthStatsHelper.estimateCpuClustersPowerByUidStats(powerProfile, cpuStatsSnapshot, cpuTimeMs, scaled) + + HealthStatsHelper.estimateCpuCoresPowerByUidStats(powerProfile, cpuStatsSnapshot, cpuTimeMs, scaled); + } + dict.put("power-cpu-uidDiff", cpuPower); + } + { + // UID Diff Scaled + double cpuPower = 0; + boolean scaled = true; + for (Delta cpuStateDelta : uidCpuStatDelta.dlt.pidDeltaCpuSateList) { + CpuStatFeature.CpuStateSnapshot cpuStatsSnapshot = cpuStateDelta.dlt; + long cpuTimeMs = cpuTime.getDltMs(cpuStatsSnapshot.name); + cpuPower += HealthStatsHelper.estimateCpuActivePower(powerProfile, cpuTimeMs) + + HealthStatsHelper.estimateCpuClustersPowerByUidStats(powerProfile, cpuStatsSnapshot, cpuTimeMs, scaled) + + HealthStatsHelper.estimateCpuCoresPowerByUidStats(powerProfile, cpuStatsSnapshot, cpuTimeMs, scaled); + } + dict.put("power-cpu-uidDiffScale", cpuPower); + } + + monitors.getDelta(CpuStatFeature.CpuStateSnapshot.class, new Consumer>() { + @Override + public void accept(Delta pidCpuStatDelta) { + { + // DEV Diff + CpuStatFeature.CpuStateSnapshot cpuStatsSnapshot = pidCpuStatDelta.dlt; + long cpuTimeMs = cpuTime.getDltMs(null); + double cpuPower = HealthStatsHelper.estimateCpuActivePower(powerProfile, cpuTimeMs) + + HealthStatsHelper.estimateCpuClustersPowerByDevStats(powerProfile, cpuStatsSnapshot, cpuTimeMs) + + HealthStatsHelper.estimateCpuCoresPowerByDevStats(powerProfile, cpuStatsSnapshot, cpuTimeMs); + dict.put("power-cpu-devDiff", cpuPower); + } + { + // CpuFreq Diff + CompositeMonitors.CpuFreqSampler cpuFreqSampler = monitors.getCpuFreqSampler(); + if (cpuFreqSampler != null) { + if (cpuFreqSampler.isCompat(powerProfile)) { + long cpuTimeMs = cpuTime.getDltMs(null); + double cpuPower = HealthStatsHelper.estimateCpuActivePower(powerProfile, cpuTimeMs) + + estimateCpuPowerByCpuFreqStats(powerProfile, cpuFreqSampler, cpuTimeMs); + dict.put("power-cpu-cpuFreq", cpuPower); + } + } + } + } + }); + } + }); + + return dict; + } + + private static double estimateCpuPowerByCpuFreqStats(PowerProfile powerProfile, CompositeMonitors.CpuFreqSampler sampler, long cpuTimeMs) { + double powerMah = 0; + if (cpuTimeMs > 0) { + long totalSum = 0; + for (int i = 0; i < sampler.cpuFreqCounters.size(); i++) { + for (int j = 0; j < sampler.cpuFreqCounters.get(i).length; j++) { + totalSum += sampler.cpuFreqCounters.get(i)[j]; + } + } + if (totalSum > 0) { + for (int i = 0; i < sampler.cpuFreqCounters.size(); i++) { + int clusterNum = powerProfile.getClusterByCpuNum(i); + long coreSum = 0; + for (int j = 0; j < sampler.cpuFreqCounters.get(i).length; j++) { + int step = sampler.cpuFreqCounters.get(i)[j]; + if (step > 0) { + long figuredCoreTimeMs = (long) ((step * 1.0f / totalSum) * cpuTimeMs); + double powerMa = powerProfile.getAveragePowerForCpuCore(clusterNum, j); + powerMah += new HealthStatsHelper.UsageBasedPowerEstimator(powerMa).calculatePower(figuredCoreTimeMs); + } + coreSum += step; + } + if (coreSum > 0) { + long figuredClusterTimeMs = (long) ((coreSum * 1.0f / totalSum) * cpuTimeMs); + double powerMa = powerProfile.getAveragePowerForCpuCluster(clusterNum); + powerMah += new HealthStatsHelper.UsageBasedPowerEstimator(powerMa).calculatePower(figuredClusterTimeMs); + } + } + } + } + return powerMah; + } + } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java index e04b5ee75..6e9aefe36 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CpuStatFeature.java @@ -1,11 +1,9 @@ package com.tencent.matrix.batterycanary.monitor.feature; -import android.content.Context; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; -import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.ListEntry; import com.tencent.matrix.batterycanary.shell.TopThreadFeature; @@ -14,6 +12,7 @@ import com.tencent.matrix.batterycanary.utils.KernelCpuSpeedReader; import com.tencent.matrix.batterycanary.utils.KernelCpuUidFreqTimeReader; import com.tencent.matrix.batterycanary.utils.PowerProfile; +import com.tencent.matrix.batterycanary.utils.ProcStatUtil; import com.tencent.matrix.util.MatrixLog; import java.io.IOException; @@ -106,6 +105,10 @@ public PowerProfile getPowerProfile() { } public CpuStateSnapshot currentCpuStateSnapshot() { + return currentCpuStateSnapshot(Process.myPid()); + } + + public CpuStateSnapshot currentCpuStateSnapshot(int pid) { CpuStateSnapshot snapshot = new CpuStateSnapshot(); try { if (!isSupported()) { @@ -116,21 +119,22 @@ public CpuStateSnapshot currentCpuStateSnapshot() { throw new IOException("PowerProfile not supported"); } // Cpu core steps jiffies - snapshot.cpuCoreStates = new ArrayList<>(); - for (int i = 0; i < mPowerProfile.getCpuCoreNum(); i++) { - final int numSpeedSteps = mPowerProfile.getNumSpeedStepsInCpuCluster(mPowerProfile.getClusterByCpuNum(i)); - KernelCpuSpeedReader cpuStepJiffiesReader = new KernelCpuSpeedReader(i, numSpeedSteps); - long[] cpuCoreStepJiffies = cpuStepJiffiesReader.readAbsolute(); - ListEntry> cpuCoreState = ListEntry.ofDigits(cpuCoreStepJiffies); - snapshot.cpuCoreStates.add(cpuCoreState); + if (pid == Process.myPid()) { + snapshot.cpuCoreStates = new ArrayList<>(); + for (int i = 0; i < mPowerProfile.getCpuCoreNum(); i++) { + final int numSpeedSteps = mPowerProfile.getNumSpeedStepsInCpuCluster(mPowerProfile.getClusterByCpuNum(i)); + KernelCpuSpeedReader cpuStepJiffiesReader = new KernelCpuSpeedReader(i, numSpeedSteps); + long[] cpuCoreStepJiffies = cpuStepJiffiesReader.readAbsolute(); + ListEntry> cpuCoreState = ListEntry.ofDigits(cpuCoreStepJiffies); + snapshot.cpuCoreStates.add(cpuCoreState); + } } - // Proc cluster steps jiffies int[] clusterSteps = new int[mPowerProfile.getNumCpuClusters()]; for (int i = 0; i < clusterSteps.length; i++) { clusterSteps[i] = mPowerProfile.getNumSpeedStepsInCpuCluster(i); } - KernelCpuUidFreqTimeReader procStepJiffiesReader = new KernelCpuUidFreqTimeReader(Process.myPid(), clusterSteps); + KernelCpuUidFreqTimeReader procStepJiffiesReader = new KernelCpuUidFreqTimeReader(pid, clusterSteps); List procStepJiffies = procStepJiffiesReader.readAbsolute(); snapshot.procCpuCoreStates = new ArrayList<>(); for (long[] item : procStepJiffies) { @@ -146,7 +150,44 @@ public CpuStateSnapshot currentCpuStateSnapshot() { } public UidCpuStateSnapshot currentUidCpuStateSnapshot() { - return UidCpuStateSnapshot.of(mCore.getContext(), mCore.getConfig()); + UidCpuStateSnapshot curr = new UidCpuStateSnapshot(); + try { + List> procList = TopThreadFeature.getProcList(mCore.getContext()); + curr.pidCurrCupSateList = new ArrayList<>(procList.size()); + + for (Pair item : procList) { + //noinspection ConstantConditions + int pid = item.first; + String procName = String.valueOf(item.second); + CpuStateSnapshot snapshot = null; + + if (pid == Process.myPid()) { + // from local + snapshot = currentCpuStateSnapshot(); + } else { + if (ProcStatUtil.exists(pid)) { + // from pid + snapshot = currentCpuStateSnapshot(pid); + } + if (snapshot != null && !snapshot.isValid() && mCore.getConfig().ipcCpuStatCollector != null) { + // from ipc + UidCpuStateSnapshot.IpcCpuStat.RemoteStat remote = mCore.getConfig().ipcCpuStatCollector.apply(item); + if (remote != null) { + snapshot = UidCpuStateSnapshot.IpcCpuStat.toLocal(remote); + } + } + } + if (snapshot != null) { + snapshot.pid = pid; + snapshot.name = TopThreadIndicator.getProcSuffix(procName); + curr.pidCurrCupSateList.add(snapshot); + } + } + } catch (Exception e) { + MatrixLog.w(TAG, "get curr UidCpuStatSnapshot failed: " + e.getMessage()); + curr.setValid(false); + } + return curr; } public static final class CpuStateSnapshot extends Snapshot { @@ -262,33 +303,6 @@ protected CpuStateSnapshot computeDelta() { } public static final class UidCpuStateSnapshot extends MonitorFeature.Snapshot { - public static UidCpuStateSnapshot of(Context context, BatteryMonitorConfig config) { - UidCpuStateSnapshot curr = new UidCpuStateSnapshot(); - try { - List> procList = TopThreadFeature.getProcList(context); - curr.pidCurrCupSateList = new ArrayList<>(procList.size()); - - for (Pair item : procList) { - //noinspection ConstantConditions - int pid = item.first; - String procName = String.valueOf(item.second); - if (config.ipcCpuStatCollector != null) { - IpcCpuStat.RemoteStat remote = config.ipcCpuStatCollector.apply(item); - if (remote != null) { - CpuStateSnapshot snapshot = IpcCpuStat.toLocal(remote); - snapshot.pid = pid; - snapshot.name = TopThreadIndicator.getProcSuffix(procName); - curr.pidCurrCupSateList.add(snapshot); - } - } - } - } catch (Exception e) { - MatrixLog.w(TAG, "get curr UidCpuStatSnapshot failed: " + e.getMessage()); - curr.setValid(false); - } - return curr; - } - public List pidCurrCupSateList = Collections.emptyList(); public List> pidDeltaCpuSateList = Collections.emptyList(); From c1ea5130254096724d7cee8020d61743c1f78866 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 25 Aug 2022 21:03:56 +0800 Subject: [PATCH 145/263] Update power tuning with mobile & wifi --- .../batterycanary/stats/HealthStatsTest.java | 20 ++++ .../src/main/AndroidManifest.xml | 1 + .../monitor/feature/CompositeMonitors.java | 56 +++++++-- .../feature/TrafficMonitorFeature.java | 16 +++ .../stats/HealthStatsHelper.java | 110 ++++++++++++++++++ .../batterycanary/utils/RadioStatUtil.java | 17 ++- 6 files changed, 209 insertions(+), 11 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 4a8f3deba..4522abe0c 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -708,6 +708,26 @@ public void testGetCurrSnapshot() { Assert.assertEquals(delta.dlt.getTotalPower(), end.getTotalPower() - bgn.getTotalPower(), 0.001d); } + @Test + public void testCalcAvgPowerPerPacket() throws IOException { + PowerProfile powerProfile = PowerProfile.init(mContext); + Assert.assertNotNull(powerProfile); + Assert.assertTrue(powerProfile.isSupported()); + + final long MOBILE_BPS = 200000; + final double MOBILE_POWER = powerProfile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ACTIVE, 120) / 3600; + final double mobilePps = (((double) MOBILE_BPS) / 8 / 2048); + double mobilePowerPerPacket = (MOBILE_POWER / mobilePps) / (60 * 60); + Assert.assertTrue(mobilePowerPerPacket > 0); + + final long wifiBps = 1000000; + final double averageWifiActivePower = powerProfile.getAveragePowerOrDefault(PowerProfile.POWER_WIFI_ACTIVE, 120) / 3600; + double wifiPowerPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); + Assert.assertTrue(wifiPowerPerPacket > 0); + + Assert.assertTrue(mobilePowerPerPacket < wifiPowerPerPacket); + } + public static class UsageBasedPowerEstimator { private static final double MILLIS_IN_HOUR = 1000.0 * 60 * 60; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/AndroidManifest.xml b/matrix/matrix-android/matrix-battery-canary/src/main/AndroidManifest.xml index a7cd0a922..8bddbf7a1 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + >() { @Override public void accept(Delta healthStatsDelta) { - // Reset cpuPower if exists tuningPowers(healthStatsDelta.dlt); - double cpuPower = 0; - Object powers = healthStatsDelta.dlt.extras.get("JiffyUid"); - if (powers instanceof Map) { - // Take power-cpu-uidDiff or 0 as default - Object val = ((Map) powers).get("power-cpu-uidDiff"); + + { + // Reset cpuPower if exists + double power = 0; + Object powers = healthStatsDelta.dlt.extras.get("JiffyUid"); + if (powers instanceof Map) { + // Take power-cpu-uidDiff or 0 as default + Object val = ((Map) powers).get("power-cpu-uidDiff"); + if (val instanceof Double) { + power = (double) val; + } + } + healthStatsDelta.dlt.cpuPower = DigitEntry.of(power); + } + { + // Reset mobilePower if exists + double power = 0; + Object val = healthStatsDelta.dlt.extras.get("power-mobile-statByte"); if (val instanceof Double) { - cpuPower = (double) val; + power = (double) val; } + healthStatsDelta.dlt.mobilePower = DigitEntry.of(power); + } + { + // Reset wifiPower if exists + double power = 0; + Object val = healthStatsDelta.dlt.extras.get("power-wifi-statByte"); + if (val instanceof Double) { + power = (double) val; + } + healthStatsDelta.dlt.wifiPower = DigitEntry.of(power); } - healthStatsDelta.dlt.cpuPower = DigitEntry.of(cpuPower); } }); } @@ -1001,6 +1022,8 @@ protected void tuningPowers(final HealthStatsFeature.HealthStatsSnapshot snapsho public void accept(CpuStatFeature feat) { if (feat.isSupported()) { final PowerProfile powerProfile = feat.getPowerProfile(); + + // Tune CPU getDelta(CpuStatFeature.CpuStateSnapshot.class, new Consumer>() { @Override public void accept(final Delta cpuStatDelta) { @@ -1097,6 +1120,23 @@ public long getDltMs(String procSuffix) { }); } }); + + // Tune Network + getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP && mMonitor != null) { + { + double power = HealthStatsHelper.calcMobilePowerByNetworkStatBytes(mMonitor.getContext(), powerProfile, delta.dlt); + snapshot.extras.put("power-mobile-statByte", power); + } + { + double power = HealthStatsHelper.calcWifiPowerByNetworkStatBytes(mMonitor.getContext(), powerProfile, delta.dlt); + snapshot.extras.put("power-wifi-statByte", power); + } + } + } + }); } } }); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/TrafficMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/TrafficMonitorFeature.java index b63877e0f..9e001d88f 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/TrafficMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/TrafficMonitorFeature.java @@ -35,19 +35,30 @@ public TrafficMonitorFeature.RadioStatSnapshot currentRadioSnapshot(Context cont if (stat == null) { return null; } + TrafficMonitorFeature.RadioStatSnapshot snapshot = new TrafficMonitorFeature.RadioStatSnapshot(); snapshot.wifiRxBytes = Snapshot.Entry.DigitEntry.of(stat.wifiRxBytes); snapshot.wifiTxBytes = Snapshot.Entry.DigitEntry.of(stat.wifiTxBytes); + snapshot.wifiRxPackets = Snapshot.Entry.DigitEntry.of(stat.wifiRxPackets); + snapshot.wifiTxPackets = Snapshot.Entry.DigitEntry.of(stat.wifiTxPackets); + snapshot.mobileRxBytes = Snapshot.Entry.DigitEntry.of(stat.mobileRxBytes); snapshot.mobileTxBytes = Snapshot.Entry.DigitEntry.of(stat.mobileTxBytes); + snapshot.mobileRxPackets = Snapshot.Entry.DigitEntry.of(stat.mobileRxPackets); + snapshot.mobileTxPackets = Snapshot.Entry.DigitEntry.of(stat.mobileTxPackets); return snapshot; } public static class RadioStatSnapshot extends Snapshot { public Entry.DigitEntry wifiRxBytes = Entry.DigitEntry.of(0L); public Entry.DigitEntry wifiTxBytes = Entry.DigitEntry.of(0L); + public Entry.DigitEntry wifiRxPackets = Entry.DigitEntry.of(0L); + public Entry.DigitEntry wifiTxPackets = Entry.DigitEntry.of(0L); + public Entry.DigitEntry mobileRxBytes = Entry.DigitEntry.of(0L); public Entry.DigitEntry mobileTxBytes = Entry.DigitEntry.of(0L); + public Entry.DigitEntry mobileRxPackets = Entry.DigitEntry.of(0L); + public Entry.DigitEntry mobileTxPackets = Entry.DigitEntry.of(0L); @Override public Delta diff(RadioStatSnapshot bgn) { @@ -57,8 +68,13 @@ protected RadioStatSnapshot computeDelta() { RadioStatSnapshot delta = new RadioStatSnapshot(); delta.wifiRxBytes = DigitDiffer.globalDiff(bgn.wifiRxBytes, end.wifiRxBytes); delta.wifiTxBytes = DigitDiffer.globalDiff(bgn.wifiTxBytes, end.wifiTxBytes); + delta.wifiRxPackets = DigitDiffer.globalDiff(bgn.wifiRxPackets, end.wifiRxPackets); + delta.wifiTxPackets = DigitDiffer.globalDiff(bgn.wifiTxPackets, end.wifiTxPackets); + delta.mobileRxBytes = DigitDiffer.globalDiff(bgn.mobileRxBytes, end.mobileRxBytes); delta.mobileTxBytes = DigitDiffer.globalDiff(bgn.mobileTxBytes, end.mobileTxBytes); + delta.mobileRxPackets = DigitDiffer.globalDiff(bgn.mobileRxPackets, end.mobileRxPackets); + delta.mobileTxPackets = DigitDiffer.globalDiff(bgn.mobileTxPackets, end.mobileTxPackets); return delta; } }; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index e447a03a9..340ffba8e 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -1,9 +1,15 @@ package com.tencent.matrix.batterycanary.stats; +import android.Manifest; import android.annotation.SuppressLint; import android.content.Context; +import android.content.pm.PackageManager; import android.hardware.Sensor; import android.hardware.SensorManager; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; import android.os.Build; import android.os.health.HealthStats; import android.os.health.SystemHealthManager; @@ -15,6 +21,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature.CpuStateSnapshot; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.ListEntry; +import com.tencent.matrix.batterycanary.monitor.feature.TrafficMonitorFeature; import com.tencent.matrix.batterycanary.utils.PowerProfile; import com.tencent.matrix.util.MatrixLog; @@ -444,6 +451,51 @@ public static double calcMobilePowerByController(PowerProfile powerProfile, Heal return power; } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public static double calcMobilePowerByNetworkStatBytes(Context context, PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot) { + if (context.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_GRANTED) { + ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + int txBwKBps = 0, rxBwKBps = 0; + for (Network item : manager.getAllNetworks()) { + NetworkInfo networkInfo = manager.getNetworkInfo(item); + if (networkInfo != null + && (networkInfo.isConnected() || networkInfo.isConnectedOrConnecting()) + && networkInfo.getTypeName().equalsIgnoreCase("MOBILE")) { + NetworkCapabilities capabilities = manager.getNetworkCapabilities(item); + if (capabilities != null) { + txBwKBps = capabilities.getLinkUpstreamBandwidthKbps() / 8; + rxBwKBps = capabilities.getLinkDownstreamBandwidthKbps() / 8; + if (txBwKBps > 0 || rxBwKBps > 0) { + break; + } + } + } + } + if (txBwKBps > 0 || rxBwKBps > 0) { + long txMs = (long) ((snapshot.mobileTxBytes.get() / (1000f * txBwKBps)) * 1000); + long rxMs = (long) ((snapshot.mobileRxBytes.get() / (1000f * rxBwKBps)) * 1000); + double power = 0; + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_RX); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(rxMs); + } + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_TX); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(txMs); + } + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_IDLE); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(txMs + rxMs); + } + return power; + } + } + return 0; + } + /** * @see com.android.internal.os.WifiPowerCalculator */ @@ -519,6 +571,64 @@ public static double calcWifiPowerByPackets(PowerProfile powerProfile, HealthSta return power; } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public static double calcWifiPowerByNetworkStatBytes(Context context, PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot) { + if (context.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_GRANTED) { + ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + int txBwKBps = 0, rxBwKBps = 0; + for (Network item : manager.getAllNetworks()) { + NetworkInfo networkInfo = manager.getNetworkInfo(item); + if (networkInfo != null + && (networkInfo.isConnected() || networkInfo.isConnectedOrConnecting()) + && networkInfo.getTypeName().equalsIgnoreCase("WIFI")) { + NetworkCapabilities capabilities = manager.getNetworkCapabilities(item); + if (capabilities != null) { + txBwKBps = capabilities.getLinkUpstreamBandwidthKbps() / 8; + rxBwKBps = capabilities.getLinkDownstreamBandwidthKbps() / 8; + if (txBwKBps > 0 || rxBwKBps > 0) { + break; + } + } + } + } + if (txBwKBps > 0 || rxBwKBps > 0) { + long txMs = (long) ((snapshot.wifiTxBytes.get() / (1000f * txBwKBps)) * 1000); + long rxMs = (long) ((snapshot.wifiRxBytes.get() / (1000f * rxBwKBps)) * 1000); + double power = 0; + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_RX); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(rxMs); + } + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_TX); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(txMs); + } + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_IDLE); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(txMs + rxMs); + } + return power; + } + } + return 0; + } + + @VisibleForTesting + public static double calcWifiPowerByNetworkStatPackets(PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot) { + double power = 0; + { + final long wifiBps = 1000000; + final double averageWifiActivePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ACTIVE) / 3600; + double powerMaPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); + long packets = snapshot.wifiRxPackets.get() + snapshot.wifiTxPackets.get(); + power += powerMaPerPacket * packets; + } + return power; + } + /** * @see com.android.internal.os.BluetoothPowerCalculator */ diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java index a8afc57be..b6f66912d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java @@ -4,6 +4,7 @@ import android.app.usage.NetworkStatsManager; import android.content.Context; import android.net.NetworkCapabilities; + import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; @@ -20,6 +21,7 @@ public final class RadioStatUtil { private static final String TAG = "Matrix.battery.ProcStatUtil"; static final long MIN_QUERY_INTERVAL = BuildConfig.DEBUG ? 0L : 2000L; static long sLastQueryMillis; + static RadioStat sLastRef; private static boolean checkIfFrequently() { long currentTimeMillis = System.currentTimeMillis(); @@ -36,8 +38,7 @@ public static RadioStat getCurrentStat(Context context) { return null; } if (checkIfFrequently()) { - MatrixLog.i(TAG, "over frequently just return"); - return null; + return sLastRef; } try { @@ -53,6 +54,8 @@ public static RadioStat getCurrentStat(Context context) { if (bucket.getUid() == android.os.Process.myUid()) { stat.wifiRxBytes += bucket.getRxBytes(); stat.wifiTxBytes += bucket.getTxBytes(); + stat.wifiRxPackets += bucket.getRxPackets(); + stat.wifiTxPackets += bucket.getTxPackets(); } } } @@ -64,15 +67,18 @@ public static RadioStat getCurrentStat(Context context) { if (bucket.getUid() == android.os.Process.myUid()) { stat.mobileRxBytes += bucket.getRxBytes(); stat.mobileTxBytes += bucket.getTxBytes(); + stat.mobileRxPackets += bucket.getRxPackets(); + stat.mobileTxPackets += bucket.getTxPackets(); } } } } - + sLastRef = stat; return stat; } catch (Throwable e) { MatrixLog.w(TAG, "querySummary fail: " + e.getMessage()); + sLastRef = null; return null; } } @@ -80,7 +86,12 @@ public static RadioStat getCurrentStat(Context context) { public static final class RadioStat { public long wifiRxBytes; public long wifiTxBytes; + public long wifiRxPackets; + public long wifiTxPackets; + public long mobileRxBytes; public long mobileTxBytes; + public long mobileRxPackets; + public long mobileTxPackets; } } From c2aad283301d09e0e1f6ec2e048749aefd92f1c7 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 26 Aug 2022 15:22:31 +0800 Subject: [PATCH 146/263] MatrixTraceTransform: fix NoSuchMethodError with com.android.tools:commons:30+ --- .../tencent/matrix/plugin/transform/MatrixTraceTransform.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/transform/MatrixTraceTransform.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/transform/MatrixTraceTransform.kt index c024bc988..e32bb773a 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/transform/MatrixTraceTransform.kt +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/transform/MatrixTraceTransform.kt @@ -26,6 +26,7 @@ import com.tencent.matrix.plugin.trace.MatrixTrace import com.tencent.matrix.trace.Configuration import com.tencent.matrix.trace.extension.MatrixTraceExtension import org.gradle.api.Project +import shadow.bundletool.com.android.tools.r8.jetbrains.kotlin.io.FilesKt import java.io.File import java.util.concurrent.ConcurrentHashMap @@ -151,7 +152,7 @@ class MatrixTraceTransform( } private fun toOutputFile(outputDir: File, inputDir: File, inputFile: File): File { - return File(outputDir, FileUtils.relativePossiblyNonExistingPath(inputFile, inputDir)) + return File(outputDir, FilesKt.toRelativeString(inputFile, inputDir)) } private fun configure(transformInvocation: TransformInvocation): Configuration { From d3f39f3c21835b5860f3d57b62333c1d07ac5a7e Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 26 Aug 2022 16:35:58 +0800 Subject: [PATCH 147/263] MatrixTraceTransform: fix NoSuchMethodError with com.android.tools:commons:30+ --- matrix/matrix-android/matrix-arscutil/build.gradle | 2 +- .../tencent/matrix/plugin/transform/MatrixTraceTransform.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-arscutil/build.gradle b/matrix/matrix-android/matrix-arscutil/build.gradle index c85af8788..1a850c4b5 100644 --- a/matrix/matrix-android/matrix-arscutil/build.gradle +++ b/matrix/matrix-android/matrix-arscutil/build.gradle @@ -8,7 +8,7 @@ group rootProject.ext.GROUP dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'commons-io:commons-io:2.6' - compile project(':matrix-commons') + implementation project(':matrix-commons') } if("External" == rootProject.ext.PUBLISH_CHANNEL) { diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/transform/MatrixTraceTransform.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/transform/MatrixTraceTransform.kt index e32bb773a..43cf08862 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/transform/MatrixTraceTransform.kt +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/transform/MatrixTraceTransform.kt @@ -26,7 +26,6 @@ import com.tencent.matrix.plugin.trace.MatrixTrace import com.tencent.matrix.trace.Configuration import com.tencent.matrix.trace.extension.MatrixTraceExtension import org.gradle.api.Project -import shadow.bundletool.com.android.tools.r8.jetbrains.kotlin.io.FilesKt import java.io.File import java.util.concurrent.ConcurrentHashMap @@ -152,7 +151,7 @@ class MatrixTraceTransform( } private fun toOutputFile(outputDir: File, inputDir: File, inputFile: File): File { - return File(outputDir, FilesKt.toRelativeString(inputFile, inputDir)) + return File(outputDir, inputFile.toRelativeString(inputDir)) } private fun configure(transformInvocation: TransformInvocation): Configuration { From 063407aaf08b57f101a930e7f39e5693c8058f75 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 26 Aug 2022 20:23:41 +0800 Subject: [PATCH 148/263] Update battery power calc with bps --- .../monitor/feature/CompositeMonitors.java | 79 +++++++++-- .../monitor/feature/MonitorFeature.java | 1 + .../feature/TrafficMonitorFeature.java | 37 +++++ .../stats/HealthStatsHelper.java | 133 ++++++------------ .../batterycanary/utils/RadioStatUtil.java | 69 ++++++++- 5 files changed, 213 insertions(+), 106 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 96069010c..01deaf468 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -74,6 +74,8 @@ public class CompositeMonitors { protected AppStats mAppStats; @Nullable protected CpuFreqSampler mCpuFreqSampler; + @Nullable + protected BpsSampler mBpsSampler; protected long mBgnMillis = SystemClock.uptimeMillis(); protected String mScope; @@ -767,14 +769,31 @@ public Number apply(Snapshot.Sampler sampler) { } return sampler; } + if (snapshotClass == TrafficMonitorFeature.RadioBpsSnapshot.class) { + final TrafficMonitorFeature feature = getFeature(TrafficMonitorFeature.class); + if (feature != null && mMonitor != null) { + mBpsSampler = new BpsSampler(); + sampler = new MonitorFeature.Snapshot.Sampler("trafficBps", mMonitor.getHandler(), new Function() { + @Override + public Number apply(Snapshot.Sampler sampler) { + TrafficMonitorFeature.RadioBpsSnapshot snapshot = feature.currentRadioBpsSnapshot(mMonitor.getContext()); + if (snapshot != null) { + mBpsSampler.count(snapshot); + } + return 0; + } + }); + mSamplers.put(snapshotClass, sampler); + } + return sampler; + } if (snapshotClass == DeviceStatMonitorFeature.BatteryCurrentSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { sampler = new MonitorFeature.Snapshot.Sampler("batt-curr", mMonitor.getHandler(), new Function() { @Override public Number apply(Snapshot.Sampler sampler) { - DeviceStatMonitorFeature.BatteryCurrentSnapshot snapshot = feature.currentBatteryCurrency(mMonitor.getContext()); - Long value = snapshot.stat.get(); + long value = BatteryCanaryUtil.getBatteryCurrencyImmediately(mMonitor.getContext()); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); if (value == -1L) { return Snapshot.Sampler.INVALID; @@ -900,6 +919,11 @@ public CpuFreqSampler getCpuFreqSampler() { return mCpuFreqSampler; } + @Nullable + public BpsSampler getBpsSampler() { + return mBpsSampler; + } + @Override @NonNull public String toString() { @@ -945,7 +969,7 @@ public boolean isCompat(PowerProfile powerProfile) { } public void count(int[] cpuCurrentFreq) { - this.cpuCurrentFreq = BatteryCanaryUtil.getCpuCurrentFreq(); + this.cpuCurrentFreq = cpuCurrentFreq; for (int i = 0; i < cpuCurrentFreq.length; i++) { int speed = cpuCurrentFreq[i]; int[] steps = cpuFreqSteps.get(i); @@ -970,6 +994,29 @@ public void count(int[] cpuCurrentFreq) { } } + public static class BpsSampler { + public int count; + public long wifiRxBps; + public long wifiTxBps; + public long mobileRxBps; + public long mobileTxBps; + + public void count(TrafficMonitorFeature.RadioBpsSnapshot snapshot) { + count++; + wifiRxBps += snapshot.wifiRxBps.get(); + wifiTxBps += snapshot.wifiTxBps.get(); + mobileRxBps += snapshot.mobileRxBps.get(); + mobileTxBps += snapshot.mobileTxBps.get(); + } + + public double getAverage(long input) { + if (count != 0) { + return input * 1f / count; + } + return 0; + } + } + protected void polishEstimatedPower() { getDelta(HealthStatsFeature.HealthStatsSnapshot.class, new Consumer>() { @@ -1126,13 +1173,29 @@ public long getDltMs(String procSuffix) { @Override public void accept(Delta delta) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP && mMonitor != null) { - { - double power = HealthStatsHelper.calcMobilePowerByNetworkStatBytes(mMonitor.getContext(), powerProfile, delta.dlt); + BpsSampler bpsSampler = getBpsSampler(); + if (bpsSampler != null) { + // mobile + double power = HealthStatsHelper.calcMobilePowerByNetworkStatBytes( + powerProfile, + delta.dlt, + bpsSampler.getAverage(bpsSampler.mobileRxBps), + bpsSampler.getAverage(bpsSampler.mobileTxBps)); snapshot.extras.put("power-mobile-statByte", power); - } - { - double power = HealthStatsHelper.calcWifiPowerByNetworkStatBytes(mMonitor.getContext(), powerProfile, delta.dlt); + + // wifi + power = HealthStatsHelper.calcWifiPowerByNetworkStatBytes( + powerProfile, + delta.dlt, + bpsSampler.getAverage(bpsSampler.wifiRxBps), + bpsSampler.getAverage(bpsSampler.wifiTxBps)); snapshot.extras.put("power-wifi-statByte", power); + power = HealthStatsHelper.calcWifiPowerByNetworkStatPackets( + powerProfile, + delta.dlt, + bpsSampler.getAverage(bpsSampler.wifiRxBps), + bpsSampler.getAverage(bpsSampler.wifiTxBps)); + snapshot.extras.put("power-wifi-statPacket", power); } } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index a8f374bf9..ba2a28484 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -434,6 +434,7 @@ public void run() { if (!currSample.equals(INVALID)) { mSampleLst = currSample.doubleValue(); mCount++; + // FIXME: calc vag on finished mSampleAvg = (mSampleAvg * (mCount - 1) + mSampleLst) / mCount; if (mSampleFst == Double.MIN_VALUE) { mSampleFst = mSampleLst; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/TrafficMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/TrafficMonitorFeature.java index 9e001d88f..209760e52 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/TrafficMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/TrafficMonitorFeature.java @@ -49,6 +49,21 @@ public TrafficMonitorFeature.RadioStatSnapshot currentRadioSnapshot(Context cont return snapshot; } + @Nullable + public TrafficMonitorFeature.RadioBpsSnapshot currentRadioBpsSnapshot(Context context) { + RadioStatUtil.RadioBps stat = RadioStatUtil.getCurrentBps(context); + if (stat == null) { + return null; + } + + TrafficMonitorFeature.RadioBpsSnapshot snapshot = new TrafficMonitorFeature.RadioBpsSnapshot(); + snapshot.wifiRxBps = Snapshot.Entry.DigitEntry.of(stat.wifiRxBps); + snapshot.wifiTxBps = Snapshot.Entry.DigitEntry.of(stat.wifiTxBps); + snapshot.mobileRxBps = Snapshot.Entry.DigitEntry.of(stat.mobileRxBps); + snapshot.mobileTxBps = Snapshot.Entry.DigitEntry.of(stat.mobileTxBps); + return snapshot; + } + public static class RadioStatSnapshot extends Snapshot { public Entry.DigitEntry wifiRxBytes = Entry.DigitEntry.of(0L); public Entry.DigitEntry wifiTxBytes = Entry.DigitEntry.of(0L); @@ -80,4 +95,26 @@ protected RadioStatSnapshot computeDelta() { }; } } + + public static class RadioBpsSnapshot extends Snapshot { + public Entry.DigitEntry wifiRxBps = Entry.DigitEntry.of(0L); + public Entry.DigitEntry wifiTxBps = Entry.DigitEntry.of(0L); + public Entry.DigitEntry mobileRxBps = Entry.DigitEntry.of(0L); + public Entry.DigitEntry mobileTxBps = Entry.DigitEntry.of(0L); + + @Override + public Delta diff(RadioBpsSnapshot bgn) { + return new Delta(bgn, this) { + @Override + protected RadioBpsSnapshot computeDelta() { + RadioBpsSnapshot delta = new RadioBpsSnapshot(); + delta.wifiRxBps = DigitDiffer.globalDiff(bgn.wifiRxBps, end.wifiRxBps); + delta.wifiTxBps = DigitDiffer.globalDiff(bgn.wifiTxBps, end.wifiTxBps); + delta.mobileRxBps = DigitDiffer.globalDiff(bgn.mobileRxBps, end.mobileRxBps); + delta.mobileTxBps = DigitDiffer.globalDiff(bgn.mobileTxBps, end.mobileTxBps); + return delta; + } + }; + } + } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 340ffba8e..115257640 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -1,15 +1,9 @@ package com.tencent.matrix.batterycanary.stats; -import android.Manifest; import android.annotation.SuppressLint; import android.content.Context; -import android.content.pm.PackageManager; import android.hardware.Sensor; import android.hardware.SensorManager; -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; import android.os.Build; import android.os.health.HealthStats; import android.os.health.SystemHealthManager; @@ -452,48 +446,26 @@ public static double calcMobilePowerByController(PowerProfile powerProfile, Heal } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public static double calcMobilePowerByNetworkStatBytes(Context context, PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot) { - if (context.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_GRANTED) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - int txBwKBps = 0, rxBwKBps = 0; - for (Network item : manager.getAllNetworks()) { - NetworkInfo networkInfo = manager.getNetworkInfo(item); - if (networkInfo != null - && (networkInfo.isConnected() || networkInfo.isConnectedOrConnecting()) - && networkInfo.getTypeName().equalsIgnoreCase("MOBILE")) { - NetworkCapabilities capabilities = manager.getNetworkCapabilities(item); - if (capabilities != null) { - txBwKBps = capabilities.getLinkUpstreamBandwidthKbps() / 8; - rxBwKBps = capabilities.getLinkDownstreamBandwidthKbps() / 8; - if (txBwKBps > 0 || rxBwKBps > 0) { - break; - } - } - } - } - if (txBwKBps > 0 || rxBwKBps > 0) { - long txMs = (long) ((snapshot.mobileTxBytes.get() / (1000f * txBwKBps)) * 1000); - long rxMs = (long) ((snapshot.mobileRxBytes.get() / (1000f * rxBwKBps)) * 1000); - double power = 0; - { - double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_RX); - UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); - power += estimator.calculatePower(rxMs); - } - { - double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_TX); - UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); - power += estimator.calculatePower(txMs); - } - { - double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_IDLE); - UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); - power += estimator.calculatePower(txMs + rxMs); - } - return power; - } + public static double calcMobilePowerByNetworkStatBytes(PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot, double rxBps, double txBps) { + long rxMs = (long) ((snapshot.mobileRxBytes.get() / (rxBps / 8)) * 1000); + long txMs = (long) ((snapshot.mobileTxBytes.get() / (txBps / 8)) * 1000); + double power = 0; + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_RX); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(rxMs); } - return 0; + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_TX); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(txMs); + } + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_MODEM_CONTROLLER_IDLE); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(txMs + rxMs); + } + return power; } /** @@ -572,56 +544,33 @@ public static double calcWifiPowerByPackets(PowerProfile powerProfile, HealthSta } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public static double calcWifiPowerByNetworkStatBytes(Context context, PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot) { - if (context.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_GRANTED) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - int txBwKBps = 0, rxBwKBps = 0; - for (Network item : manager.getAllNetworks()) { - NetworkInfo networkInfo = manager.getNetworkInfo(item); - if (networkInfo != null - && (networkInfo.isConnected() || networkInfo.isConnectedOrConnecting()) - && networkInfo.getTypeName().equalsIgnoreCase("WIFI")) { - NetworkCapabilities capabilities = manager.getNetworkCapabilities(item); - if (capabilities != null) { - txBwKBps = capabilities.getLinkUpstreamBandwidthKbps() / 8; - rxBwKBps = capabilities.getLinkDownstreamBandwidthKbps() / 8; - if (txBwKBps > 0 || rxBwKBps > 0) { - break; - } - } - } - } - if (txBwKBps > 0 || rxBwKBps > 0) { - long txMs = (long) ((snapshot.wifiTxBytes.get() / (1000f * txBwKBps)) * 1000); - long rxMs = (long) ((snapshot.wifiRxBytes.get() / (1000f * rxBwKBps)) * 1000); - double power = 0; - { - double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_RX); - UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); - power += estimator.calculatePower(rxMs); - } - { - double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_TX); - UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); - power += estimator.calculatePower(txMs); - } - { - double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_IDLE); - UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); - power += estimator.calculatePower(txMs + rxMs); - } - return power; - } + public static double calcWifiPowerByNetworkStatBytes(PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot, double rxBps, double txBps) { + long rxMs = (long) ((snapshot.wifiRxBytes.get() / (rxBps / 8)) * 1000); + long txMs = (long) ((snapshot.wifiTxBytes.get() / (txBps / 8)) * 1000); + double power = 0; + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_RX); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(rxMs); } - return 0; + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_TX); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(txMs); + } + { + double avgPower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_CONTROLLER_IDLE); + UsageBasedPowerEstimator estimator = new UsageBasedPowerEstimator(avgPower); + power += estimator.calculatePower(txMs + rxMs); + } + return power; } - @VisibleForTesting - public static double calcWifiPowerByNetworkStatPackets(PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot) { + public static double calcWifiPowerByNetworkStatPackets(PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot, double rxBps, double txBps) { double power = 0; { - final long wifiBps = 1000000; - final double averageWifiActivePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ACTIVE) / 3600; + final double wifiBps = rxBps + txBps; + final double averageWifiActivePower = powerProfile.getAveragePowerOrDefault(PowerProfile.POWER_WIFI_ACTIVE, 120) / 3600; double powerMaPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); long packets = snapshot.wifiRxPackets.get() + snapshot.wifiTxPackets.get(); power += powerMaPerPacket * packets; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java index b6f66912d..a96b9df6b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java @@ -1,16 +1,24 @@ package com.tencent.matrix.batterycanary.utils; +import android.Manifest; import android.app.usage.NetworkStats; import android.app.usage.NetworkStatsManager; import android.content.Context; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.Network; import android.net.NetworkCapabilities; - -import androidx.annotation.Nullable; -import androidx.annotation.RestrictTo; +import android.net.NetworkInfo; +import android.os.Build; import com.tencent.matrix.batterycanary.BuildConfig; import com.tencent.matrix.util.MatrixLog; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.annotation.RestrictTo; +import androidx.core.util.Pair; + /** * @author Kaede * @since 2020/12/8 @@ -37,9 +45,10 @@ public static RadioStat getCurrentStat(Context context) { if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) { return null; } - if (checkIfFrequently()) { - return sLastRef; - } + + // if (checkIfFrequently()) { + // return sLastRef; + // } try { NetworkStatsManager network = (NetworkStatsManager) context.getSystemService(Context.NETWORK_STATS_SERVICE); @@ -83,6 +92,46 @@ public static RadioStat getCurrentStat(Context context) { } } + @Nullable + public static RadioBps getCurrentBps(Context context) { + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + return null; + } + RadioBps stat = new RadioBps(); + Pair wifi = getCurrentBps(context, "WIFI"); + stat.wifiRxBps = wifi.first == null ? 0 : wifi.first; + stat.wifiTxBps = wifi.second == null ? 0 : wifi.second; + + Pair mobile = getCurrentBps(context, "MOBILE"); + stat.mobileRxBps = mobile.first == null ? 0 : mobile.first; + stat.mobileTxBps = mobile.second == null ? 0 : mobile.second; + return stat; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private static Pair getCurrentBps(Context context, String typeName) { + long rxBwBps = 0, txBwBps = 0; + if (context.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_GRANTED) { + ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + for (Network item : manager.getAllNetworks()) { + NetworkInfo networkInfo = manager.getNetworkInfo(item); + if (networkInfo != null + && (networkInfo.isConnected() || networkInfo.isConnectedOrConnecting()) + && networkInfo.getTypeName().equalsIgnoreCase(typeName)) { + NetworkCapabilities capabilities = manager.getNetworkCapabilities(item); + if (capabilities != null) { + rxBwBps = capabilities.getLinkDownstreamBandwidthKbps() * 1024L; + txBwBps = capabilities.getLinkUpstreamBandwidthKbps() * 1024L; + if (rxBwBps > 0 || txBwBps > 0) { + break; + } + } + } + } + } + return new Pair<>(rxBwBps, txBwBps); + } + public static final class RadioStat { public long wifiRxBytes; public long wifiTxBytes; @@ -94,4 +143,12 @@ public static final class RadioStat { public long mobileRxPackets; public long mobileTxPackets; } + + public static final class RadioBps { + public long wifiRxBps; + public long wifiTxBps; + + public long mobileRxBps; + public long mobileTxBps; + } } From 439dc6090d164865b6a9795a18b8134615c44a0b Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 23 Aug 2022 14:14:52 +0800 Subject: [PATCH 149/263] Update top indicator --- .../monitor/feature/CompositeMonitors.java | 2 + .../batterycanary/shell/TopThreadFeature.java | 61 +++++--- .../shell/ui/TopThreadIndicator.java | 143 +++++++++++++++++- .../res/layout/float_item_power_entry.xml | 47 ++++++ .../src/main/res/layout/float_top_thread.xml | 30 +++- .../battery/BatteryCanaryInitHelper.java | 2 + .../matrix/battery/TestBatteryActivity.java | 14 ++ 7 files changed, 270 insertions(+), 29 deletions(-) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 01deaf468..b2f08ddbd 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -47,6 +47,8 @@ public class CompositeMonitors { public static final String SCOPE_CANARY = "canary"; public static final String SCOPE_INTERNAL = "internal"; public static final String SCOPE_OVERHEAT = "overheat"; + public static final String SCOPE_TOP_SHELL = "topShell"; + public static final String SCOPE_TOP_INDICATOR = "topIndicator"; // Differing protected final List>> mMetrics = new ArrayList<>(); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/TopThreadFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/TopThreadFeature.java index 6466e8a74..840453574 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/TopThreadFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/TopThreadFeature.java @@ -9,15 +9,18 @@ import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCallback.BatteryPrinter.Printer; import com.tencent.matrix.batterycanary.monitor.feature.AbsMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.CompositeMonitors; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.JiffiesSnapshot; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import androidx.annotation.Nullable; import androidx.core.util.Pair; +import androidx.core.util.Supplier; /** * Something like 'adb shell top -Hb -u ' @@ -29,8 +32,8 @@ public class TopThreadFeature extends AbsMonitorFeature { private static final String TAG = "Matrix.battery.TopThread"; private boolean sStopShell; - public interface ContinuousCallback> { - boolean onGetDeltas(List> deltas, long windowMillis); + public interface ContinuousCallback { + boolean onGetDeltas(CompositeMonitors monitors, long windowMillis); } @Nullable private Runnable mTopTask; @@ -48,10 +51,18 @@ public int weight() { public void topShell(final int seconds) { sStopShell = false; - top(seconds, new ContinuousCallback() { + top(seconds, new Supplier() { @Override - public boolean onGetDeltas(List> deltaList, long windowMillis) { + public CompositeMonitors get() { + CompositeMonitors monitors = new CompositeMonitors(mCore, CompositeMonitors.SCOPE_TOP_SHELL); + monitors.metric(JiffiesMonitorFeature.UidJiffiesSnapshot.class); + return monitors; + } + }, new ContinuousCallback() { + @Override + public boolean onGetDeltas(CompositeMonitors monitors, long windowMillis) { // Proc Load + List> deltaList = monitors.getAllPidDeltaList(); long allProcJiffies = 0; for (Delta delta : deltaList) { allProcJiffies += delta.dlt.totalJiffies.get(); @@ -103,39 +114,43 @@ public void stopShell() { } - public void top(final int seconds, final ContinuousCallback callback) { + public void top(final int seconds, final Supplier supplier, final ContinuousCallback callback) { final JiffiesMonitorFeature jiffiesFeat = mCore.getMonitorFeature(JiffiesMonitorFeature.class); if (jiffiesFeat == null) { return; } final long windowMillis = seconds * 1000L; - final SparseArray lastHolder = new SparseArray<>(); + final AtomicReference lastMonitors = new AtomicReference<>(null); HandlerThread thread = new HandlerThread("matrix_top"); thread.start(); final Handler handler = new Handler(thread.getLooper()); final Runnable action = new Runnable() { @Override public void run() { - List> deltaList = new ArrayList<>(); - List pidList = getAllPidList(mCore.getContext()); - for (Integer pid : pidList) { - JiffiesSnapshot curr = jiffiesFeat.currentJiffiesSnapshot(pid); - JiffiesSnapshot last = lastHolder.get(pid); - if (last != null) { - Delta delta = curr.diff(last); - if (delta.isValid()) { - deltaList.add(delta); - } - } - lastHolder.put(pid, curr); - } - boolean stop = callback.onGetDeltas(deltaList, windowMillis); - if (stop) { - handler.getLooper().quit(); + CompositeMonitors monitors = lastMonitors.get(); + if (monitors == null) { + // Fist time + scheduleNext(); + } else { - handler.postDelayed(this, windowMillis); + lastMonitors.set(null); + monitors.finish(); + boolean stop = callback.onGetDeltas(monitors, windowMillis); + if (stop) { + handler.getLooper().quit(); + } else { + // Next + scheduleNext(); + } } } + + private void scheduleNext() { + CompositeMonitors monitors = supplier.get(); + monitors.start(); + lastMonitors.set(monitors); + handler.postDelayed(this, windowMillis); + } }; handler.postDelayed(action, windowMillis); } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java index f40cc682b..27d15b747 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java @@ -31,17 +31,27 @@ import com.tencent.matrix.batterycanary.BatteryCanary; import com.tencent.matrix.batterycanary.R; +import com.tencent.matrix.batterycanary.monitor.AppStats; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCallback; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; +import com.tencent.matrix.batterycanary.monitor.feature.CompositeMonitors; +import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature; +import com.tencent.matrix.batterycanary.monitor.feature.DeviceStatMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.JiffiesSnapshot; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Sampler.Result; import com.tencent.matrix.batterycanary.shell.TopThreadFeature; import com.tencent.matrix.batterycanary.shell.TopThreadFeature.ContinuousCallback; import com.tencent.matrix.batterycanary.stats.BatteryStatsFeature; +import com.tencent.matrix.batterycanary.stats.HealthStatsFeature; +import com.tencent.matrix.batterycanary.stats.HealthStatsHelper; import com.tencent.matrix.batterycanary.stats.ui.BatteryStatsActivity; import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.CallStackCollector; import com.tencent.matrix.batterycanary.utils.Consumer; +import com.tencent.matrix.batterycanary.utils.PowerProfile; import com.tencent.matrix.util.MatrixLog; import java.util.LinkedHashMap; @@ -53,6 +63,7 @@ import androidx.annotation.RestrictTo; import androidx.annotation.UiThread; import androidx.core.util.Pair; +import androidx.core.util.Supplier; import static com.tencent.matrix.batterycanary.shell.TopThreadFeature.figureCupLoad; import static com.tencent.matrix.batterycanary.shell.TopThreadFeature.fixedColumn; @@ -68,6 +79,7 @@ final public class TopThreadIndicator { private static final String TAG = "Matrix.TopThreadIndicator"; private static final int MAX_PROC_NUM = 10; private static final int MAX_THREAD_NUM = 10; + private static final int MAX_POWER_NUM = 30; @SuppressLint("StaticFieldLeak") private static final TopThreadIndicator sInstance = new TopThreadIndicator(); @@ -310,6 +322,15 @@ public boolean show(Context context) { entryItemView.setVisibility(View.GONE); threadEntryGroup.addView(entryItemView, layoutParams); } + // init power entryGroup + LinearLayout powerEntryGroup = mRootView.findViewById(R.id.layout_entry_power_group); + for (int i = 0; i < MAX_POWER_NUM - 1; i++) { + View entryItemView = LayoutInflater.from(powerEntryGroup.getContext()).inflate(R.layout.float_item_power_entry, powerEntryGroup, false); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, powerEntryGroup.getContext().getResources().getDisplayMetrics()); + entryItemView.setVisibility(View.GONE); + powerEntryGroup.addView(entryItemView, layoutParams); + } // 3. Drag View.OnTouchListener onTouchListener = new View.OnTouchListener() { @@ -483,10 +504,60 @@ public void start(final int seconds) { BatteryCanary.getMonitorFeature(TopThreadFeature.class, new Consumer() { @Override public void accept(TopThreadFeature topThreadFeat) { - topThreadFeat.top(seconds, new ContinuousCallback() { + topThreadFeat.top(seconds, new Supplier() { + @Override + public CompositeMonitors get() { + CompositeMonitors monitors = new CompositeMonitors(mCore, CompositeMonitors.SCOPE_TOP_INDICATOR); + monitors.metric(JiffiesMonitorFeature.UidJiffiesSnapshot.class); + monitors.metric(CpuStatFeature.CpuStateSnapshot.class); + monitors.metric(HealthStatsFeature.HealthStatsSnapshot.class); + monitors.sample(DeviceStatMonitorFeature.BatteryCurrentSnapshot.class, 500L); + return monitors; + } + }, new ContinuousCallback() { @Override - public boolean onGetDeltas(List> deltaList, long windowMillis) { - refresh(deltaList); + public boolean onGetDeltas(final CompositeMonitors monitors, long windowMillis) { + monitors.getDelta(HealthStatsFeature.HealthStatsSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta healthStatsDelta) { + monitors.getFeature(CpuStatFeature.class, new Consumer() { + @Override + public void accept(CpuStatFeature cpuStatFeat) { + if (cpuStatFeat.isSupported()) { + final PowerProfile powerProfile = cpuStatFeat.getPowerProfile(); + monitors.getDelta(JiffiesMonitorFeature.UidJiffiesSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta uidJiffiesDelta) { + monitors.getDelta(CpuStatFeature.CpuStateSnapshot.class, new Consumer>() { + @SuppressLint("VisibleForTests") + @Override + public void accept(Delta cpuStatDelta) { + CpuStatFeature.CpuStateSnapshot cpuStatsSnapshot = cpuStatDelta.dlt; + // CPU + long cpuTimeMs = uidJiffiesDelta.dlt.totalUidJiffies.get() * 10; + double cpuPower = HealthStatsHelper.estimateCpuActivePower(powerProfile, cpuTimeMs) + + HealthStatsHelper.estimateCpuClustersPower(powerProfile, cpuStatsSnapshot, cpuTimeMs, false) + + HealthStatsHelper.estimateCpuCoresPower(powerProfile, cpuStatsSnapshot, cpuTimeMs, false); + healthStatsDelta.dlt.cpuPower = MonitorFeature.Snapshot.Entry.DigitEntry.of(cpuPower); + // SysSrv + if (healthStatsDelta.dlt.jobsMs.get() >= 0 && healthStatsDelta.dlt.syncMs.get() >= 0) { + long sysSrvTimeMs = healthStatsDelta.dlt.jobsMs.get() + healthStatsDelta.dlt.syncMs.get(); + double systemServicePower = HealthStatsHelper.estimateCpuActivePower(powerProfile, sysSrvTimeMs) + + HealthStatsHelper.estimateCpuClustersPower(powerProfile, cpuStatsSnapshot, sysSrvTimeMs, false) + + HealthStatsHelper.estimateCpuCoresPower(powerProfile, cpuStatsSnapshot, sysSrvTimeMs, false); + healthStatsDelta.dlt.systemServicePower = MonitorFeature.Snapshot.Entry.DigitEntry.of(systemServicePower); + } + } + }); + } + }); + } + } + }); + } + }); + + refresh(monitors); if (mRootView == null || !mRunningRef.get(hashcode, false)) { return true; } @@ -524,14 +595,19 @@ private void setTextAlertColor(TextView tv, int level) { } @SuppressLint({"SetTextI18n", "RestrictedApi"}) - private void refresh(final List> deltaList) { + private void refresh(final CompositeMonitors monitors) { mUiHandler.post(new Runnable() { @Override public void run() { if (mRootView == null) { return; } + AppStats appStats = monitors.getAppStats(); + if (appStats == null) { + return; + } + List> deltaList = monitors.getAllPidDeltaList(); int battTemp = BatteryCanaryUtil.getBatteryTemperatureImmediately(mRootView.getContext()); TextView tvBattTemp = mRootView.findViewById(R.id.tv_header_left); tvBattTemp.setText((battTemp > 0 ? battTemp / 10f : "/") + "°C"); @@ -540,7 +616,7 @@ public void run() { tvBattTemp.setText((battTemp > 0 ? battTemp / 10f : "/") + "°C"); setTextAlertColor(tvBattTemp, battTemp >= 350 ? 2 : battTemp >= 300 ? 1 : 0); - // EntryList + // CpuLoad EntryList LinearLayout procEntryGroup = mRootView.findViewById(R.id.layout_entry_proc_group); for (int i = 0; i < procEntryGroup.getChildCount(); i++) { procEntryGroup.getChildAt(i).setVisibility(View.GONE); @@ -621,6 +697,63 @@ public void run() { tvLoad.setText(totalLoad); tvLoad = mRootView.findViewById(R.id.tv_load_minify); tvLoad.setText(totalLoad); + + // Power EntryList + LinearLayout powerEntryGroup = mRootView.findViewById(R.id.layout_entry_power_group); + for (int i = 0; i < powerEntryGroup.getChildCount(); i++) { + powerEntryGroup.getChildAt(i).setVisibility(View.GONE); + } + Map powerMap = new LinkedHashMap<>(); + Result result = monitors.getSamplingResult(DeviceStatMonitorFeature.BatteryCurrentSnapshot.class); + if (result != null) { + double power = (result.sampleAvg / -1000) * (appStats.duringMillis * 1f / BatteryCanaryUtil.ONE_HOR); + double deltaPh = (Double) power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; + powerMap.put("currency", deltaPh / 1000); + } + Delta healthStatsDelta = monitors.getDelta(HealthStatsFeature.HealthStatsSnapshot.class); + if (healthStatsDelta != null) { + powerMap.put("total", healthStatsDelta.dlt.getTotalPower()); + powerMap.put("cpu", healthStatsDelta.dlt.cpuPower.get()); + powerMap.put("----cpuUsrTimeMs", healthStatsDelta.dlt.cpuUsrTimeMs.get() + 0d); + powerMap.put("----cpuSysTimeMs", healthStatsDelta.dlt.cpuSysTimeMs.get() + 0d); + powerMap.put("wakelocks", healthStatsDelta.dlt.wakelocksPower.get()); + powerMap.put("mobile", healthStatsDelta.dlt.mobilePower.get()); + powerMap.put("wifi", healthStatsDelta.dlt.wifiPower.get()); + powerMap.put("blueTooth", healthStatsDelta.dlt.blueToothPower.get()); + powerMap.put("gps", healthStatsDelta.dlt.gpsPower.get()); + powerMap.put("sensors", healthStatsDelta.dlt.sensorsPower.get()); + powerMap.put("camera", healthStatsDelta.dlt.cameraPower.get()); + powerMap.put("flashLight", healthStatsDelta.dlt.flashLightPower.get()); + powerMap.put("audio", healthStatsDelta.dlt.audioPower.get()); + powerMap.put("video", healthStatsDelta.dlt.videoPower.get()); + powerMap.put("screen", healthStatsDelta.dlt.screenPower.get()); + powerMap.put("systemService", healthStatsDelta.dlt.systemServicePower.get()); + powerMap.put("idle", healthStatsDelta.dlt.idlePower.get()); + powerMap.put("----realTimeMs", healthStatsDelta.dlt.realTimeMs.get() + 0d); + powerMap.put("----upTimeMs", healthStatsDelta.dlt.upTimeMs.get() + 0d); + } + // for (Iterator> iterator = powerMap.entrySet().iterator(); iterator.hasNext(); ) { + // Map.Entry item = iterator.next(); + // if (item.getValue() == 0d) { + // iterator.remove(); + // } + // } + int idx = 0; + for (Map.Entry entry : powerMap.entrySet()) { + String module = entry.getKey(); + double power = entry.getValue(); + double powerPh = power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; + View threadItemView = powerEntryGroup.getChildAt(idx); + threadItemView.setVisibility(View.VISIBLE); + TextView tvName = threadItemView.findViewById(R.id.tv_name); + TextView tvPower = threadItemView.findViewById(R.id.tv_power); + tvName.setText(module); + tvPower.setText(String.valueOf(HealthStatsHelper.round(powerPh, 5))); + idx++; + if (idx >= MAX_POWER_NUM) { + break; + } + } } }); } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml new file mode 100644 index 000000000..fa7c88a76 --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_top_thread.xml b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_top_thread.xml index 7576bf7b2..7ec7df1f3 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_top_thread.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_top_thread.xml @@ -136,11 +136,39 @@ + + + + + + + + + + + + () { + // @Override + // public void accept(CpuStatFeature cpuStatFeature) { + // double averagePowerUni = cpuStatFeature.getPowerProfile().getAveragePowerUni(PowerProfile.POWER_CAMERA); + // if (averagePowerUni > 0) { + // + // } + // } + // }); + BatteryCanaryInitHelper.startBatteryMonitor(this); BatteryMonitorPlugin plugin = Matrix.with().getPluginByClass(BatteryMonitorPlugin.class); From 06b45cc654dbae15c5e92cd2362cdbe6a4396eb0 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 24 Aug 2022 21:03:59 +0800 Subject: [PATCH 150/263] Update top power --- .../shell/ui/TopThreadIndicator.java | 33 ++++++++++++++++--- .../battery/BatteryCanaryInitHelper.java | 1 + .../matrix/battery/TestBatteryActivity.java | 1 - 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java index 27d15b747..9790b2ec6 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java @@ -54,6 +54,7 @@ import com.tencent.matrix.batterycanary.utils.PowerProfile; import com.tencent.matrix.util.MatrixLog; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -510,7 +511,9 @@ public CompositeMonitors get() { CompositeMonitors monitors = new CompositeMonitors(mCore, CompositeMonitors.SCOPE_TOP_INDICATOR); monitors.metric(JiffiesMonitorFeature.UidJiffiesSnapshot.class); monitors.metric(CpuStatFeature.CpuStateSnapshot.class); + monitors.metric(CpuStatFeature.UidCpuStateSnapshot.class); monitors.metric(HealthStatsFeature.HealthStatsSnapshot.class); + monitors.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 500L); monitors.sample(DeviceStatMonitorFeature.BatteryCurrentSnapshot.class, 500L); return monitors; } @@ -714,8 +717,27 @@ public void run() { if (healthStatsDelta != null) { powerMap.put("total", healthStatsDelta.dlt.getTotalPower()); powerMap.put("cpu", healthStatsDelta.dlt.cpuPower.get()); - powerMap.put("----cpuUsrTimeMs", healthStatsDelta.dlt.cpuUsrTimeMs.get() + 0d); - powerMap.put("----cpuSysTimeMs", healthStatsDelta.dlt.cpuSysTimeMs.get() + 0d); + { + List modes = Arrays.asList("JiffyUid"); + for (String mode : modes) { + Object powers = healthStatsDelta.dlt.extras.get(mode); + if (powers != null) { + if (powers instanceof Map) { + // tuning cpu powers + for (Map.Entry entry : ((Map) powers).entrySet()) { + String key = String.valueOf(entry.getKey()); + Object val = entry.getValue(); + if (key.startsWith("power-cpu") && val instanceof Double) { + double cpuPower = (Double) val; + powerMap.put(key.replace("power-cpu", "cpu"), cpuPower); + } + } + } + } + } + } + // powerMap.put("----cpuUsrTimeMs", healthStatsDelta.dlt.cpuUsrTimeMs.get() + 0d); + // powerMap.put("----cpuSysTimeMs", healthStatsDelta.dlt.cpuSysTimeMs.get() + 0d); powerMap.put("wakelocks", healthStatsDelta.dlt.wakelocksPower.get()); powerMap.put("mobile", healthStatsDelta.dlt.mobilePower.get()); powerMap.put("wifi", healthStatsDelta.dlt.wifiPower.get()); @@ -727,10 +749,11 @@ public void run() { powerMap.put("audio", healthStatsDelta.dlt.audioPower.get()); powerMap.put("video", healthStatsDelta.dlt.videoPower.get()); powerMap.put("screen", healthStatsDelta.dlt.screenPower.get()); - powerMap.put("systemService", healthStatsDelta.dlt.systemServicePower.get()); + // powerMap.put("systemService", healthStatsDelta.dlt.systemServicePower.get()); powerMap.put("idle", healthStatsDelta.dlt.idlePower.get()); - powerMap.put("----realTimeMs", healthStatsDelta.dlt.realTimeMs.get() + 0d); - powerMap.put("----upTimeMs", healthStatsDelta.dlt.upTimeMs.get() + 0d); + + // powerMap.put("----realTimeMs", healthStatsDelta.dlt.realTimeMs.get() + 0d); + // powerMap.put("----upTimeMs", healthStatsDelta.dlt.upTimeMs.get() + 0d); } // for (Iterator> iterator = powerMap.entrySet().iterator(); iterator.hasNext(); ) { // Map.Entry item = iterator.next(); diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/BatteryCanaryInitHelper.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/BatteryCanaryInitHelper.java index 97ef68b1d..6d1a74316 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/BatteryCanaryInitHelper.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/BatteryCanaryInitHelper.java @@ -119,6 +119,7 @@ public String call() { .setRecorder(new BatteryRecorder.MMKVRecorder(mmkv)) .setStats(new BatteryStats.BatteryStatsImpl()) .enable(HealthStatsFeature.class) + .enable(HealthStatsFeature.class) // Lab Feature: // network monitor diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/TestBatteryActivity.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/TestBatteryActivity.java index e627e90a0..eadb3ad0b 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/TestBatteryActivity.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/TestBatteryActivity.java @@ -51,7 +51,6 @@ import com.tencent.matrix.batterycanary.stats.ui.BatteryStatsActivity; import com.tencent.matrix.batterycanary.utils.Consumer; import com.tencent.matrix.batterycanary.utils.PowerProfile; -import com.tencent.matrix.batterycanary.utils.TestPowerProfile; import com.tencent.matrix.util.MatrixLog; import androidx.annotation.NonNull; From 2fc70bd611de691fb95ca0a60a261a38c375d8ac Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 25 Aug 2022 21:02:16 +0800 Subject: [PATCH 151/263] Update top power --- .../shell/ui/TopThreadIndicator.java | 100 ++++++++++++++---- .../res/layout/float_item_power_entry.xml | 6 +- 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java index 9790b2ec6..072f586ce 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java @@ -42,6 +42,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Sampler.Result; +import com.tencent.matrix.batterycanary.monitor.feature.TrafficMonitorFeature; import com.tencent.matrix.batterycanary.shell.TopThreadFeature; import com.tencent.matrix.batterycanary.shell.TopThreadFeature.ContinuousCallback; import com.tencent.matrix.batterycanary.stats.BatteryStatsFeature; @@ -513,6 +514,7 @@ public CompositeMonitors get() { monitors.metric(CpuStatFeature.CpuStateSnapshot.class); monitors.metric(CpuStatFeature.UidCpuStateSnapshot.class); monitors.metric(HealthStatsFeature.HealthStatsSnapshot.class); + monitors.metric(TrafficMonitorFeature.RadioStatSnapshot.class); monitors.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 500L); monitors.sample(DeviceStatMonitorFeature.BatteryCurrentSnapshot.class, 500L); return monitors; @@ -658,7 +660,7 @@ public void run() { float threadLoad = figureCupLoad(entryJffies, delta.during / 10L); View threadItemView = threadEntryGroup.getChildAt(idx); - threadItemView.setVisibility(View.VISIBLE); + // threadItemView.setVisibility(View.VISIBLE); TextView tvName = threadItemView.findViewById(R.id.tv_name); TextView tvTid = threadItemView.findViewById(R.id.tv_tid); TextView tvStatus = threadItemView.findViewById(R.id.tv_status); @@ -706,17 +708,17 @@ public void run() { for (int i = 0; i < powerEntryGroup.getChildCount(); i++) { powerEntryGroup.getChildAt(i).setVisibility(View.GONE); } - Map powerMap = new LinkedHashMap<>(); + final Map> powerMap = new LinkedHashMap<>(); Result result = monitors.getSamplingResult(DeviceStatMonitorFeature.BatteryCurrentSnapshot.class); if (result != null) { double power = (result.sampleAvg / -1000) * (appStats.duringMillis * 1f / BatteryCanaryUtil.ONE_HOR); double deltaPh = (Double) power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; - powerMap.put("currency", deltaPh / 1000); + powerMap.put("currency", new Pair<>("mAh", deltaPh / 1000)); } - Delta healthStatsDelta = monitors.getDelta(HealthStatsFeature.HealthStatsSnapshot.class); + final Delta healthStatsDelta = monitors.getDelta(HealthStatsFeature.HealthStatsSnapshot.class); if (healthStatsDelta != null) { - powerMap.put("total", healthStatsDelta.dlt.getTotalPower()); - powerMap.put("cpu", healthStatsDelta.dlt.cpuPower.get()); + powerMap.put("total", new Pair<>("mAh", healthStatsDelta.dlt.getTotalPower())); + powerMap.put("cpu", new Pair<>("mAh", healthStatsDelta.dlt.cpuPower.get())); { List modes = Arrays.asList("JiffyUid"); for (String mode : modes) { @@ -729,7 +731,7 @@ public void run() { Object val = entry.getValue(); if (key.startsWith("power-cpu") && val instanceof Double) { double cpuPower = (Double) val; - powerMap.put(key.replace("power-cpu", "cpu"), cpuPower); + powerMap.put(key.replace("power-cpu", " - cpu"), new Pair<>("mAh", cpuPower)); } } } @@ -738,19 +740,58 @@ public void run() { } // powerMap.put("----cpuUsrTimeMs", healthStatsDelta.dlt.cpuUsrTimeMs.get() + 0d); // powerMap.put("----cpuSysTimeMs", healthStatsDelta.dlt.cpuSysTimeMs.get() + 0d); - powerMap.put("wakelocks", healthStatsDelta.dlt.wakelocksPower.get()); - powerMap.put("mobile", healthStatsDelta.dlt.mobilePower.get()); - powerMap.put("wifi", healthStatsDelta.dlt.wifiPower.get()); - powerMap.put("blueTooth", healthStatsDelta.dlt.blueToothPower.get()); - powerMap.put("gps", healthStatsDelta.dlt.gpsPower.get()); - powerMap.put("sensors", healthStatsDelta.dlt.sensorsPower.get()); - powerMap.put("camera", healthStatsDelta.dlt.cameraPower.get()); - powerMap.put("flashLight", healthStatsDelta.dlt.flashLightPower.get()); - powerMap.put("audio", healthStatsDelta.dlt.audioPower.get()); - powerMap.put("video", healthStatsDelta.dlt.videoPower.get()); - powerMap.put("screen", healthStatsDelta.dlt.screenPower.get()); + powerMap.put("wakelocks", new Pair<>("mAh", healthStatsDelta.dlt.wakelocksPower.get())); + powerMap.put("mobile", new Pair<>("mAh", healthStatsDelta.dlt.mobilePower.get())); + powerMap.put("wifi", new Pair<>("mAh", healthStatsDelta.dlt.wifiPower.get())); + { + monitors.getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta delta) { + monitors.getFeature(CpuStatFeature.class, new Consumer() { + @SuppressLint("VisibleForTests") + @Override + public void accept(CpuStatFeature feat) { + if (feat.isSupported()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && mCore != null) { + { + double power = HealthStatsHelper.calcWifiPowerByNetworkStatBytes(mCore.getContext(), feat.getPowerProfile(), delta.dlt); + if (power > 0) { + powerMap.put(" - wifi-PowerBytes", new Pair<>("mAh", power)); + powerMap.put(" - wifi-TxBytes", new Pair<>("byte", (double) delta.dlt.wifiTxBytes.get())); + powerMap.put(" - wifi-RxBytes", new Pair<>("byte", (double) delta.dlt.wifiRxBytes.get())); + } + } + { + double power = HealthStatsHelper.calcWifiPowerByNetworkStatPackets(feat.getPowerProfile(), delta.dlt); + if (power > 0) { + powerMap.put(" - wifi-PowerPackets", new Pair<>("mAh", power)); + powerMap.put(" - wifi-RxPackets", new Pair<>("packet", (double) delta.dlt.wifiRxPackets.get())); + powerMap.put(" - wifi-TxPackets", new Pair<>("packet", (double) delta.dlt.wifiTxPackets.get())); + } + } + } + } + } + }); + // powerMap.put("mobile-TxBytes", new Pair<>(false, (double) delta.dlt.mobileTxBytes.get())); + // powerMap.put("mobile-RxBytes", new Pair<>(false, (double) delta.dlt.mobileRxBytes.get())); + // powerMap.put("mobile-RxPackets", new Pair<>(false, (double) delta.dlt.mobileRxPackets.get())); + // powerMap.put("wifi-TxBytes", new Pair<>(false, (double) delta.dlt.wifiTxBytes.get())); + // powerMap.put("wifi-RxBytes", new Pair<>(false, (double) delta.dlt.wifiRxBytes.get())); + // powerMap.put("wifi-RxPackets", new Pair<>(false, (double) delta.dlt.wifiRxPackets.get())); + } + }); + } + powerMap.put("blueTooth", new Pair<>("mAh", healthStatsDelta.dlt.blueToothPower.get())); + powerMap.put("gps", new Pair<>("mAh", healthStatsDelta.dlt.gpsPower.get())); + powerMap.put("sensors", new Pair<>("mAh", healthStatsDelta.dlt.sensorsPower.get())); + powerMap.put("camera", new Pair<>("mAh", healthStatsDelta.dlt.cameraPower.get())); + powerMap.put("flashLight", new Pair<>("mAh", healthStatsDelta.dlt.flashLightPower.get())); + powerMap.put("audio", new Pair<>("mAh", healthStatsDelta.dlt.audioPower.get())); + powerMap.put("video", new Pair<>("mAh", healthStatsDelta.dlt.videoPower.get())); + powerMap.put("screen", new Pair<>("mAh", healthStatsDelta.dlt.screenPower.get())); // powerMap.put("systemService", healthStatsDelta.dlt.systemServicePower.get()); - powerMap.put("idle", healthStatsDelta.dlt.idlePower.get()); + powerMap.put("idle", new Pair<>("mAh", healthStatsDelta.dlt.idlePower.get())); // powerMap.put("----realTimeMs", healthStatsDelta.dlt.realTimeMs.get() + 0d); // powerMap.put("----upTimeMs", healthStatsDelta.dlt.upTimeMs.get() + 0d); @@ -762,16 +803,29 @@ public void run() { // } // } int idx = 0; - for (Map.Entry entry : powerMap.entrySet()) { + for (Map.Entry> entry : powerMap.entrySet()) { String module = entry.getKey(); - double power = entry.getValue(); - double powerPh = power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; + String unit = ""; + double value = 0d; + Pair pair = entry.getValue(); + if (pair.first != null && pair.second != null) { + if (pair.first.equals("mAh")) { + unit = "mAph"; + double power = (double) pair.second; + value = power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; + } else { + unit = pair.first; + value = pair.second; + } + } View threadItemView = powerEntryGroup.getChildAt(idx); threadItemView.setVisibility(View.VISIBLE); TextView tvName = threadItemView.findViewById(R.id.tv_name); + TextView tvUnit = threadItemView.findViewById(R.id.tv_unit); TextView tvPower = threadItemView.findViewById(R.id.tv_power); tvName.setText(module); - tvPower.setText(String.valueOf(HealthStatsHelper.round(powerPh, 5))); + tvUnit.setText(unit); + tvPower.setText(String.valueOf(HealthStatsHelper.round(value, 5))); idx++; if (idx >= MAX_POWER_NUM) { break; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml index fa7c88a76..255357216 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml @@ -22,9 +22,9 @@ android:layout_height="wrap_content"> Date: Fri, 26 Aug 2022 16:55:32 +0800 Subject: [PATCH 152/263] Update top power indicator --- .../shell/ui/TopThreadIndicator.java | 137 +++++++----------- .../res/layout/float_item_power_entry.xml | 4 +- 2 files changed, 54 insertions(+), 87 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java index 072f586ce..5a7412eef 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java @@ -39,7 +39,6 @@ import com.tencent.matrix.batterycanary.monitor.feature.DeviceStatMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.JiffiesSnapshot; -import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Sampler.Result; import com.tencent.matrix.batterycanary.monitor.feature.TrafficMonitorFeature; @@ -52,7 +51,6 @@ import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.CallStackCollector; import com.tencent.matrix.batterycanary.utils.Consumer; -import com.tencent.matrix.batterycanary.utils.PowerProfile; import com.tencent.matrix.util.MatrixLog; import java.util.Arrays; @@ -522,46 +520,6 @@ public CompositeMonitors get() { }, new ContinuousCallback() { @Override public boolean onGetDeltas(final CompositeMonitors monitors, long windowMillis) { - monitors.getDelta(HealthStatsFeature.HealthStatsSnapshot.class, new Consumer>() { - @Override - public void accept(final Delta healthStatsDelta) { - monitors.getFeature(CpuStatFeature.class, new Consumer() { - @Override - public void accept(CpuStatFeature cpuStatFeat) { - if (cpuStatFeat.isSupported()) { - final PowerProfile powerProfile = cpuStatFeat.getPowerProfile(); - monitors.getDelta(JiffiesMonitorFeature.UidJiffiesSnapshot.class, new Consumer>() { - @Override - public void accept(final Delta uidJiffiesDelta) { - monitors.getDelta(CpuStatFeature.CpuStateSnapshot.class, new Consumer>() { - @SuppressLint("VisibleForTests") - @Override - public void accept(Delta cpuStatDelta) { - CpuStatFeature.CpuStateSnapshot cpuStatsSnapshot = cpuStatDelta.dlt; - // CPU - long cpuTimeMs = uidJiffiesDelta.dlt.totalUidJiffies.get() * 10; - double cpuPower = HealthStatsHelper.estimateCpuActivePower(powerProfile, cpuTimeMs) - + HealthStatsHelper.estimateCpuClustersPower(powerProfile, cpuStatsSnapshot, cpuTimeMs, false) - + HealthStatsHelper.estimateCpuCoresPower(powerProfile, cpuStatsSnapshot, cpuTimeMs, false); - healthStatsDelta.dlt.cpuPower = MonitorFeature.Snapshot.Entry.DigitEntry.of(cpuPower); - // SysSrv - if (healthStatsDelta.dlt.jobsMs.get() >= 0 && healthStatsDelta.dlt.syncMs.get() >= 0) { - long sysSrvTimeMs = healthStatsDelta.dlt.jobsMs.get() + healthStatsDelta.dlt.syncMs.get(); - double systemServicePower = HealthStatsHelper.estimateCpuActivePower(powerProfile, sysSrvTimeMs) - + HealthStatsHelper.estimateCpuClustersPower(powerProfile, cpuStatsSnapshot, sysSrvTimeMs, false) - + HealthStatsHelper.estimateCpuCoresPower(powerProfile, cpuStatsSnapshot, sysSrvTimeMs, false); - healthStatsDelta.dlt.systemServicePower = MonitorFeature.Snapshot.Entry.DigitEntry.of(systemServicePower); - } - } - }); - } - }); - } - } - }); - } - }); - refresh(monitors); if (mRootView == null || !mRunningRef.get(hashcode, false)) { return true; @@ -714,6 +672,8 @@ public void run() { double power = (result.sampleAvg / -1000) * (appStats.duringMillis * 1f / BatteryCanaryUtil.ONE_HOR); double deltaPh = (Double) power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; powerMap.put("currency", new Pair<>("mAh", deltaPh / 1000)); + } else { + powerMap.put("currency", new Pair("mAh", null)); } final Delta healthStatsDelta = monitors.getDelta(HealthStatsFeature.HealthStatsSnapshot.class); if (healthStatsDelta != null) { @@ -738,47 +698,49 @@ public void run() { } } } - // powerMap.put("----cpuUsrTimeMs", healthStatsDelta.dlt.cpuUsrTimeMs.get() + 0d); - // powerMap.put("----cpuSysTimeMs", healthStatsDelta.dlt.cpuSysTimeMs.get() + 0d); powerMap.put("wakelocks", new Pair<>("mAh", healthStatsDelta.dlt.wakelocksPower.get())); powerMap.put("mobile", new Pair<>("mAh", healthStatsDelta.dlt.mobilePower.get())); + { + + monitors.getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta delta) { + if (healthStatsDelta.dlt.extras.containsKey("power-mobile-statByte")) { + Object val = healthStatsDelta.dlt.extras.get("power-mobile-statByte"); + if (val instanceof Double) { + double power = (double) val; + powerMap.put(" - mobile-PowerBytes", new Pair<>("mAh", power)); + powerMap.put(" - mobile-TxBytes", new Pair<>("byte", (double) delta.dlt.mobileTxBytes.get())); + powerMap.put(" - mobile-RxBytes", new Pair<>("byte", (double) delta.dlt.mobileRxBytes.get())); + } + } + } + }); + } powerMap.put("wifi", new Pair<>("mAh", healthStatsDelta.dlt.wifiPower.get())); { + monitors.getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { @Override public void accept(final Delta delta) { - monitors.getFeature(CpuStatFeature.class, new Consumer() { - @SuppressLint("VisibleForTests") - @Override - public void accept(CpuStatFeature feat) { - if (feat.isSupported()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && mCore != null) { - { - double power = HealthStatsHelper.calcWifiPowerByNetworkStatBytes(mCore.getContext(), feat.getPowerProfile(), delta.dlt); - if (power > 0) { - powerMap.put(" - wifi-PowerBytes", new Pair<>("mAh", power)); - powerMap.put(" - wifi-TxBytes", new Pair<>("byte", (double) delta.dlt.wifiTxBytes.get())); - powerMap.put(" - wifi-RxBytes", new Pair<>("byte", (double) delta.dlt.wifiRxBytes.get())); - } - } - { - double power = HealthStatsHelper.calcWifiPowerByNetworkStatPackets(feat.getPowerProfile(), delta.dlt); - if (power > 0) { - powerMap.put(" - wifi-PowerPackets", new Pair<>("mAh", power)); - powerMap.put(" - wifi-RxPackets", new Pair<>("packet", (double) delta.dlt.wifiRxPackets.get())); - powerMap.put(" - wifi-TxPackets", new Pair<>("packet", (double) delta.dlt.wifiTxPackets.get())); - } - } - } - } + if (healthStatsDelta.dlt.extras.containsKey("power-wifi-statByte")) { + Object val = healthStatsDelta.dlt.extras.get("power-wifi-statByte"); + if (val instanceof Double) { + double power = (double) val; + powerMap.put(" - wifi-PowerBytes", new Pair<>("mAh", power)); + powerMap.put(" - wifi-TxBytes", new Pair<>("byte", (double) delta.dlt.wifiTxBytes.get())); + powerMap.put(" - wifi-RxBytes", new Pair<>("byte", (double) delta.dlt.wifiRxBytes.get())); + } + } + if (healthStatsDelta.dlt.extras.containsKey("power-wifi-statPacket")) { + Object val = healthStatsDelta.dlt.extras.get("power-wifi-statPacket"); + if (val instanceof Double) { + double power = (double) val; + powerMap.put(" - wifi-PowerPackets", new Pair<>("mAh", power)); + powerMap.put(" - wifi-RxPackets", new Pair<>("packet", (double) delta.dlt.wifiRxPackets.get())); + powerMap.put(" - wifi-TxPackets", new Pair<>("packet", (double) delta.dlt.wifiTxPackets.get())); } - }); - // powerMap.put("mobile-TxBytes", new Pair<>(false, (double) delta.dlt.mobileTxBytes.get())); - // powerMap.put("mobile-RxBytes", new Pair<>(false, (double) delta.dlt.mobileRxBytes.get())); - // powerMap.put("mobile-RxPackets", new Pair<>(false, (double) delta.dlt.mobileRxPackets.get())); - // powerMap.put("wifi-TxBytes", new Pair<>(false, (double) delta.dlt.wifiTxBytes.get())); - // powerMap.put("wifi-RxBytes", new Pair<>(false, (double) delta.dlt.wifiRxBytes.get())); - // powerMap.put("wifi-RxPackets", new Pair<>(false, (double) delta.dlt.wifiRxPackets.get())); + } } }); } @@ -792,9 +754,6 @@ public void accept(CpuStatFeature feat) { powerMap.put("screen", new Pair<>("mAh", healthStatsDelta.dlt.screenPower.get())); // powerMap.put("systemService", healthStatsDelta.dlt.systemServicePower.get()); powerMap.put("idle", new Pair<>("mAh", healthStatsDelta.dlt.idlePower.get())); - - // powerMap.put("----realTimeMs", healthStatsDelta.dlt.realTimeMs.get() + 0d); - // powerMap.put("----upTimeMs", healthStatsDelta.dlt.upTimeMs.get() + 0d); } // for (Iterator> iterator = powerMap.entrySet().iterator(); iterator.hasNext(); ) { // Map.Entry item = iterator.next(); @@ -806,16 +765,20 @@ public void accept(CpuStatFeature feat) { for (Map.Entry> entry : powerMap.entrySet()) { String module = entry.getKey(); String unit = ""; - double value = 0d; + Double value = null; Pair pair = entry.getValue(); - if (pair.first != null && pair.second != null) { + if (pair.first != null) { if (pair.first.equals("mAh")) { - unit = "mAph"; - double power = (double) pair.second; - value = power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; + unit = ""; + if (pair.second != null) { + double power = (double) pair.second; + value = power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; + } } else { unit = pair.first; - value = pair.second; + if (pair.second != null) { + value = pair.second; + } } } View threadItemView = powerEntryGroup.getChildAt(idx); @@ -825,7 +788,11 @@ public void accept(CpuStatFeature feat) { TextView tvPower = threadItemView.findViewById(R.id.tv_power); tvName.setText(module); tvUnit.setText(unit); - tvPower.setText(String.valueOf(HealthStatsHelper.round(value, 5))); + if (value == null) { + tvPower.setText("NULL"); + } else { + tvPower.setText(String.valueOf(HealthStatsHelper.round(value, 5))); + } idx++; if (idx >= MAX_POWER_NUM) { break; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml index 255357216..c04f18b50 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_item_power_entry.xml @@ -11,7 +11,7 @@ android:ellipsize="end" android:maxLines="1" - android:text="ThreadName" + android:text="ModuleName" android:textColor="@color/FG_2" android:textSize="10sp" /> @@ -22,7 +22,7 @@ android:layout_height="wrap_content"> Date: Fri, 26 Aug 2022 20:21:44 +0800 Subject: [PATCH 153/263] Update top power indicator --- .../matrix/batterycanary/shell/ui/TopThreadIndicator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java index 5a7412eef..15010ea84 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java @@ -515,6 +515,7 @@ public CompositeMonitors get() { monitors.metric(TrafficMonitorFeature.RadioStatSnapshot.class); monitors.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 500L); monitors.sample(DeviceStatMonitorFeature.BatteryCurrentSnapshot.class, 500L); + monitors.sample(TrafficMonitorFeature.RadioBpsSnapshot.class, 500L); return monitors; } }, new ContinuousCallback() { @@ -710,8 +711,8 @@ public void accept(final Delta delta) { if (val instanceof Double) { double power = (double) val; powerMap.put(" - mobile-PowerBytes", new Pair<>("mAh", power)); - powerMap.put(" - mobile-TxBytes", new Pair<>("byte", (double) delta.dlt.mobileTxBytes.get())); powerMap.put(" - mobile-RxBytes", new Pair<>("byte", (double) delta.dlt.mobileRxBytes.get())); + powerMap.put(" - mobile-TxBytes", new Pair<>("byte", (double) delta.dlt.mobileTxBytes.get())); } } } @@ -728,8 +729,8 @@ public void accept(final Delta delta) { if (val instanceof Double) { double power = (double) val; powerMap.put(" - wifi-PowerBytes", new Pair<>("mAh", power)); - powerMap.put(" - wifi-TxBytes", new Pair<>("byte", (double) delta.dlt.wifiTxBytes.get())); powerMap.put(" - wifi-RxBytes", new Pair<>("byte", (double) delta.dlt.wifiRxBytes.get())); + powerMap.put(" - wifi-TxBytes", new Pair<>("byte", (double) delta.dlt.wifiTxBytes.get())); } } if (healthStatsDelta.dlt.extras.containsKey("power-wifi-statPacket")) { From 037b464d901fd1a5c305ea11c191d6b66da238cc Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 26 Aug 2022 21:11:13 +0800 Subject: [PATCH 154/263] Update mobile power cfg --- .../monitor/feature/CompositeMonitors.java | 42 +++++++++++-------- .../stats/HealthStatsHelper.java | 34 ++++++++++++--- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index b2f08ddbd..bbd93d244 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -1039,24 +1039,24 @@ public void accept(Delta healthStatsDelta) { } healthStatsDelta.dlt.cpuPower = DigitEntry.of(power); } - { - // Reset mobilePower if exists - double power = 0; - Object val = healthStatsDelta.dlt.extras.get("power-mobile-statByte"); - if (val instanceof Double) { - power = (double) val; - } - healthStatsDelta.dlt.mobilePower = DigitEntry.of(power); - } - { - // Reset wifiPower if exists - double power = 0; - Object val = healthStatsDelta.dlt.extras.get("power-wifi-statByte"); - if (val instanceof Double) { - power = (double) val; - } - healthStatsDelta.dlt.wifiPower = DigitEntry.of(power); - } + // { + // // Reset mobilePower if exists + // double power = 0; + // Object val = healthStatsDelta.dlt.extras.get("power-mobile-statByte"); + // if (val instanceof Double) { + // power = (double) val; + // } + // healthStatsDelta.dlt.mobilePower = DigitEntry.of(power); + // } + // { + // // Reset wifiPower if exists + // double power = 0; + // Object val = healthStatsDelta.dlt.extras.get("power-wifi-statByte"); + // if (val instanceof Double) { + // power = (double) val; + // } + // healthStatsDelta.dlt.wifiPower = DigitEntry.of(power); + // } } }); } @@ -1184,6 +1184,12 @@ public void accept(Delta delta) { bpsSampler.getAverage(bpsSampler.mobileRxBps), bpsSampler.getAverage(bpsSampler.mobileTxBps)); snapshot.extras.put("power-mobile-statByte", power); + power = HealthStatsHelper.calcMobilePowerByNetworkStatPackets( + powerProfile, + delta.dlt, + bpsSampler.getAverage(bpsSampler.mobileRxBps), + bpsSampler.getAverage(bpsSampler.mobileTxBps)); + snapshot.extras.put("power-mobile-statPacket", power); // wifi power = HealthStatsHelper.calcWifiPowerByNetworkStatBytes( diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 115257640..2837248eb 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -15,7 +15,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature.CpuStateSnapshot; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.DigitEntry; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.ListEntry; -import com.tencent.matrix.batterycanary.monitor.feature.TrafficMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.TrafficMonitorFeature.RadioStatSnapshot; import com.tencent.matrix.batterycanary.utils.PowerProfile; import com.tencent.matrix.util.MatrixLog; @@ -446,7 +446,7 @@ public static double calcMobilePowerByController(PowerProfile powerProfile, Heal } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public static double calcMobilePowerByNetworkStatBytes(PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot, double rxBps, double txBps) { + public static double calcMobilePowerByNetworkStatBytes(PowerProfile powerProfile, RadioStatSnapshot snapshot, double rxBps, double txBps) { long rxMs = (long) ((snapshot.mobileRxBytes.get() / (rxBps / 8)) * 1000); long txMs = (long) ((snapshot.mobileTxBytes.get() / (txBps / 8)) * 1000); double power = 0; @@ -468,6 +468,30 @@ public static double calcMobilePowerByNetworkStatBytes(PowerProfile powerProfile return power; } + public static double calcMobilePowerByNetworkStatPackets(PowerProfile powerProfile, RadioStatSnapshot snapshot, double rxBps, double txBps) { + double power = 0; + { + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_RADIO_ACTIVE); + if (powerMa <= 0) { + double sum = 0; + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); + int num = powerProfile.getNumElements(PowerProfile.POWER_MODEM_CONTROLLER_TX); + for (int i = 0; i < num; i++) { + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i); + } + powerMa = sum / (num + 1); + } + double mobileBps = rxBps + txBps; + double powerPs = powerMa / 3600; + double mobilePps = ((double) mobileBps) / 8 / 2048; + double powerMaPerPacket = (powerPs / mobilePps) / (60 * 60); + long packets = snapshot.mobileRxPackets.get() + snapshot.mobileTxPackets.get(); + power += powerMaPerPacket * packets; + } + return power; + } + + /** * @see com.android.internal.os.WifiPowerCalculator */ @@ -544,7 +568,7 @@ public static double calcWifiPowerByPackets(PowerProfile powerProfile, HealthSta } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public static double calcWifiPowerByNetworkStatBytes(PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot, double rxBps, double txBps) { + public static double calcWifiPowerByNetworkStatBytes(PowerProfile powerProfile, RadioStatSnapshot snapshot, double rxBps, double txBps) { long rxMs = (long) ((snapshot.wifiRxBytes.get() / (rxBps / 8)) * 1000); long txMs = (long) ((snapshot.wifiTxBytes.get() / (txBps / 8)) * 1000); double power = 0; @@ -566,11 +590,11 @@ public static double calcWifiPowerByNetworkStatBytes(PowerProfile powerProfile, return power; } - public static double calcWifiPowerByNetworkStatPackets(PowerProfile powerProfile, TrafficMonitorFeature.RadioStatSnapshot snapshot, double rxBps, double txBps) { + public static double calcWifiPowerByNetworkStatPackets(PowerProfile powerProfile, RadioStatSnapshot snapshot, double rxBps, double txBps) { double power = 0; { final double wifiBps = rxBps + txBps; - final double averageWifiActivePower = powerProfile.getAveragePowerOrDefault(PowerProfile.POWER_WIFI_ACTIVE, 120) / 3600; + final double averageWifiActivePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ACTIVE) / 3600; double powerMaPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); long packets = snapshot.wifiRxPackets.get() + snapshot.wifiTxPackets.get(); power += powerMaPerPacket * packets; From f70d380b8e55262a67609e20872a8ae493b4590f Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 29 Aug 2022 14:53:08 +0800 Subject: [PATCH 155/263] Update battery mobile/wifi power cfg --- .../monitor/feature/CompositeMonitors.java | 126 ++++++++++++------ .../stats/HealthStatsFeature.java | 29 +--- .../stats/HealthStatsHelper.java | 77 +++++++---- 3 files changed, 148 insertions(+), 84 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index bbd93d244..6f4ea8c7b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -21,6 +21,7 @@ import com.tencent.matrix.batterycanary.utils.Consumer; import com.tencent.matrix.batterycanary.utils.Function; import com.tencent.matrix.batterycanary.utils.PowerProfile; +import com.tencent.matrix.batterycanary.utils.RadioStatUtil; import com.tencent.matrix.util.MatrixLog; import java.util.ArrayList; @@ -28,6 +29,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -1072,11 +1074,11 @@ public void accept(CpuStatFeature feat) { if (feat.isSupported()) { final PowerProfile powerProfile = feat.getPowerProfile(); - // Tune CPU + // 1. Tune CPU getDelta(CpuStatFeature.CpuStateSnapshot.class, new Consumer>() { @Override public void accept(final Delta cpuStatDelta) { - // CpuTimeMs + // 1.1 CpuTimeMs getDelta(HealthStatsFeature.HealthStatsSnapshot.class, new Consumer>() { @Override public void accept(final Delta healthStats) { @@ -1117,7 +1119,7 @@ private long getCpuTimeMs(String procSuffix, HealthStatsFeature.HealthStatsSnaps } }); - // CpuTimeJiffies + // 1.2 CpuTimeJiffies getDelta(JiffiesMonitorFeature.UidJiffiesSnapshot.class, new Consumer>() { @Override public void accept(final Delta delta) { @@ -1170,44 +1172,92 @@ public long getDltMs(String procSuffix) { } }); - // Tune Network - getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { - @Override - public void accept(Delta delta) { - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP && mMonitor != null) { - BpsSampler bpsSampler = getBpsSampler(); - if (bpsSampler != null) { - // mobile - double power = HealthStatsHelper.calcMobilePowerByNetworkStatBytes( - powerProfile, - delta.dlt, - bpsSampler.getAverage(bpsSampler.mobileRxBps), - bpsSampler.getAverage(bpsSampler.mobileTxBps)); - snapshot.extras.put("power-mobile-statByte", power); - power = HealthStatsHelper.calcMobilePowerByNetworkStatPackets( - powerProfile, - delta.dlt, - bpsSampler.getAverage(bpsSampler.mobileRxBps), - bpsSampler.getAverage(bpsSampler.mobileTxBps)); - snapshot.extras.put("power-mobile-statPacket", power); + // 2. Tune Network + { + double mobileRxBps = 0, mobileTxBps = 0; + double wifiRxBps = 0, wifiTxBps = 0; + BpsSampler bpsSampler = getBpsSampler(); + if (bpsSampler != null) { + mobileRxBps = bpsSampler.getAverage(bpsSampler.mobileRxBps); + mobileTxBps = bpsSampler.getAverage(bpsSampler.mobileTxBps); + wifiRxBps = bpsSampler.getAverage(bpsSampler.wifiRxBps); + wifiTxBps = bpsSampler.getAverage(bpsSampler.wifiTxBps); + } else { + if (mMonitor != null) { + RadioStatUtil.RadioBps bpsStat = RadioStatUtil.getCurrentBps(mMonitor.getContext()); + if (bpsStat != null) { + mobileRxBps = bpsStat.mobileRxBps; + mobileTxBps = bpsStat.mobileTxBps; + wifiRxBps = bpsStat.wifiRxBps; + wifiTxBps = bpsStat.wifiTxBps; + } + } + } + final double finalMobileRxBps = mobileRxBps; + final double finalMobileTxBps = mobileTxBps; + final double finalWifiRxBps = wifiRxBps; + final double finalWifiTxBps = wifiTxBps; + + // 2.1 HealthStats + getDelta(HealthStatsSnapshot.class, new Consumer>() { + @SuppressLint("VisibleForTests") + @Override + public void accept(Delta delta) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + // mobile + { + double powerBgn = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, delta.bgn.healthStats); + double powerEnd = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, delta.end.healthStats); + snapshot.extras.put("power-mobile-radio", powerEnd - powerBgn); + } + { + double powerBgn = HealthStatsHelper.calcMobilePowerByController(powerProfile, delta.bgn.healthStats); + double powerEnd = HealthStatsHelper.calcMobilePowerByController(powerProfile, delta.end.healthStats); + snapshot.extras.put("power-mobile-controller", powerEnd - powerBgn); + } + { + double powerBgn = HealthStatsHelper.calcMobilePowerByPackets(powerProfile, delta.bgn.healthStats, finalMobileRxBps, finalMobileTxBps); + double powerEnd = HealthStatsHelper.calcMobilePowerByPackets(powerProfile, delta.end.healthStats, finalMobileRxBps, finalMobileTxBps); + snapshot.extras.put("power-mobile-packet", powerEnd - powerBgn); + } // wifi - power = HealthStatsHelper.calcWifiPowerByNetworkStatBytes( - powerProfile, - delta.dlt, - bpsSampler.getAverage(bpsSampler.wifiRxBps), - bpsSampler.getAverage(bpsSampler.wifiTxBps)); - snapshot.extras.put("power-wifi-statByte", power); - power = HealthStatsHelper.calcWifiPowerByNetworkStatPackets( - powerProfile, - delta.dlt, - bpsSampler.getAverage(bpsSampler.wifiRxBps), - bpsSampler.getAverage(bpsSampler.wifiTxBps)); - snapshot.extras.put("power-wifi-statPacket", power); + { + double powerBgn = HealthStatsHelper.calcWifiPowerByController(powerProfile, delta.bgn.healthStats); + double powerEnd = HealthStatsHelper.calcWifiPowerByController(powerProfile, delta.end.healthStats); + snapshot.extras.put("power-wifi-controller", powerEnd - powerBgn); + } + { + double powerBgn = HealthStatsHelper.calcWifiPowerByPackets(powerProfile, delta.bgn.healthStats, finalWifiRxBps, finalWifiTxBps); + double powerEnd = HealthStatsHelper.calcWifiPowerByPackets(powerProfile, delta.end.healthStats, finalWifiRxBps, finalWifiTxBps); + snapshot.extras.put("power-wifi-packet", powerEnd - powerBgn); + } } } - } - }); + }); + + // 2.2 RadioStat + getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mMonitor != null) { + BpsSampler bpsSampler = getBpsSampler(); + if (bpsSampler != null) { + // mobile + double power = HealthStatsHelper.calcMobilePowerByNetworkStatBytes(powerProfile, delta.dlt, finalMobileRxBps, finalMobileTxBps); + snapshot.extras.put("power-mobile-statByte", power); + power = HealthStatsHelper.calcMobilePowerByNetworkStatPackets(powerProfile, delta.dlt, finalMobileRxBps, finalMobileTxBps); + snapshot.extras.put("power-mobile-statPacket", power); + // wifi + power = HealthStatsHelper.calcWifiPowerByNetworkStatBytes(powerProfile, delta.dlt, finalWifiRxBps, finalWifiTxBps); + snapshot.extras.put("power-wifi-statByte", power); + power = HealthStatsHelper.calcWifiPowerByNetworkStatPackets(powerProfile, delta.dlt, finalWifiRxBps, finalWifiTxBps); + snapshot.extras.put("power-wifi-statPacket", power); + } + } + } + }); + } } } }); @@ -1223,7 +1273,7 @@ interface CpuTime { } public Map tuningCpuPowers(final PowerProfile powerProfile, final CompositeMonitors monitors, final CpuTime cpuTime) { - final Map dict = new HashMap<>(); + final Map dict = new LinkedHashMap<>(); monitors.getDelta(CpuStatFeature.UidCpuStateSnapshot.class, new Consumer>() { @SuppressLint("VisibleForTests") @Override diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index d0fb9c736..519c3f613 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -63,11 +64,6 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { if (cpuStatFeat != null) { PowerProfile powerProfile = cpuStatFeat.getPowerProfile(); if (powerProfile != null && powerProfile.isSupported()) { - snapshot.mobilePowerByRadioActive = DigitEntry.of(HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, healthStats)); - snapshot.mobilePowerByController = DigitEntry.of(HealthStatsHelper.calcMobilePowerByController(powerProfile, healthStats)); - snapshot.wifiPowerByController = DigitEntry.of(HealthStatsHelper.calcWifiPowerByController(powerProfile, healthStats)); - snapshot.wifiPowerByPackets = DigitEntry.of(HealthStatsHelper.calcWifiPowerByPackets(powerProfile, healthStats)); - snapshot.cpuPower = DigitEntry.of(HealthStatsHelper.calcCpuPower(powerProfile, healthStats)); snapshot.wakelocksPower = DigitEntry.of(HealthStatsHelper.calcWakelocksPower(powerProfile, healthStats)); snapshot.mobilePower = DigitEntry.of(HealthStatsHelper.calcMobilePower(powerProfile, healthStats)); @@ -248,12 +244,8 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { } public static class HealthStatsSnapshot extends Snapshot { - @VisibleForTesting public HealthStats healthStats; - @VisibleForTesting public DigitEntry mobilePowerByRadioActive = DigitEntry.of(0D); - @VisibleForTesting public DigitEntry mobilePowerByController = DigitEntry.of(0D); - @VisibleForTesting public DigitEntry wifiPowerByController = DigitEntry.of(0D); - @VisibleForTesting public DigitEntry wifiPowerByPackets = DigitEntry.of(0D); - + @VisibleForTesting + public HealthStats healthStats; public Map extras = Collections.emptyMap(); // Estimated Powers @@ -343,7 +335,7 @@ public double getTotalPower() { + audioPower.get() + videoPower.get() + screenPower.get() - // + systemServicePower.get() + // + systemServicePower.get() // WIP + idlePower.get(); } @@ -353,17 +345,8 @@ public Delta diff(HealthStatsSnapshot bgn) { @Override protected HealthStatsSnapshot computeDelta() { HealthStatsSnapshot delta = new HealthStatsSnapshot(); - - // For test - delta.mobilePowerByRadioActive = Differ.DigitDiffer.globalDiff(bgn.mobilePowerByRadioActive, end.mobilePowerByRadioActive); - delta.mobilePowerByController = Differ.DigitDiffer.globalDiff(bgn.mobilePowerByController, end.mobilePowerByController); - delta.wifiPowerByController = Differ.DigitDiffer.globalDiff(bgn.wifiPowerByController, end.wifiPowerByController); - delta.wifiPowerByPackets = Differ.DigitDiffer.globalDiff(bgn.wifiPowerByPackets, end.wifiPowerByPackets); - delta.extras = new HashMap<>(); - delta.extras.put("power-mobile-radio", mobilePowerByRadioActive.get()); - delta.extras.put("power-mobile-controller", mobilePowerByController.get()); - delta.extras.put("power-wifi-controller", wifiPowerByController.get()); - delta.extras.put("power-wifi-packets", wifiPowerByPackets.get()); + // For test & tunings + delta.extras = new LinkedHashMap<>(); // UID delta.cpuPower = Differ.DigitDiffer.globalDiff(bgn.cpuPower, end.cpuPower); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 2837248eb..31b1e29b3 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -394,11 +394,11 @@ public static double calcMobilePower(PowerProfile powerProfile, HealthStats heal MatrixLog.i(TAG, "estimate Mobile by radioActive"); return power; } - power = calcMobilePowerByController(powerProfile, healthStats); - if (power > 0) { - MatrixLog.i(TAG, "estimate Mobile by controller"); - return power; - } + // power = calcMobilePowerByController(powerProfile, healthStats); + // if (power > 0) { + // MatrixLog.i(TAG, "estimate Mobile by controller"); + // return power; + // } return 0; } @@ -445,6 +445,32 @@ public static double calcMobilePowerByController(PowerProfile powerProfile, Heal return power; } + @RequiresApi(api = Build.VERSION_CODES.N) + @VisibleForTesting + public static double calcMobilePowerByPackets(PowerProfile powerProfile, HealthStats healthStats, double rxBps, double txBps) { + double power = 0; + { + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_RADIO_ACTIVE); + if (powerMa <= 0) { + double sum = 0; + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); + int num = powerProfile.getNumElements(PowerProfile.POWER_MODEM_CONTROLLER_TX); + for (int i = 0; i < num; i++) { + sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i); + } + powerMa = sum / (num + 1); + } + double mobileBps = rxBps + txBps; + double powerPs = powerMa / 3600; + double mobilePps = ((double) mobileBps) / 8 / 2048; + double powerMaPerPacket = (powerPs / mobilePps) / (60 * 60); + long packets = getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_PACKETS); + power += powerMaPerPacket * packets; + } + return power; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public static double calcMobilePowerByNetworkStatBytes(PowerProfile powerProfile, RadioStatSnapshot snapshot, double rxBps, double txBps) { long rxMs = (long) ((snapshot.mobileRxBytes.get() / (rxBps / 8)) * 1000); @@ -507,7 +533,7 @@ public static double calcWifiPower(PowerProfile powerProfile, HealthStats health MatrixLog.i(TAG, "estimate WIFI by controller"); return power; } - power = calcWifiPowerByPackets(powerProfile, healthStats); + power = calcWifiPowerByPackets(powerProfile, healthStats, 500000, 500000); if (power > 0) { MatrixLog.i(TAG, "estimate WIFI by packets"); return power; @@ -543,26 +569,31 @@ public static double calcWifiPowerByController(PowerProfile powerProfile, Health @RequiresApi(api = Build.VERSION_CODES.N) @VisibleForTesting - public static double calcWifiPowerByPackets(PowerProfile powerProfile, HealthStats healthStats) { + public static double calcWifiPowerByPackets(PowerProfile powerProfile, HealthStats healthStats, double rxBps, double txBps) { // calc from packets double power = 0; MatrixLog.i(TAG, "estimate WIFI by packets"); - { - final long wifiBps = 1000000; - final double averageWifiActivePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ACTIVE) / 3600; - double powerMaPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); - long packets = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS); - power += powerMaPerPacket * packets; - } - { - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ON); - long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); - } - { - double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_SCAN); - long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_WIFI_SCAN); - power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + if (rxBps >= 0 && txBps >= 0) { + if (rxBps == 0 && txBps == 0) { + return power; + } + { + final double wifiBps = rxBps + txBps; + final double averageWifiActivePower = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ACTIVE) / 3600; + double powerMaPerPacket = averageWifiActivePower / (((double) wifiBps) / 8 / 2048); + long packets = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS) + getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS); + power += powerMaPerPacket * packets; + } + { + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_ON); + long timeMs = getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } + { + double powerMa = powerProfile.getAveragePowerUni(PowerProfile.POWER_WIFI_SCAN); + long timeMs = getTimerTime(healthStats, UidHealthStats.TIMER_WIFI_SCAN); + power += new UsageBasedPowerEstimator(powerMa).calculatePower(timeMs); + } } return power; } From dc90a84e2b718ca8d4b5eeee341dab1e2d1d79c1 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 30 Aug 2022 10:23:46 +0800 Subject: [PATCH 156/263] sample: fix dependency --- samples/sample-android/app/dependencies-aar.gradle | 2 +- samples/sample-android/app/dependencies-src.gradle | 2 +- .../java/sample/tencent/matrix/hooks/TestHooksActivity.java | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/sample-android/app/dependencies-aar.gradle b/samples/sample-android/app/dependencies-aar.gradle index f4a266028..108c4e3d0 100644 --- a/samples/sample-android/app/dependencies-aar.gradle +++ b/samples/sample-android/app/dependencies-aar.gradle @@ -13,7 +13,7 @@ dependencies { "matrix-sqlite-lint-android-sdk", "matrix-hooks", "matrix-fd", - "matrix-jectl", + "matrix-mallctl", "matrix-backtrace", "matrix-traffic", "matrix-memory-canary", diff --git a/samples/sample-android/app/dependencies-src.gradle b/samples/sample-android/app/dependencies-src.gradle index aff5557ac..7338d57eb 100644 --- a/samples/sample-android/app/dependencies-src.gradle +++ b/samples/sample-android/app/dependencies-src.gradle @@ -13,7 +13,7 @@ dependencies { "matrix-sqlite-lint-android-sdk", "matrix-hooks", "matrix-fd", - "matrix-jectl", + "matrix-mallctl", "matrix-backtrace", "matrix-traffic", "matrix-memory-canary", diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java index 1838530b4..8ebfe5c45 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java @@ -24,7 +24,7 @@ import com.tencent.matrix.hook.HookManager; import com.tencent.matrix.hook.memory.MemoryHook; import com.tencent.matrix.hook.pthread.PthreadHook; -import com.tencent.matrix.jectl.JeCtl; +import com.tencent.matrix.mallctl.MallCtl; import java.io.File; @@ -231,8 +231,8 @@ public void threadTest(View view) { } public void jectlTest(View view) { - Log.d(TAG, "jemalloc version = " + JeCtl.version()); - Log.d(TAG, "set retain, old value = " + JeCtl.setRetain(true)); + Log.d(TAG, "jemalloc version = " + MallCtl.jeVersion()); + Log.d(TAG, "set retain, old value = " + MallCtl.jeSetRetain(true)); } public void killSelf(View view) { From 3c0232f259dee5d734be557694e5aa8143cf6cae Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 30 Aug 2022 17:39:23 +0800 Subject: [PATCH 157/263] Update battery power top indicator --- .../shell/ui/TopThreadIndicator.java | 246 ++++++++++-------- .../src/main/res/layout/float_top_thread.xml | 35 +++ 2 files changed, 166 insertions(+), 115 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java index 15010ea84..3c7efe83c 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/shell/ui/TopThreadIndicator.java @@ -24,6 +24,7 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.animation.AccelerateInterpolator; +import android.widget.CheckBox; import android.widget.LinearLayout; import android.widget.PopupMenu; import android.widget.TextView; @@ -95,6 +96,7 @@ final public class TopThreadIndicator { private BatteryMonitorCore mCore; @Nullable private Delta mCurrDelta; + private boolean mShowPower = false; @NonNull private CallStackCollector mCollector = new CallStackCollector(); @NonNull @@ -304,6 +306,9 @@ public boolean show(Context context) { final TextView tvProc = mRootView.findViewById(R.id.tv_proc); tvProc.setText(mCurrProc.second); + final CheckBox checkPower = mRootView.findViewById(R.id.check_power); + mShowPower = checkPower.isChecked(); + // init thread entryGroup LinearLayout procEntryGroup = mRootView.findViewById(R.id.layout_entry_proc_group); for (int i = 0; i < MAX_PROC_NUM - 1; i++) { @@ -442,6 +447,12 @@ public boolean onMenuItemClick(MenuItem item) { mRootView.findViewById(R.id.iv_logo_minify).setVisibility(View.VISIBLE); return; } + if (v.getId() == R.id.layout_check_power) { + CheckBox view = v.findViewById(R.id.check_power); + view.setChecked(!view.isChecked()); + mShowPower = view.isChecked(); + return; + } if (v == mRootView && mRootView.findViewById(R.id.layout_top).getVisibility() == View.GONE) { // Minify LOGO View anchorView = mRootView.findViewById(R.id.iv_logo_minify); @@ -481,6 +492,7 @@ public void run() { mRootView.findViewById(R.id.layout_dump).setOnClickListener(listener); mRootView.findViewById(R.id.iv_logo).setOnClickListener(listener); mRootView.findViewById(R.id.tv_minify).setOnClickListener(listener); + mRootView.findViewById(R.id.layout_check_power).setOnClickListener(listener); mRootView.setOnClickListener(listener); return true; } catch (Exception e) { @@ -619,7 +631,9 @@ public void run() { float threadLoad = figureCupLoad(entryJffies, delta.during / 10L); View threadItemView = threadEntryGroup.getChildAt(idx); - // threadItemView.setVisibility(View.VISIBLE); + if (!mShowPower) { + threadItemView.setVisibility(View.VISIBLE); + } TextView tvName = threadItemView.findViewById(R.id.tv_name); TextView tvTid = threadItemView.findViewById(R.id.tv_tid); TextView tvStatus = threadItemView.findViewById(R.id.tv_status); @@ -667,136 +681,138 @@ public void run() { for (int i = 0; i < powerEntryGroup.getChildCount(); i++) { powerEntryGroup.getChildAt(i).setVisibility(View.GONE); } - final Map> powerMap = new LinkedHashMap<>(); - Result result = monitors.getSamplingResult(DeviceStatMonitorFeature.BatteryCurrentSnapshot.class); - if (result != null) { - double power = (result.sampleAvg / -1000) * (appStats.duringMillis * 1f / BatteryCanaryUtil.ONE_HOR); - double deltaPh = (Double) power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; - powerMap.put("currency", new Pair<>("mAh", deltaPh / 1000)); - } else { - powerMap.put("currency", new Pair("mAh", null)); - } - final Delta healthStatsDelta = monitors.getDelta(HealthStatsFeature.HealthStatsSnapshot.class); - if (healthStatsDelta != null) { - powerMap.put("total", new Pair<>("mAh", healthStatsDelta.dlt.getTotalPower())); - powerMap.put("cpu", new Pair<>("mAh", healthStatsDelta.dlt.cpuPower.get())); - { - List modes = Arrays.asList("JiffyUid"); - for (String mode : modes) { - Object powers = healthStatsDelta.dlt.extras.get(mode); - if (powers != null) { - if (powers instanceof Map) { - // tuning cpu powers - for (Map.Entry entry : ((Map) powers).entrySet()) { - String key = String.valueOf(entry.getKey()); - Object val = entry.getValue(); - if (key.startsWith("power-cpu") && val instanceof Double) { - double cpuPower = (Double) val; - powerMap.put(key.replace("power-cpu", " - cpu"), new Pair<>("mAh", cpuPower)); + if (mShowPower) { + final Map> powerMap = new LinkedHashMap<>(); + Result result = monitors.getSamplingResult(DeviceStatMonitorFeature.BatteryCurrentSnapshot.class); + if (result != null) { + double power = (result.sampleAvg / -1000) * (appStats.duringMillis * 1f / BatteryCanaryUtil.ONE_HOR); + double deltaPh = (Double) power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; + powerMap.put("currency", new Pair<>("mAh", deltaPh / 1000)); + } else { + powerMap.put("currency", new Pair("mAh", null)); + } + final Delta healthStatsDelta = monitors.getDelta(HealthStatsFeature.HealthStatsSnapshot.class); + if (healthStatsDelta != null) { + powerMap.put("total", new Pair<>("mAh", healthStatsDelta.dlt.getTotalPower())); + powerMap.put("cpu", new Pair<>("mAh", healthStatsDelta.dlt.cpuPower.get())); + { + List modes = Arrays.asList("JiffyUid"); + for (String mode : modes) { + Object powers = healthStatsDelta.dlt.extras.get(mode); + if (powers != null) { + if (powers instanceof Map) { + // tuning cpu powers + for (Map.Entry entry : ((Map) powers).entrySet()) { + String key = String.valueOf(entry.getKey()); + Object val = entry.getValue(); + if (key.startsWith("power-cpu") && val instanceof Double) { + double cpuPower = (Double) val; + powerMap.put(key.replace("power-cpu", " - cpu"), new Pair<>("mAh", cpuPower)); + } } } } } } - } - powerMap.put("wakelocks", new Pair<>("mAh", healthStatsDelta.dlt.wakelocksPower.get())); - powerMap.put("mobile", new Pair<>("mAh", healthStatsDelta.dlt.mobilePower.get())); - { + powerMap.put("wakelocks", new Pair<>("mAh", healthStatsDelta.dlt.wakelocksPower.get())); + powerMap.put("mobile", new Pair<>("mAh", healthStatsDelta.dlt.mobilePower.get())); + { - monitors.getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { - @Override - public void accept(final Delta delta) { - if (healthStatsDelta.dlt.extras.containsKey("power-mobile-statByte")) { - Object val = healthStatsDelta.dlt.extras.get("power-mobile-statByte"); - if (val instanceof Double) { - double power = (double) val; - powerMap.put(" - mobile-PowerBytes", new Pair<>("mAh", power)); - powerMap.put(" - mobile-RxBytes", new Pair<>("byte", (double) delta.dlt.mobileRxBytes.get())); - powerMap.put(" - mobile-TxBytes", new Pair<>("byte", (double) delta.dlt.mobileTxBytes.get())); + monitors.getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta delta) { + if (healthStatsDelta.dlt.extras.containsKey("power-mobile-statByte")) { + Object val = healthStatsDelta.dlt.extras.get("power-mobile-statByte"); + if (val instanceof Double) { + double power = (double) val; + powerMap.put(" - mobile-PowerBytes", new Pair<>("mAh", power)); + powerMap.put(" - mobile-RxBytes", new Pair<>("byte", (double) delta.dlt.mobileRxBytes.get())); + powerMap.put(" - mobile-TxBytes", new Pair<>("byte", (double) delta.dlt.mobileTxBytes.get())); + } } } - } - }); - } - powerMap.put("wifi", new Pair<>("mAh", healthStatsDelta.dlt.wifiPower.get())); - { + }); + } + powerMap.put("wifi", new Pair<>("mAh", healthStatsDelta.dlt.wifiPower.get())); + { - monitors.getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { - @Override - public void accept(final Delta delta) { - if (healthStatsDelta.dlt.extras.containsKey("power-wifi-statByte")) { - Object val = healthStatsDelta.dlt.extras.get("power-wifi-statByte"); - if (val instanceof Double) { - double power = (double) val; - powerMap.put(" - wifi-PowerBytes", new Pair<>("mAh", power)); - powerMap.put(" - wifi-RxBytes", new Pair<>("byte", (double) delta.dlt.wifiRxBytes.get())); - powerMap.put(" - wifi-TxBytes", new Pair<>("byte", (double) delta.dlt.wifiTxBytes.get())); + monitors.getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta delta) { + if (healthStatsDelta.dlt.extras.containsKey("power-wifi-statByte")) { + Object val = healthStatsDelta.dlt.extras.get("power-wifi-statByte"); + if (val instanceof Double) { + double power = (double) val; + powerMap.put(" - wifi-PowerBytes", new Pair<>("mAh", power)); + powerMap.put(" - wifi-RxBytes", new Pair<>("byte", (double) delta.dlt.wifiRxBytes.get())); + powerMap.put(" - wifi-TxBytes", new Pair<>("byte", (double) delta.dlt.wifiTxBytes.get())); + } } - } - if (healthStatsDelta.dlt.extras.containsKey("power-wifi-statPacket")) { - Object val = healthStatsDelta.dlt.extras.get("power-wifi-statPacket"); - if (val instanceof Double) { - double power = (double) val; - powerMap.put(" - wifi-PowerPackets", new Pair<>("mAh", power)); - powerMap.put(" - wifi-RxPackets", new Pair<>("packet", (double) delta.dlt.wifiRxPackets.get())); - powerMap.put(" - wifi-TxPackets", new Pair<>("packet", (double) delta.dlt.wifiTxPackets.get())); + if (healthStatsDelta.dlt.extras.containsKey("power-wifi-statPacket")) { + Object val = healthStatsDelta.dlt.extras.get("power-wifi-statPacket"); + if (val instanceof Double) { + double power = (double) val; + powerMap.put(" - wifi-PowerPackets", new Pair<>("mAh", power)); + powerMap.put(" - wifi-RxPackets", new Pair<>("packet", (double) delta.dlt.wifiRxPackets.get())); + powerMap.put(" - wifi-TxPackets", new Pair<>("packet", (double) delta.dlt.wifiTxPackets.get())); + } } } - } - }); + }); + } + powerMap.put("blueTooth", new Pair<>("mAh", healthStatsDelta.dlt.blueToothPower.get())); + powerMap.put("gps", new Pair<>("mAh", healthStatsDelta.dlt.gpsPower.get())); + powerMap.put("sensors", new Pair<>("mAh", healthStatsDelta.dlt.sensorsPower.get())); + powerMap.put("camera", new Pair<>("mAh", healthStatsDelta.dlt.cameraPower.get())); + powerMap.put("flashLight", new Pair<>("mAh", healthStatsDelta.dlt.flashLightPower.get())); + powerMap.put("audio", new Pair<>("mAh", healthStatsDelta.dlt.audioPower.get())); + powerMap.put("video", new Pair<>("mAh", healthStatsDelta.dlt.videoPower.get())); + powerMap.put("screen", new Pair<>("mAh", healthStatsDelta.dlt.screenPower.get())); + // powerMap.put("systemService", healthStatsDelta.dlt.systemServicePower.get()); + powerMap.put("idle", new Pair<>("mAh", healthStatsDelta.dlt.idlePower.get())); } - powerMap.put("blueTooth", new Pair<>("mAh", healthStatsDelta.dlt.blueToothPower.get())); - powerMap.put("gps", new Pair<>("mAh", healthStatsDelta.dlt.gpsPower.get())); - powerMap.put("sensors", new Pair<>("mAh", healthStatsDelta.dlt.sensorsPower.get())); - powerMap.put("camera", new Pair<>("mAh", healthStatsDelta.dlt.cameraPower.get())); - powerMap.put("flashLight", new Pair<>("mAh", healthStatsDelta.dlt.flashLightPower.get())); - powerMap.put("audio", new Pair<>("mAh", healthStatsDelta.dlt.audioPower.get())); - powerMap.put("video", new Pair<>("mAh", healthStatsDelta.dlt.videoPower.get())); - powerMap.put("screen", new Pair<>("mAh", healthStatsDelta.dlt.screenPower.get())); - // powerMap.put("systemService", healthStatsDelta.dlt.systemServicePower.get()); - powerMap.put("idle", new Pair<>("mAh", healthStatsDelta.dlt.idlePower.get())); - } - // for (Iterator> iterator = powerMap.entrySet().iterator(); iterator.hasNext(); ) { - // Map.Entry item = iterator.next(); - // if (item.getValue() == 0d) { - // iterator.remove(); - // } - // } - int idx = 0; - for (Map.Entry> entry : powerMap.entrySet()) { - String module = entry.getKey(); - String unit = ""; - Double value = null; - Pair pair = entry.getValue(); - if (pair.first != null) { - if (pair.first.equals("mAh")) { - unit = ""; - if (pair.second != null) { - double power = (double) pair.second; - value = power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; + // for (Iterator> iterator = powerMap.entrySet().iterator(); iterator.hasNext(); ) { + // Map.Entry item = iterator.next(); + // if (item.getValue() == 0d) { + // iterator.remove(); + // } + // } + int idx = 0; + for (Map.Entry> entry : powerMap.entrySet()) { + String module = entry.getKey(); + String unit = ""; + Double value = null; + Pair pair = entry.getValue(); + if (pair.first != null) { + if (pair.first.equals("mAh")) { + unit = ""; + if (pair.second != null) { + double power = (double) pair.second; + value = power * BatteryCanaryUtil.ONE_HOR / appStats.duringMillis; + } + } else { + unit = pair.first; + if (pair.second != null) { + value = pair.second; + } } + } + View threadItemView = powerEntryGroup.getChildAt(idx); + threadItemView.setVisibility(View.VISIBLE); + TextView tvName = threadItemView.findViewById(R.id.tv_name); + TextView tvUnit = threadItemView.findViewById(R.id.tv_unit); + TextView tvPower = threadItemView.findViewById(R.id.tv_power); + tvName.setText(module); + tvUnit.setText(unit); + if (value == null) { + tvPower.setText("NULL"); } else { - unit = pair.first; - if (pair.second != null) { - value = pair.second; - } + tvPower.setText(String.valueOf(HealthStatsHelper.round(value, 5))); + } + idx++; + if (idx >= MAX_POWER_NUM) { + break; } - } - View threadItemView = powerEntryGroup.getChildAt(idx); - threadItemView.setVisibility(View.VISIBLE); - TextView tvName = threadItemView.findViewById(R.id.tv_name); - TextView tvUnit = threadItemView.findViewById(R.id.tv_unit); - TextView tvPower = threadItemView.findViewById(R.id.tv_power); - tvName.setText(module); - tvUnit.setText(unit); - if (value == null) { - tvPower.setText("NULL"); - } else { - tvPower.setText(String.valueOf(HealthStatsHelper.round(value, 5))); - } - idx++; - if (idx >= MAX_POWER_NUM) { - break; } } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_top_thread.xml b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_top_thread.xml index 7ec7df1f3..de6771a4d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_top_thread.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/main/res/layout/float_top_thread.xml @@ -28,6 +28,41 @@ android:text="Matrix TOP" android:textSize="12sp" /> + + + + + + + Date: Tue, 30 Aug 2022 17:39:47 +0800 Subject: [PATCH 158/263] Update battery healthstats cfg --- .../stats/HealthStatsFeature.java | 43 ++++++++++++++++++- .../stats/HealthStatsHelper.java | 25 ++++++++--- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 519c3f613..190ade61d 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; /** @@ -96,10 +97,21 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { snapshot.mobileRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_MS)); snapshot.mobileTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_MS)); + snapshot.mobileRxBytes = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_BYTES)); + snapshot.mobileTxBytes = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_BYTES)); + snapshot.mobileRxPackets = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS)); + snapshot.mobileTxPackets = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_MOBILE_TX_PACKETS)); + snapshot.wifiPowerMams = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS)); snapshot.wifiIdleMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_IDLE_MS)); snapshot.wifiRxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_MS)); snapshot.wifiTxMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_MS)); + snapshot.wifiRunningMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS)); + snapshot.wifiLockMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_FULL_LOCK_MS)); + snapshot.wifiScanMs = DigitEntry.of(HealthStatsHelper.getTimerTime(healthStats, UidHealthStats.TIMER_WIFI_SCAN)); + snapshot.wifiMulticastMs = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_MULTICAST_MS)); + snapshot.wifiRxBytes = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_BYTES)); + snapshot.wifiTxBytes = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_BYTES)); snapshot.wifiRxPackets = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS)); snapshot.wifiTxPackets = DigitEntry.of(HealthStatsHelper.getMeasure(healthStats, UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS)); @@ -280,11 +292,21 @@ public static class HealthStatsSnapshot extends Snapshot { public DigitEntry mobileIdleMs = DigitEntry.of(0L); public DigitEntry mobileRxMs = DigitEntry.of(0L); public DigitEntry mobileTxMs = DigitEntry.of(0L); + public DigitEntry mobileRxBytes = DigitEntry.of(0L); + public DigitEntry mobileTxBytes = DigitEntry.of(0L); + public DigitEntry mobileRxPackets = DigitEntry.of(0L); + public DigitEntry mobileTxPackets = DigitEntry.of(0L); public DigitEntry wifiPowerMams = DigitEntry.of(0L); public DigitEntry wifiIdleMs = DigitEntry.of(0L); public DigitEntry wifiRxMs = DigitEntry.of(0L); public DigitEntry wifiTxMs = DigitEntry.of(0L); + public DigitEntry wifiRunningMs = DigitEntry.of(0L); + public DigitEntry wifiLockMs = DigitEntry.of(0L); + public DigitEntry wifiScanMs = DigitEntry.of(0L); + public DigitEntry wifiMulticastMs = DigitEntry.of(0L); + public DigitEntry wifiRxBytes = DigitEntry.of(0L); + public DigitEntry wifiTxBytes = DigitEntry.of(0L); public DigitEntry wifiRxPackets = DigitEntry.of(0L); public DigitEntry wifiTxPackets = DigitEntry.of(0L); @@ -330,11 +352,11 @@ public double getTotalPower() { + blueToothPower.get() + gpsPower.get() + sensorsPower.get() - + cameraPower.get() + flashLightPower.get() + audioPower.get() + videoPower.get() + screenPower.get() + // + cameraPower.get() // WIP // + systemServicePower.get() // WIP + idlePower.get(); } @@ -375,11 +397,22 @@ protected HealthStatsSnapshot computeDelta() { delta.mobileIdleMs = Differ.DigitDiffer.globalDiff(bgn.mobileIdleMs, end.mobileIdleMs); delta.mobileRxMs = Differ.DigitDiffer.globalDiff(bgn.mobileRxMs, end.mobileRxMs); delta.mobileTxMs = Differ.DigitDiffer.globalDiff(bgn.mobileTxMs, end.mobileTxMs); + delta.mobileRxBytes = Differ.DigitDiffer.globalDiff(bgn.mobileRxBytes, end.mobileRxBytes); + delta.mobileTxBytes = Differ.DigitDiffer.globalDiff(bgn.mobileTxBytes, end.mobileTxBytes); + delta.mobileRxPackets = Differ.DigitDiffer.globalDiff(bgn.mobileRxPackets, end.mobileRxPackets); + delta.mobileTxPackets = Differ.DigitDiffer.globalDiff(bgn.mobileTxPackets, end.mobileTxPackets); + delta.wifiPowerMams = Differ.DigitDiffer.globalDiff(bgn.wifiPowerMams, end.wifiPowerMams); delta.wifiIdleMs = Differ.DigitDiffer.globalDiff(bgn.wifiIdleMs, end.wifiIdleMs); delta.wifiRxMs = Differ.DigitDiffer.globalDiff(bgn.wifiRxMs, end.wifiRxMs); delta.wifiTxMs = Differ.DigitDiffer.globalDiff(bgn.wifiTxMs, end.wifiTxMs); + delta.wifiRunningMs = Differ.DigitDiffer.globalDiff(bgn.wifiRunningMs, end.wifiRunningMs); + delta.wifiLockMs = Differ.DigitDiffer.globalDiff(bgn.wifiLockMs, end.wifiLockMs); + delta.wifiScanMs = Differ.DigitDiffer.globalDiff(bgn.wifiScanMs, end.wifiScanMs); + delta.wifiMulticastMs = Differ.DigitDiffer.globalDiff(bgn.wifiMulticastMs, end.wifiMulticastMs); + delta.wifiRxBytes = Differ.DigitDiffer.globalDiff(bgn.wifiRxBytes, end.wifiRxBytes); + delta.wifiTxBytes = Differ.DigitDiffer.globalDiff(bgn.wifiTxBytes, end.wifiTxBytes); delta.wifiRxPackets = Differ.DigitDiffer.globalDiff(bgn.wifiRxPackets, end.wifiRxPackets); delta.wifiTxPackets = Differ.DigitDiffer.globalDiff(bgn.wifiTxPackets, end.wifiTxPackets); @@ -470,5 +503,13 @@ public int compare(Map.Entry> o1, Map.Entry extra, String key) { + Object val = extra.get(key); + if (val instanceof Double) { + return (double) val; + } + return 0; + } } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java index 31b1e29b3..b4fb3b139 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsHelper.java @@ -348,6 +348,7 @@ public static double estimateCpuCoresPowerByDevStats(PowerProfile powerProfile, /** * WIP + * Memory TimeStats support needed, see "com.android.internal.os.KernelMemoryBandwidthStats" * * @see com.android.internal.os.MemoryPowerCalculator */ @@ -355,7 +356,7 @@ public static double calcMemoryPower(PowerProfile powerProfile) { double power = 0; int numBuckets = powerProfile.getNumElements(PowerProfile.POWER_MEMORY); for (int i = 0; i < numBuckets; i++) { - long timeMs = 0; // TODO: Memory TimeStats supported, see "com.android.internal.os.KernelMemoryBandwidthStats" + long timeMs = 0; power += new UsageBasedPowerEstimator(powerProfile.getAveragePower(PowerProfile.POWER_MEMORY, i)).calculatePower(timeMs); } return power; @@ -472,6 +473,7 @@ public static double calcMobilePowerByPackets(PowerProfile powerProfile, HealthS @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @VisibleForTesting public static double calcMobilePowerByNetworkStatBytes(PowerProfile powerProfile, RadioStatSnapshot snapshot, double rxBps, double txBps) { long rxMs = (long) ((snapshot.mobileRxBytes.get() / (rxBps / 8)) * 1000); long txMs = (long) ((snapshot.mobileTxBytes.get() / (txBps / 8)) * 1000); @@ -494,6 +496,7 @@ public static double calcMobilePowerByNetworkStatBytes(PowerProfile powerProfile return power; } + @VisibleForTesting public static double calcMobilePowerByNetworkStatPackets(PowerProfile powerProfile, RadioStatSnapshot snapshot, double rxBps, double txBps) { double power = 0; { @@ -533,11 +536,11 @@ public static double calcWifiPower(PowerProfile powerProfile, HealthStats health MatrixLog.i(TAG, "estimate WIFI by controller"); return power; } - power = calcWifiPowerByPackets(powerProfile, healthStats, 500000, 500000); - if (power > 0) { - MatrixLog.i(TAG, "estimate WIFI by packets"); - return power; - } + // power = calcWifiPowerByPackets(powerProfile, healthStats, 500000, 500000); + // if (power > 0) { + // MatrixLog.i(TAG, "estimate WIFI by packets"); + // return power; + // } return 0; } @@ -572,7 +575,6 @@ public static double calcWifiPowerByController(PowerProfile powerProfile, Health public static double calcWifiPowerByPackets(PowerProfile powerProfile, HealthStats healthStats, double rxBps, double txBps) { // calc from packets double power = 0; - MatrixLog.i(TAG, "estimate WIFI by packets"); if (rxBps >= 0 && txBps >= 0) { if (rxBps == 0 && txBps == 0) { return power; @@ -599,6 +601,7 @@ public static double calcWifiPowerByPackets(PowerProfile powerProfile, HealthSta } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @VisibleForTesting public static double calcWifiPowerByNetworkStatBytes(PowerProfile powerProfile, RadioStatSnapshot snapshot, double rxBps, double txBps) { long rxMs = (long) ((snapshot.wifiRxBytes.get() / (rxBps / 8)) * 1000); long txMs = (long) ((snapshot.wifiTxBytes.get() / (txBps / 8)) * 1000); @@ -621,6 +624,7 @@ public static double calcWifiPowerByNetworkStatBytes(PowerProfile powerProfile, return power; } + @VisibleForTesting public static double calcWifiPowerByNetworkStatPackets(PowerProfile powerProfile, RadioStatSnapshot snapshot, double rxBps, double txBps) { double power = 0; { @@ -733,6 +737,10 @@ public static double calcSensorsPower(Context context, HealthStats healthStats) } /** + * WIP + * Calculate camera power usage. Right now, this is a (very) rough estimate based on the + * average power usage for a typical camera application. + * * @see com.android.internal.os.CameraPowerCalculator */ @RequiresApi(api = Build.VERSION_CODES.N) @@ -762,6 +770,7 @@ public static double calcFlashLightPower(PowerProfile powerProfile, HealthStats /** * @see com.android.internal.os.MediaPowerCalculator + * @see com.android.internal.os.AudioPowerCalculator */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcAudioPower(PowerProfile powerProfile, HealthStats healthStats) { @@ -779,6 +788,7 @@ public static double calcAudioPower(PowerProfile powerProfile, HealthStats healt /** * @see com.android.internal.os.MediaPowerCalculator + * @see com.android.internal.os.VideoPowerCalculator */ @RequiresApi(api = Build.VERSION_CODES.N) public static double calcVideoPower(PowerProfile powerProfile, HealthStats healthStats) { @@ -812,6 +822,7 @@ public static double calcScreenPower(PowerProfile powerProfile, HealthStats heal /** * WIP + * Binder cup time_in_state can not be collected right now * * @see com.android.internal.os.SystemServicePowerCalculator */ From d142b265357295916ee0a07cb7f1483879c1ed93 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 31 Aug 2022 21:00:07 +0800 Subject: [PATCH 159/263] Update battery canary config with tunning --- .../monitor/BatteryMonitorConfig.java | 6 + .../monitor/feature/CompositeMonitors.java | 133 +++++++++++------- 2 files changed, 85 insertions(+), 54 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java index 1f3b19130..f4d7d37b5 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java @@ -70,6 +70,7 @@ public class BatteryMonitorConfig { public CallStackCollector callStackCollector; public Function, IpcProcessJiffies> ipcJiffiesCollector; public Function, RemoteStat> ipcCpuStatCollector; + public boolean isTuningPowers = BuildConfig.DEBUG; private BatteryMonitorConfig() { } @@ -296,6 +297,11 @@ public Builder setCollector(Function, IpcProcessJiffies> c return this; } + public Builder enableTuningPowers(boolean enable) { + config.isTuningPowers = enable; + return this; + } + public BatteryMonitorConfig build() { Collections.sort(config.features, new Comparator() { @Override diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 6f4ea8c7b..6f27f906f 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -1027,9 +1027,8 @@ protected void polishEstimatedPower() { @Override public void accept(Delta healthStatsDelta) { tuningPowers(healthStatsDelta.dlt); - { - // Reset cpuPower if exists + // Reset cpuPower double power = 0; Object powers = healthStatsDelta.dlt.extras.get("JiffyUid"); if (powers instanceof Map) { @@ -1041,24 +1040,30 @@ public void accept(Delta healthStatsDelta) { } healthStatsDelta.dlt.cpuPower = DigitEntry.of(power); } - // { - // // Reset mobilePower if exists - // double power = 0; - // Object val = healthStatsDelta.dlt.extras.get("power-mobile-statByte"); - // if (val instanceof Double) { - // power = (double) val; - // } - // healthStatsDelta.dlt.mobilePower = DigitEntry.of(power); - // } - // { - // // Reset wifiPower if exists - // double power = 0; - // Object val = healthStatsDelta.dlt.extras.get("power-wifi-statByte"); - // if (val instanceof Double) { - // power = (double) val; - // } - // healthStatsDelta.dlt.wifiPower = DigitEntry.of(power); - // } + { + // Reset mobilePower if exists + if (healthStatsDelta.dlt.mobilePower.get() <= 0) { + double power = 0; + // Take power-mobile-statByte + Object val = healthStatsDelta.dlt.extras.get("power-mobile-statByte"); + if (val instanceof Double) { + power = (double) val; + } + healthStatsDelta.dlt.mobilePower = DigitEntry.of(power); + } + } + { + // Reset wifiPower if exists + if (healthStatsDelta.dlt.wifiPower.get() <= 0) { + double power = 0; + // Take power-wifi-statByte + Object val = healthStatsDelta.dlt.extras.get("power-wifi-statByte"); + if (val instanceof Double) { + power = (double) val; + } + healthStatsDelta.dlt.wifiPower = DigitEntry.of(power); + } + } } }); } @@ -1067,7 +1072,14 @@ protected void tuningPowers(final HealthStatsFeature.HealthStatsSnapshot snapsho if (!snapshot.isDelta) { throw new IllegalStateException("Only support delta snapshot"); } + BatteryMonitorCore monitor = getMonitor(); + if (monitor == null) { + return; + } + + final boolean tunning = monitor.getConfig().isTuningPowers; final Tuner tuner = new Tuner(); + getFeature(CpuStatFeature.class, new Consumer() { @Override public void accept(CpuStatFeature feat) { @@ -1079,45 +1091,47 @@ public void accept(CpuStatFeature feat) { @Override public void accept(final Delta cpuStatDelta) { // 1.1 CpuTimeMs - getDelta(HealthStatsFeature.HealthStatsSnapshot.class, new Consumer>() { - @Override - public void accept(final Delta healthStats) { - healthStats.dlt.extras.put("TimeUid", tuner.tuningCpuPowers(powerProfile, CompositeMonitors.this, new Tuner.CpuTime() { - @Override - public long getBgnMs(String procSuffix) { - return getCpuTimeMs(procSuffix, healthStats.bgn); - } + if (tunning) { + getDelta(HealthStatsSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta healthStats) { + healthStats.dlt.extras.put("TimeUid", tuner.tuningCpuPowers(powerProfile, CompositeMonitors.this, new Tuner.CpuTime() { + @Override + public long getBgnMs(String procSuffix) { + return getCpuTimeMs(procSuffix, healthStats.bgn); + } - @Override - public long getEndMs(String procSuffix) { - return getCpuTimeMs(procSuffix, healthStats.end); - } + @Override + public long getEndMs(String procSuffix) { + return getCpuTimeMs(procSuffix, healthStats.end); + } - @Override - public long getDltMs(String procSuffix) { - return getCpuTimeMs(procSuffix, healthStats.dlt); - } + @Override + public long getDltMs(String procSuffix) { + return getCpuTimeMs(procSuffix, healthStats.dlt); + } - private long getCpuTimeMs(String procSuffix, HealthStatsFeature.HealthStatsSnapshot healthStatsSnapshot) { - if (procSuffix == null) { - return healthStatsSnapshot.cpuUsrTimeMs.get() - + healthStatsSnapshot.cpuSysTimeMs.get(); - } else { - if (mMonitor != null) { - String procName = mMonitor.getContext().getPackageName(); - if ("main".equals(procSuffix)) { - procName = mMonitor.getContext().getPackageName() + ":" + procSuffix; + private long getCpuTimeMs(String procSuffix, HealthStatsSnapshot healthStatsSnapshot) { + if (procSuffix == null) { + return healthStatsSnapshot.cpuUsrTimeMs.get() + + healthStatsSnapshot.cpuSysTimeMs.get(); + } else { + if (mMonitor != null) { + String procName = mMonitor.getContext().getPackageName(); + if ("main".equals(procSuffix)) { + procName = mMonitor.getContext().getPackageName() + ":" + procSuffix; + } + DigitEntry usrTime = healthStatsSnapshot.procStatsCpuUsrTimeMs.get(procName); + DigitEntry sysTime = healthStatsSnapshot.procStatsCpuSysTimeMs.get(procName); + return (usrTime == null ? 0 : usrTime.get()) + (sysTime == null ? 0 : sysTime.get()); } - DigitEntry usrTime = healthStatsSnapshot.procStatsCpuUsrTimeMs.get(procName); - DigitEntry sysTime = healthStatsSnapshot.procStatsCpuSysTimeMs.get(procName); - return (usrTime == null ? 0 : usrTime.get()) + (sysTime == null ? 0 : sysTime.get()); } + return 0L; } - return 0L; - } - })); - } - }); + })); + } + }); + } // 1.2 CpuTimeJiffies getDelta(JiffiesMonitorFeature.UidJiffiesSnapshot.class, new Consumer>() { @@ -1265,7 +1279,7 @@ public void accept(Delta delta) { @SuppressLint("RestrictedApi") - static class Tuner { + protected static class Tuner { interface CpuTime { long getBgnMs(String procSuffix); long getEndMs(String procSuffix); @@ -1278,6 +1292,11 @@ public Map tuningCpuPowers(final PowerProfile powerProfile, fina @SuppressLint("VisibleForTests") @Override public void accept(Delta uidCpuStatDelta) { + BatteryMonitorCore monitor = monitors.getMonitor(); + if (monitor == null) { + return; + } + // Calc by DIff { // UID Diff @@ -1292,6 +1311,12 @@ public void accept(Delta uidCpuStatDelta) { } dict.put("power-cpu-uidDiff", cpuPower); } + + boolean tunning = monitor.getConfig().isTuningPowers; + if (!tunning) { + return; + } + { // UID Diff Scaled double cpuPower = 0; From 68a209356585f305843af52986243bc2ecf62620 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 1 Sep 2022 15:22:35 +0800 Subject: [PATCH 160/263] Update battery sample cfgs --- .../sample/tencent/matrix/battery/BatteryCanaryInitHelper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/BatteryCanaryInitHelper.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/BatteryCanaryInitHelper.java index 6d1a74316..97ef68b1d 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/BatteryCanaryInitHelper.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/battery/BatteryCanaryInitHelper.java @@ -119,7 +119,6 @@ public String call() { .setRecorder(new BatteryRecorder.MMKVRecorder(mmkv)) .setStats(new BatteryStats.BatteryStatsImpl()) .enable(HealthStatsFeature.class) - .enable(HealthStatsFeature.class) // Lab Feature: // network monitor From 58ae7c96793762007c70c98cf31e14a5a5e63e4a Mon Sep 17 00:00:00 2001 From: kaedexie Date: Mon, 5 Sep 2022 14:00:39 +0800 Subject: [PATCH 161/263] Update time breaker for test --- .../batterycanary/utils/TimeBreakerTest.java | 54 +++++++++++++++++++ .../batterycanary/utils/TimeBreaker.java | 17 ++++++ 2 files changed, 71 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java index 7b15e76a7..14798ba73 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java @@ -20,15 +20,21 @@ import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.Objects; @@ -278,6 +284,54 @@ public TimeBreaker.Stamp stamp(String key) { } } + @Test + public void testPortionFromJson() throws JSONException { + final List stampList = new ArrayList<>(); + JSONArray json = new JSONArray("[\n" + + " {\n" + + " \"key\": \"1\",\n" + + " \"upTime\": 13269846,\n" + + " \"statMillis\": \"05:25:05\"\n" + + " },\n" + + " {\n" + + " \"key\": \"1\",\n" + + " \"upTime\": 13269845,\n" + + " \"statMillis\": \"05:25:05\"\n" + + " }\n" + + "]"); + + for (int i = 0; i < json.length(); i++) { + JSONObject jsonObject = json.getJSONObject(i); + long upTime = jsonObject.getLong("upTime"); + Timestamp timestamp = Timestamp.valueOf(new SimpleDateFormat("yyyy-MM-dd ") + .format(new Date()) + .concat(jsonObject.getString("statMillis"))); + long statMillis = timestamp.getTime(); + TimeBreaker.Stamp stamp = new TimeBreaker.Stamp(jsonObject.getString("key"), upTime, statMillis); + stampList.add(stamp); + } + + Assert.assertFalse(stampList.isEmpty()); + + long windowMs = BatteryCanaryUtil.ONE_HOR; + final String currStat = "1"; + final long currUpTimeMs = 16978289; + final long currStatMs = Timestamp.valueOf(new SimpleDateFormat("yyyy-MM-dd ") + .format(new Date()) + .concat("06:26:54")).getTime(); + TimeBreaker.TimePortions portions = TimeBreaker.configurePortions( + stampList, + windowMs, + 10L, + new TimeBreaker.Stamp.Stamper() { + @Override + public TimeBreaker.Stamp stamp(String key) { + return new TimeBreaker.Stamp(currStat, currUpTimeMs, currStatMs); + } + }); + Assert.assertTrue(portions.isValid()); + } + @Test public void testConcurrentBenchmark() throws InterruptedException { final List stampList = new ArrayList<>(); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/TimeBreaker.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/TimeBreaker.java index 4b797953a..5e477b7ca 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/TimeBreaker.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/TimeBreaker.java @@ -11,6 +11,7 @@ import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; +import androidx.annotation.VisibleForTesting; /** * Configure timeline portions & ratio for the given stamps and return split-portions with each weight. @@ -185,6 +186,22 @@ public Stamp(String key, long upTime) { this.upTime = upTime; this.statMillis = System.currentTimeMillis(); } + + @VisibleForTesting + public Stamp(String key, long upTime, long statMillis) { + this.key = key; + this.upTime = upTime; + this.statMillis = statMillis; + } + + @Override + public String toString() { + return "Stamp{" + + "key='" + key + '\'' + + ", upTime=" + upTime + + ", statMillis=" + statMillis + + '}'; + } } public static final class TimePortions { From a4b7ec046c167fe4e7b51ff25089b6d173b65fa5 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Tue, 6 Sep 2022 16:49:18 +0800 Subject: [PATCH 162/263] Add connectivity manager hook --- .../src/androidTest/AndroidManifest.xml | 1 + .../utils/ConnectivityManagerHookerTest.java | 181 ++++++++++++++++++ .../utils/WifiManagerHookerTest.java | 2 +- .../src/main/AndroidManifest.xml | 1 - 4 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/ConnectivityManagerHookerTest.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml index e02acdf6a..0d8e7adc6 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml @@ -9,6 +9,7 @@ + >> pairs = new ArrayList<>(); + for (Network item : manager.getAllNetworks()) { + NetworkInfo networkInfo = manager.getNetworkInfo(item); + if (networkInfo != null && (networkInfo.isConnected() || networkInfo.isConnectedOrConnecting())) { + pairs.add(Arrays.asList( + new Pair<>(networkInfo.getType(), String.valueOf(networkInfo.getTypeName())), + new Pair<>(networkInfo.getSubtype(), String.valueOf(networkInfo.getSubtypeName())) + )); + int txBwKBps = 0, rxBwKBps = 0; + NetworkCapabilities capabilities = manager.getNetworkCapabilities(item); + if (capabilities != null) { + txBwKBps = capabilities.getLinkUpstreamBandwidthKbps() / 8; + rxBwKBps = capabilities.getLinkDownstreamBandwidthKbps() / 8; + } + } + } + + Assert.assertFalse(pairs.isEmpty()); + + ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() { + long mLastMs = 0; + + @Override + public void onAvailable(@NonNull Network network) { + super.onAvailable(network); + } + + @Override + public void onLosing(@NonNull Network network, int maxMsToLive) { + super.onLosing(network, maxMsToLive); + } + + @Override + public void onLost(@NonNull Network network) { + super.onLost(network); + } + + @Override + public void onUnavailable() { + super.onUnavailable(); + } + + @SuppressLint({"WrongConstant", "RestrictedApi"}) + @Override + public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { + super.onCapabilitiesChanged(network, networkCapabilities); + try { + int strength = 0; + int[] capabilities = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + strength = networkCapabilities.getSignalStrength(); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + capabilities = networkCapabilities.getCapabilities(); + } + + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { + } + } catch (Throwable ignored) { + } + + // Dual-link check: both wifi & cellar transported networks + { + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE) || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { + } + } + } catch (Throwable e) { + } + } + + @Override + public void onLinkPropertiesChanged(@NonNull Network network, @NonNull LinkProperties linkProperties) { + super.onLinkPropertiesChanged(network, linkProperties); + } + + @Override + public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) { + super.onBlockedStatusChanged(network, blocked); + } + }; + + manager.registerDefaultNetworkCallback(callback); + hooker.doUnHook(); + } +} + diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java index c1ecc28d1..02a36cadf 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java @@ -36,7 +36,7 @@ @RunWith(AndroidJUnit4.class) public class WifiManagerHookerTest { - static final String TAG = "Matrix.test.BleManagerHookerTest"; + static final String TAG = "Matrix.test.WifiManagerHookerTest"; Context mContext; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/AndroidManifest.xml b/matrix/matrix-android/matrix-battery-canary/src/main/AndroidManifest.xml index 8bddbf7a1..a7cd0a922 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ - Date: Wed, 7 Sep 2022 17:29:49 +0800 Subject: [PATCH 163/263] Fix health stats npe issue --- .../monitor/feature/CompositeMonitors.java | 51 +++++++++++++------ .../stats/HealthStatsFeature.java | 2 + 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 6f27f906f..2b13dcb80 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -1221,30 +1221,50 @@ public void accept(Delta delta) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { // mobile { - double powerBgn = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, delta.bgn.healthStats); - double powerEnd = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, delta.end.healthStats); - snapshot.extras.put("power-mobile-radio", powerEnd - powerBgn); + double power = 0; + if (delta.bgn.healthStats != null && delta.end.healthStats != null) { + double powerBgn = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, delta.bgn.healthStats); + double powerEnd = HealthStatsHelper.calcMobilePowerByRadioActive(powerProfile, delta.end.healthStats); + power = powerEnd - powerBgn; + } + snapshot.extras.put("power-mobile-radio", power); } { - double powerBgn = HealthStatsHelper.calcMobilePowerByController(powerProfile, delta.bgn.healthStats); - double powerEnd = HealthStatsHelper.calcMobilePowerByController(powerProfile, delta.end.healthStats); - snapshot.extras.put("power-mobile-controller", powerEnd - powerBgn); + double power = 0; + if (delta.bgn.healthStats != null && delta.end.healthStats != null) { + double powerBgn = HealthStatsHelper.calcMobilePowerByController(powerProfile, delta.bgn.healthStats); + double powerEnd = HealthStatsHelper.calcMobilePowerByController(powerProfile, delta.end.healthStats); + power = powerEnd - powerBgn; + } + snapshot.extras.put("power-mobile-controller", power); } { - double powerBgn = HealthStatsHelper.calcMobilePowerByPackets(powerProfile, delta.bgn.healthStats, finalMobileRxBps, finalMobileTxBps); - double powerEnd = HealthStatsHelper.calcMobilePowerByPackets(powerProfile, delta.end.healthStats, finalMobileRxBps, finalMobileTxBps); - snapshot.extras.put("power-mobile-packet", powerEnd - powerBgn); + double power = 0; + if (delta.bgn.healthStats != null && delta.end.healthStats != null) { + double powerBgn = HealthStatsHelper.calcMobilePowerByPackets(powerProfile, delta.bgn.healthStats, finalMobileRxBps, finalMobileTxBps); + double powerEnd = HealthStatsHelper.calcMobilePowerByPackets(powerProfile, delta.end.healthStats, finalMobileRxBps, finalMobileTxBps); + power = powerEnd - powerBgn; + } + snapshot.extras.put("power-mobile-packet", power); } // wifi { - double powerBgn = HealthStatsHelper.calcWifiPowerByController(powerProfile, delta.bgn.healthStats); - double powerEnd = HealthStatsHelper.calcWifiPowerByController(powerProfile, delta.end.healthStats); - snapshot.extras.put("power-wifi-controller", powerEnd - powerBgn); + double power = 0; + if (delta.bgn.healthStats != null && delta.end.healthStats != null) { + double powerBgn = HealthStatsHelper.calcWifiPowerByController(powerProfile, delta.bgn.healthStats); + double powerEnd = HealthStatsHelper.calcWifiPowerByController(powerProfile, delta.end.healthStats); + power = powerEnd - powerBgn; + } + snapshot.extras.put("power-wifi-controller", power); } { - double powerBgn = HealthStatsHelper.calcWifiPowerByPackets(powerProfile, delta.bgn.healthStats, finalWifiRxBps, finalWifiTxBps); - double powerEnd = HealthStatsHelper.calcWifiPowerByPackets(powerProfile, delta.end.healthStats, finalWifiRxBps, finalWifiTxBps); - snapshot.extras.put("power-wifi-packet", powerEnd - powerBgn); + double power = 0; + if (delta.bgn.healthStats != null && delta.end.healthStats != null) { + double powerBgn = HealthStatsHelper.calcWifiPowerByPackets(powerProfile, delta.bgn.healthStats, finalWifiRxBps, finalWifiTxBps); + double powerEnd = HealthStatsHelper.calcWifiPowerByPackets(powerProfile, delta.end.healthStats, finalWifiRxBps, finalWifiTxBps); + power = powerEnd - powerBgn; + } + snapshot.extras.put("power-wifi-packet", power); } } } @@ -1252,6 +1272,7 @@ public void accept(Delta delta) { // 2.2 RadioStat getDelta(TrafficMonitorFeature.RadioStatSnapshot.class, new Consumer>() { + @SuppressLint("VisibleForTests") @Override public void accept(Delta delta) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mMonitor != null) { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 190ade61d..59a1d31b2 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -27,6 +27,7 @@ import java.util.Map; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; /** @@ -257,6 +258,7 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { public static class HealthStatsSnapshot extends Snapshot { @VisibleForTesting + @Nullable public HealthStats healthStats; public Map extras = Collections.emptyMap(); From 7bd65c2df9a99f56db4b23ba46270bd6f705d15b Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 7 Sep 2022 17:41:25 +0800 Subject: [PATCH 164/263] Revert tests codes --- .../src/androidTest/AndroidManifest.xml | 1 - .../utils/ConnectivityManagerHookerTest.java | 181 ------------------ .../batterycanary/utils/TimeBreakerTest.java | 54 ------ .../utils/WifiManagerHookerTest.java | 2 +- 4 files changed, 1 insertion(+), 237 deletions(-) delete mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/ConnectivityManagerHookerTest.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml index 0d8e7adc6..e02acdf6a 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml @@ -9,7 +9,6 @@ - >> pairs = new ArrayList<>(); - for (Network item : manager.getAllNetworks()) { - NetworkInfo networkInfo = manager.getNetworkInfo(item); - if (networkInfo != null && (networkInfo.isConnected() || networkInfo.isConnectedOrConnecting())) { - pairs.add(Arrays.asList( - new Pair<>(networkInfo.getType(), String.valueOf(networkInfo.getTypeName())), - new Pair<>(networkInfo.getSubtype(), String.valueOf(networkInfo.getSubtypeName())) - )); - int txBwKBps = 0, rxBwKBps = 0; - NetworkCapabilities capabilities = manager.getNetworkCapabilities(item); - if (capabilities != null) { - txBwKBps = capabilities.getLinkUpstreamBandwidthKbps() / 8; - rxBwKBps = capabilities.getLinkDownstreamBandwidthKbps() / 8; - } - } - } - - Assert.assertFalse(pairs.isEmpty()); - - ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() { - long mLastMs = 0; - - @Override - public void onAvailable(@NonNull Network network) { - super.onAvailable(network); - } - - @Override - public void onLosing(@NonNull Network network, int maxMsToLive) { - super.onLosing(network, maxMsToLive); - } - - @Override - public void onLost(@NonNull Network network) { - super.onLost(network); - } - - @Override - public void onUnavailable() { - super.onUnavailable(); - } - - @SuppressLint({"WrongConstant", "RestrictedApi"}) - @Override - public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { - super.onCapabilitiesChanged(network, networkCapabilities); - try { - int strength = 0; - int[] capabilities = null; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - strength = networkCapabilities.getSignalStrength(); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - capabilities = networkCapabilities.getCapabilities(); - } - - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { - } - } catch (Throwable ignored) { - } - - // Dual-link check: both wifi & cellar transported networks - { - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE) || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { - } - } - } catch (Throwable e) { - } - } - - @Override - public void onLinkPropertiesChanged(@NonNull Network network, @NonNull LinkProperties linkProperties) { - super.onLinkPropertiesChanged(network, linkProperties); - } - - @Override - public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) { - super.onBlockedStatusChanged(network, blocked); - } - }; - - manager.registerDefaultNetworkCallback(callback); - hooker.doUnHook(); - } -} - diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java index 14798ba73..7b15e76a7 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java @@ -20,21 +20,15 @@ import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.sql.Timestamp; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Date; import java.util.List; import java.util.Objects; @@ -284,54 +278,6 @@ public TimeBreaker.Stamp stamp(String key) { } } - @Test - public void testPortionFromJson() throws JSONException { - final List stampList = new ArrayList<>(); - JSONArray json = new JSONArray("[\n" + - " {\n" + - " \"key\": \"1\",\n" + - " \"upTime\": 13269846,\n" + - " \"statMillis\": \"05:25:05\"\n" + - " },\n" + - " {\n" + - " \"key\": \"1\",\n" + - " \"upTime\": 13269845,\n" + - " \"statMillis\": \"05:25:05\"\n" + - " }\n" + - "]"); - - for (int i = 0; i < json.length(); i++) { - JSONObject jsonObject = json.getJSONObject(i); - long upTime = jsonObject.getLong("upTime"); - Timestamp timestamp = Timestamp.valueOf(new SimpleDateFormat("yyyy-MM-dd ") - .format(new Date()) - .concat(jsonObject.getString("statMillis"))); - long statMillis = timestamp.getTime(); - TimeBreaker.Stamp stamp = new TimeBreaker.Stamp(jsonObject.getString("key"), upTime, statMillis); - stampList.add(stamp); - } - - Assert.assertFalse(stampList.isEmpty()); - - long windowMs = BatteryCanaryUtil.ONE_HOR; - final String currStat = "1"; - final long currUpTimeMs = 16978289; - final long currStatMs = Timestamp.valueOf(new SimpleDateFormat("yyyy-MM-dd ") - .format(new Date()) - .concat("06:26:54")).getTime(); - TimeBreaker.TimePortions portions = TimeBreaker.configurePortions( - stampList, - windowMs, - 10L, - new TimeBreaker.Stamp.Stamper() { - @Override - public TimeBreaker.Stamp stamp(String key) { - return new TimeBreaker.Stamp(currStat, currUpTimeMs, currStatMs); - } - }); - Assert.assertTrue(portions.isValid()); - } - @Test public void testConcurrentBenchmark() throws InterruptedException { final List stampList = new ArrayList<>(); diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java index 02a36cadf..c1ecc28d1 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java @@ -36,7 +36,7 @@ @RunWith(AndroidJUnit4.class) public class WifiManagerHookerTest { - static final String TAG = "Matrix.test.WifiManagerHookerTest"; + static final String TAG = "Matrix.test.BleManagerHookerTest"; Context mContext; From 107feb4e1948d34f777da90cd42930b0619f9a9a Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 7 Sep 2022 17:43:04 +0800 Subject: [PATCH 165/263] Revert "Revert tests codes" This reverts commit 7bd65c2df9a99f56db4b23ba46270bd6f705d15b. --- .../src/androidTest/AndroidManifest.xml | 1 + .../utils/ConnectivityManagerHookerTest.java | 181 ++++++++++++++++++ .../batterycanary/utils/TimeBreakerTest.java | 54 ++++++ .../utils/WifiManagerHookerTest.java | 2 +- 4 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/ConnectivityManagerHookerTest.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml index e02acdf6a..0d8e7adc6 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/AndroidManifest.xml @@ -9,6 +9,7 @@ + >> pairs = new ArrayList<>(); + for (Network item : manager.getAllNetworks()) { + NetworkInfo networkInfo = manager.getNetworkInfo(item); + if (networkInfo != null && (networkInfo.isConnected() || networkInfo.isConnectedOrConnecting())) { + pairs.add(Arrays.asList( + new Pair<>(networkInfo.getType(), String.valueOf(networkInfo.getTypeName())), + new Pair<>(networkInfo.getSubtype(), String.valueOf(networkInfo.getSubtypeName())) + )); + int txBwKBps = 0, rxBwKBps = 0; + NetworkCapabilities capabilities = manager.getNetworkCapabilities(item); + if (capabilities != null) { + txBwKBps = capabilities.getLinkUpstreamBandwidthKbps() / 8; + rxBwKBps = capabilities.getLinkDownstreamBandwidthKbps() / 8; + } + } + } + + Assert.assertFalse(pairs.isEmpty()); + + ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() { + long mLastMs = 0; + + @Override + public void onAvailable(@NonNull Network network) { + super.onAvailable(network); + } + + @Override + public void onLosing(@NonNull Network network, int maxMsToLive) { + super.onLosing(network, maxMsToLive); + } + + @Override + public void onLost(@NonNull Network network) { + super.onLost(network); + } + + @Override + public void onUnavailable() { + super.onUnavailable(); + } + + @SuppressLint({"WrongConstant", "RestrictedApi"}) + @Override + public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { + super.onCapabilitiesChanged(network, networkCapabilities); + try { + int strength = 0; + int[] capabilities = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + strength = networkCapabilities.getSignalStrength(); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + capabilities = networkCapabilities.getCapabilities(); + } + + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { + } + } catch (Throwable ignored) { + } + + // Dual-link check: both wifi & cellar transported networks + { + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE) || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { + } + } + } catch (Throwable e) { + } + } + + @Override + public void onLinkPropertiesChanged(@NonNull Network network, @NonNull LinkProperties linkProperties) { + super.onLinkPropertiesChanged(network, linkProperties); + } + + @Override + public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) { + super.onBlockedStatusChanged(network, blocked); + } + }; + + manager.registerDefaultNetworkCallback(callback); + hooker.doUnHook(); + } +} + diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java index 7b15e76a7..14798ba73 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/TimeBreakerTest.java @@ -20,15 +20,21 @@ import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.Objects; @@ -278,6 +284,54 @@ public TimeBreaker.Stamp stamp(String key) { } } + @Test + public void testPortionFromJson() throws JSONException { + final List stampList = new ArrayList<>(); + JSONArray json = new JSONArray("[\n" + + " {\n" + + " \"key\": \"1\",\n" + + " \"upTime\": 13269846,\n" + + " \"statMillis\": \"05:25:05\"\n" + + " },\n" + + " {\n" + + " \"key\": \"1\",\n" + + " \"upTime\": 13269845,\n" + + " \"statMillis\": \"05:25:05\"\n" + + " }\n" + + "]"); + + for (int i = 0; i < json.length(); i++) { + JSONObject jsonObject = json.getJSONObject(i); + long upTime = jsonObject.getLong("upTime"); + Timestamp timestamp = Timestamp.valueOf(new SimpleDateFormat("yyyy-MM-dd ") + .format(new Date()) + .concat(jsonObject.getString("statMillis"))); + long statMillis = timestamp.getTime(); + TimeBreaker.Stamp stamp = new TimeBreaker.Stamp(jsonObject.getString("key"), upTime, statMillis); + stampList.add(stamp); + } + + Assert.assertFalse(stampList.isEmpty()); + + long windowMs = BatteryCanaryUtil.ONE_HOR; + final String currStat = "1"; + final long currUpTimeMs = 16978289; + final long currStatMs = Timestamp.valueOf(new SimpleDateFormat("yyyy-MM-dd ") + .format(new Date()) + .concat("06:26:54")).getTime(); + TimeBreaker.TimePortions portions = TimeBreaker.configurePortions( + stampList, + windowMs, + 10L, + new TimeBreaker.Stamp.Stamper() { + @Override + public TimeBreaker.Stamp stamp(String key) { + return new TimeBreaker.Stamp(currStat, currUpTimeMs, currStatMs); + } + }); + Assert.assertTrue(portions.isValid()); + } + @Test public void testConcurrentBenchmark() throws InterruptedException { final List stampList = new ArrayList<>(); diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java index c1ecc28d1..02a36cadf 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/WifiManagerHookerTest.java @@ -36,7 +36,7 @@ @RunWith(AndroidJUnit4.class) public class WifiManagerHookerTest { - static final String TAG = "Matrix.test.BleManagerHookerTest"; + static final String TAG = "Matrix.test.WifiManagerHookerTest"; Context mContext; From a79c28d4cda1d6178ed6cd93c132d9d6774ca17d Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 7 Sep 2022 19:48:52 +0800 Subject: [PATCH 166/263] Fix battery canary handler --- .../matrix/batterycanary/monitor/BatteryMonitorCore.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java index 2114f0f1d..2c4ec405b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java @@ -93,6 +93,7 @@ public void run() { private final BatteryMonitorConfig mConfig; @NonNull private final Handler mHandler; + @NonNull private final Handler mCanaryHandler; @Nullable private ForegroundLoopCheckTask mFgLooperTask; @Nullable private BackgroundLoopCheckTask mBgLooperTask; @Nullable private TaskJiffiesSnapshot mLastInternalSnapshot; @@ -121,7 +122,8 @@ public BatteryMonitorCore(BatteryMonitorConfig config) { mSupplier = config.onSceneSupplier; } - mHandler = new Handler(MatrixHandlerThread.getDefaultHandlerThread().getLooper(), this); + mHandler = new Handler(MatrixHandlerThread.getDefaultHandlerThread().getLooper(), this); // For BatteryMonitorCore only + mCanaryHandler = new Handler(MatrixHandlerThread.getDefaultHandlerThread().getLooper(), this); // For BatteryCanary enableForegroundLoopCheck(config.isForegroundModeEnabled); enableBackgroundLoopCheck(config.isBackgroundModeEnabled); mMonitorDelayMillis = config.greyTime; @@ -265,7 +267,7 @@ public void onForeground(boolean isForeground) { @NonNull public Handler getHandler() { - return mHandler; + return mCanaryHandler; } public Context getContext() { From c1fdb81fb4f86a76005ea7a70c5199f197cc5b40 Mon Sep 17 00:00:00 2001 From: opdeng Date: Thu, 8 Sep 2022 16:27:13 +0800 Subject: [PATCH 167/263] =?UTF-8?q?binder=20=E6=B7=BB=E5=8A=A0=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E4=BF=9D=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix/openglleak/OpenglLeakPlugin.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java index 6650427b7..e83edbce0 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java @@ -132,22 +132,27 @@ private void executeHook(IBinder iBinder) { private void startImpl() { Intent service = new Intent(context, OpenglIndexDetectorService.class); - boolean result = context.bindService(service, new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName componentName, final IBinder iBinder) { - new Thread(new Runnable() { - @Override - public void run() { - executeHook(iBinder); - } - }).start(); - } + boolean result = false; + try { + result = context.bindService(service, new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, final IBinder iBinder) { + new Thread(new Runnable() { + @Override + public void run() { + executeHook(iBinder); + } + }).start(); + } - @Override - public void onServiceDisconnected(ComponentName componentName) { - context.unbindService(this); - } - }, Context.BIND_AUTO_CREATE); + @Override + public void onServiceDisconnected(ComponentName componentName) { + context.unbindService(this); + } + }, Context.BIND_AUTO_CREATE); + } catch (Exception e) { + MatrixLog.d(TAG, "bindService error = " + e.getCause()); + } MatrixLog.d(TAG, "bindService result = " + result); if (result) { From 5177796bf1227fd071e141aadf6f88e694fe7462 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 8 Sep 2022 17:10:58 +0800 Subject: [PATCH 168/263] Update battery handler thread cfg --- .../matrix/batterycanary/monitor/BatteryMonitorCore.java | 7 +++++-- .../matrix/batterycanary/stats/BatteryStatsFeature.java | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java index 2c4ec405b..7516dcc2c 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java @@ -4,6 +4,7 @@ import android.content.ComponentName; import android.content.Context; import android.os.Handler; +import android.os.HandlerThread; import android.os.Message; import com.tencent.matrix.Matrix; @@ -122,8 +123,10 @@ public BatteryMonitorCore(BatteryMonitorConfig config) { mSupplier = config.onSceneSupplier; } - mHandler = new Handler(MatrixHandlerThread.getDefaultHandlerThread().getLooper(), this); // For BatteryMonitorCore only - mCanaryHandler = new Handler(MatrixHandlerThread.getDefaultHandlerThread().getLooper(), this); // For BatteryCanary + //noinspection SpellCheckingInspection + HandlerThread thread = MatrixHandlerThread.getNewHandlerThread("matrix_batt", Thread.NORM_PRIORITY); + mHandler = new Handler(thread.getLooper(), this); // For BatteryMonitorCore only + mCanaryHandler = new Handler(thread.getLooper(), this); // For BatteryCanary enableForegroundLoopCheck(config.isForegroundModeEnabled); enableBackgroundLoopCheck(config.isBackgroundModeEnabled); mMonitorDelayMillis = config.greyTime; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/BatteryStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/BatteryStatsFeature.java index 07f81e3c4..30df7d54b 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/BatteryStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/BatteryStatsFeature.java @@ -49,7 +49,7 @@ public void onTurnOn() { mBatteryRecorder = mCore.getConfig().batteryRecorder; mBatteryStats = mCore.getConfig().batteryStats; if (mBatteryRecorder != null) { - mStatsThread = MatrixHandlerThread.getNewHandlerThread("matrix-stats", Thread.NORM_PRIORITY); + mStatsThread = MatrixHandlerThread.getNewHandlerThread("matrix_stats", Thread.MIN_PRIORITY); mStatsHandler = new Handler(mStatsThread.getLooper()); mStatsHandler.post(new Runnable() { @Override From be931c574eff05a5a721b9f0098c1f641591fb0f Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 9 Sep 2022 12:56:42 +0800 Subject: [PATCH 169/263] Add battery currency inspector --- .../utils/BatteryCurrencyInspectorTest.java | 53 ++++++++++++++++ .../utils/BatteryCurrencyInspector.java | 62 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspectorTest.java create mode 100644 matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspector.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspectorTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspectorTest.java new file mode 100644 index 000000000..3a13fb736 --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspectorTest.java @@ -0,0 +1,53 @@ +package com.tencent.matrix.batterycanary.utils; + +import android.app.Application; +import android.content.Context; + +import com.tencent.matrix.Matrix; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +/** + * @author Kaede + * @since 9/9/2022 + */ +@RunWith(AndroidJUnit4.class) +public class BatteryCurrencyInspectorTest { + static final String TAG = "Matrix.test.BatteryCurrencyInspectorTest"; + + Context mContext; + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + if (!Matrix.isInstalled()) { + Matrix.init(new Matrix.Builder(((Application) mContext.getApplicationContext())).build()); + } + } + + @After + public void shutDown() { + } + + @Test + @SuppressWarnings("ConstantConditions") + public void testInspection() { + boolean charging = BatteryCanaryUtil.isDeviceCharging(mContext); + if (charging) { + Assert.assertNull(BatteryCurrencyInspector.isMicroAmpCurr(mContext)); + Assert.assertTrue(BatteryCurrencyInspector.isPositiveInChargeCurr(mContext)); + Assert.assertNull(BatteryCurrencyInspector.isPositiveOutOfChargeCurr(mContext)); + } else { + Assert.assertTrue(BatteryCurrencyInspector.isMicroAmpCurr(mContext)); + Assert.assertNull(BatteryCurrencyInspector.isPositiveInChargeCurr(mContext)); + Assert.assertFalse(BatteryCurrencyInspector.isPositiveOutOfChargeCurr(mContext)); + } + } +} diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspector.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspector.java new file mode 100644 index 000000000..a1159808d --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspector.java @@ -0,0 +1,62 @@ +package com.tencent.matrix.batterycanary.utils; + +import android.content.Context; +import android.os.BatteryManager; + +import androidx.annotation.Nullable; + +/** + * Since {@link BatteryManager#BATTERY_PROPERTY_CURRENT_NOW} will return microAmp/millisAmp & + * positive/negative value in difference devices, here we figure out the unit somehow. + * + * @author Kaede + * @since 9/9/2022 + */ +public class BatteryCurrencyInspector { + + /** + * To get a high currency value, you are supposed to call this API within a high cpu-load + * activity & without charging. (When the device's cpu-load is very low, we can not tell + * microAmp or millisAmp.) + */ + @Nullable + public static Boolean isMicroAmpCurr(Context context) { + if (BatteryCanaryUtil.isDeviceCharging(context)) { + // Currency might be very low in charge + return null; + } + long val = BatteryCanaryUtil.getBatteryCurrencyImmediately(context); + if (val == -1) { + return null; + } + return isMicroAmp(val); + } + + public static boolean isMicroAmp(long amp) { + return amp > 1000L; + } + + @Nullable + public static Boolean isPositiveInChargeCurr(Context context) { + if (!BatteryCanaryUtil.isDeviceCharging(context)) { + return null; + } + long val = BatteryCanaryUtil.getBatteryCurrencyImmediately(context); + if (val == -1) { + return null; + } + return val > 0; + } + + @Nullable + public static Boolean isPositiveOutOfChargeCurr(Context context) { + if (BatteryCanaryUtil.isDeviceCharging(context)) { + return null; + } + long val = BatteryCanaryUtil.getBatteryCurrencyImmediately(context); + if (val == -1) { + return null; + } + return val > 0; + } +} From ae848f2045cf9f421f4ef6d654a65687905eeab5 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 9 Sep 2022 15:48:00 +0800 Subject: [PATCH 170/263] Update battery currency inspect --- .../utils/BatteryCurrencyInspector.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspector.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspector.java index a1159808d..c3186b072 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspector.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/BatteryCurrencyInspector.java @@ -20,7 +20,7 @@ public class BatteryCurrencyInspector { * microAmp or millisAmp.) */ @Nullable - public static Boolean isMicroAmpCurr(Context context) { + public static Boolean isMicroAmpCurr(Context context, int threshold) { if (BatteryCanaryUtil.isDeviceCharging(context)) { // Currency might be very low in charge return null; @@ -29,11 +29,16 @@ public static Boolean isMicroAmpCurr(Context context) { if (val == -1) { return null; } - return isMicroAmp(val); + return isMicroAmp(val, threshold); + } + + @Nullable + public static Boolean isMicroAmpCurr(Context context) { + return isMicroAmpCurr(context, 1000); } - public static boolean isMicroAmp(long amp) { - return amp > 1000L; + public static boolean isMicroAmp(long amp, int threshold) { + return amp > threshold; } @Nullable From 89fd8d51fb0e0cff86290a43bedd6a6463bd9244 Mon Sep 17 00:00:00 2001 From: aurorani Date: Tue, 30 Aug 2022 19:19:19 +0800 Subject: [PATCH 171/263] fix: Support ZIP with directory entries. --- .../matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt index 9285b3ac0..91ca0ab88 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt @@ -259,8 +259,10 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { if (zipEntry.method == ZipEntry.DEFLATED) { compressedEntry.add(destFile) } - Log.d(TAG, "unzip %s to file %s", zipEntry.name, destFile) - ApkUtil.unzipEntry(zipInputFile, zipEntry, destFile) + if (!zipEntry.isDirectory) { + Log.d(TAG, "unzip %s to file %s", zipEntry.name, destFile) + ApkUtil.unzipEntry(zipInputFile, zipEntry, destFile) + } } } else { Log.w(TAG, "parse entry %s resource name failed!", zipEntry.name) @@ -270,7 +272,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { if (zipEntry.method == ZipEntry.DEFLATED) { compressedEntry.add(destFile) } - if (zipEntry.name != ARSC_FILE_NAME) { // has already unzip resources.arsc before + if (!zipEntry.isDirectory && zipEntry.name != ARSC_FILE_NAME) { // has already unzip resources.arsc before Log.d(TAG, "unzip %s to file %s", zipEntry.name, destFile) ApkUtil.unzipEntry(zipInputFile, zipEntry, destFile) } From 2d9fed38716eee1a721d84d6b2858871d873dc4c Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 14 Sep 2022 18:50:28 +0800 Subject: [PATCH 172/263] Update canary thread cfg --- .../batterycanary/monitor/BatteryMonitorConfig.java | 8 ++++++++ .../matrix/batterycanary/monitor/BatteryMonitorCore.java | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java index f4d7d37b5..744be111c 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java @@ -1,6 +1,7 @@ package com.tencent.matrix.batterycanary.monitor; import android.app.ActivityManager; +import android.os.HandlerThread; import com.tencent.matrix.batterycanary.BuildConfig; import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature.UidCpuStateSnapshot.IpcCpuStat.RemoteStat; @@ -36,6 +37,8 @@ public class BatteryMonitorConfig { public static final int AMS_HOOK_FLAG_BT = 0b00000001; + @Nullable + public HandlerThread canaryThread = null; @NonNull public BatteryMonitorCallback callback = new BatteryMonitorCallback.BatteryPrinter(); @Nullable @@ -114,6 +117,11 @@ public String toString() { public static class Builder { private final BatteryMonitorConfig config = new BatteryMonitorConfig(); + public Builder setCallback(HandlerThread thread) { + config.canaryThread = thread; + return this; + } + public Builder setCallback(BatteryMonitorCallback callback) { config.callback = callback; return this; diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java index 7516dcc2c..987cbe8a6 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java @@ -97,7 +97,6 @@ public void run() { @NonNull private final Handler mCanaryHandler; @Nullable private ForegroundLoopCheckTask mFgLooperTask; @Nullable private BackgroundLoopCheckTask mBgLooperTask; - @Nullable private TaskJiffiesSnapshot mLastInternalSnapshot; @NonNull Callable mSupplier = new Callable() { @@ -123,8 +122,10 @@ public BatteryMonitorCore(BatteryMonitorConfig config) { mSupplier = config.onSceneSupplier; } - //noinspection SpellCheckingInspection - HandlerThread thread = MatrixHandlerThread.getNewHandlerThread("matrix_batt", Thread.NORM_PRIORITY); + HandlerThread thread = config.canaryThread; + if (thread == null) { + thread = MatrixHandlerThread.getNewHandlerThread("matrix_batt", Thread.NORM_PRIORITY); + } mHandler = new Handler(thread.getLooper(), this); // For BatteryMonitorCore only mCanaryHandler = new Handler(thread.getLooper(), this); // For BatteryCanary enableForegroundLoopCheck(config.isForegroundModeEnabled); From 4b6d8e77d04fc12244654a8a625ed2d7d58f8800 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 14 Sep 2022 19:00:12 +0800 Subject: [PATCH 173/263] Update canary thread cfg --- .../monitor/BatteryMonitorConfig.java | 2 +- .../batterycanary/monitor/BatteryMonitorCore.java | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java index 744be111c..0b74bfe18 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorConfig.java @@ -117,7 +117,7 @@ public String toString() { public static class Builder { private final BatteryMonitorConfig config = new BatteryMonitorConfig(); - public Builder setCallback(HandlerThread thread) { + public Builder setCanaryThread(HandlerThread thread) { config.canaryThread = thread; return this; } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java index 987cbe8a6..9e6506b37 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCore.java @@ -122,12 +122,16 @@ public BatteryMonitorCore(BatteryMonitorConfig config) { mSupplier = config.onSceneSupplier; } - HandlerThread thread = config.canaryThread; - if (thread == null) { - thread = MatrixHandlerThread.getNewHandlerThread("matrix_batt", Thread.NORM_PRIORITY); + if (config.canaryThread != null) { + HandlerThread thread = config.canaryThread; + mHandler = new Handler(thread.getLooper(), this); // For BatteryMonitorCore only + mCanaryHandler = new Handler(thread.getLooper(), this); // For BatteryCanary + } else { + HandlerThread thread = MatrixHandlerThread.getDefaultHandlerThread(); + mHandler = new Handler(thread.getLooper(), this); // For BatteryMonitorCore only + mCanaryHandler = mHandler; // For BatteryCanary as legacy logic } - mHandler = new Handler(thread.getLooper(), this); // For BatteryMonitorCore only - mCanaryHandler = new Handler(thread.getLooper(), this); // For BatteryCanary + enableForegroundLoopCheck(config.isForegroundModeEnabled); enableBackgroundLoopCheck(config.isBackgroundModeEnabled); mMonitorDelayMillis = config.greyTime; From f2fd0ac2f87ac700e1d41f638e056d492810c65e Mon Sep 17 00:00:00 2001 From: aurorani Date: Thu, 15 Sep 2022 11:36:05 +0800 Subject: [PATCH 174/263] feat: Add several property-override methods. --- .../MatrixRemoveUnusedResExtension.kt | 4 ++ .../task/RemoveUnusedResourcesTaskV2.kt | 50 ++++++++++++++----- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/extension/MatrixRemoveUnusedResExtension.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/extension/MatrixRemoveUnusedResExtension.kt index 2ad288ee7..1232274a6 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/extension/MatrixRemoveUnusedResExtension.kt +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/extension/MatrixRemoveUnusedResExtension.kt @@ -29,6 +29,8 @@ open class MatrixRemoveUnusedResExtension( var variant: String = "", + var obfuscatedResourcesDirectoryName: String? = null, + // WIP. Should not use these options yet. var use7zip: Boolean = false, var zipAlign: Boolean = false, @@ -55,6 +57,8 @@ open class MatrixRemoveUnusedResExtension( | sevenZipPath = ${sevenZipPath} | zipAlignPath = ${zipAlignPath} | ignoreResources = ${ignoreResources} + | obfuscatedResourcesDirectoryName = ${obfuscatedResourcesDirectoryName} + | """.trimMargin() } } diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt index 91ca0ab88..ad549a1fd 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt @@ -69,6 +69,10 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { private var is7zipEnabled: Boolean = false private var isResGuardEnabled: Boolean = false + private var obfuscatedResourcesDirectoryName: String? = null + private var overrideInputApkFiles: List = emptyList() + private var resguardMapping: File? = null + private lateinit var pathOfApkChecker: String private lateinit var pathOfApkSigner: String private lateinit var pathOfZipAlign: String @@ -76,20 +80,30 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { private lateinit var rulesOfIgnore: Set + fun overrideInputApkFiles(inputApkFiles: List) { + this.overrideInputApkFiles = inputApkFiles.map { File(it) } + } + + fun withResguardMapping(path: String) { + resguardMapping = File(path) + } + @TaskAction fun removeResources() { - - variant.outputs.forEach { output -> - val startTime = System.currentTimeMillis() - removeResourcesV2( + overrideInputApkFiles + .ifEmpty { + variant.outputs.map { it.outputFile } + } + .forEach { apk -> + val startTime = System.currentTimeMillis() + removeResourcesV2( project = project, - originalApkFile = output.outputFile, + originalApkFile = apk, signingConfig = AgpCompat.getSigningConfig(variant), nameOfSymbolDirectory = AgpCompat.getIntermediatesSymbolDirName() - ) - Log.i(TAG, "cost time %f s", (System.currentTimeMillis() - startTime) / 1000.0f) - - } + ) + Log.i(TAG, "cost time %f s", (System.currentTimeMillis() - startTime) / 1000.0f) + } } class CreationAction( @@ -113,6 +127,10 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { task.is7zipEnabled = use7zip task.isResGuardEnabled = embedResGuard + task.obfuscatedResourcesDirectoryName = obfuscatedResourcesDirectoryName?.let { + if (it.endsWith("/")) it else "${it}/" + } + task.pathOfApkChecker = apkCheckerPath task.pathOfApkSigner = apksignerPath task.pathOfZipAlign = zipAlignPath @@ -354,6 +372,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { pathOfOriginalApk: String, pathOfMapping: String, pathOfRTxt: String, + pathOfResguardMapping: String?, resultOfUnused: MutableSet, resultOfDuplicates: MutableMap> ) { @@ -381,6 +400,10 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { parameters.add("-unusedResources") parameters.add("--rTxt") parameters.add(pathOfRTxt) + if (pathOfResguardMapping != null) { + parameters.add("--resMappingTxt") + parameters.add(pathOfResguardMapping) + } val parametersOfIgnoredResources = StringBuilder() if (configOfIgnoredResources.isNotEmpty()) { @@ -497,7 +520,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { val duplicatesNames = HashMap() if (duplicatesEntries != null) { for (entry in duplicatesEntries) { - if (!entry.startsWith("res/")) { + if (!entry.startsWith(obfuscatedResourcesDirectoryName ?: "res/")) { Log.w(TAG, " %s is not resource file!", entry) continue } else { @@ -647,9 +670,9 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { var startTime = System.currentTimeMillis() val rTxtFile = File(project.buildDir, "intermediates") - .resolve(nameOfSymbolDirectory) - .resolve(variant.name) - .resolve("R.txt") + .resolve(nameOfSymbolDirectory) + .resolve(variant.name) + .resolve("R.txt") val mappingTxtFile = File(project.buildDir, "outputs") .resolve("mapping") @@ -668,6 +691,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { pathOfOriginalApk = originalApkPath, pathOfMapping = mappingTxtFile.absolutePath, pathOfRTxt = rTxtFile.absolutePath, + pathOfResguardMapping = resguardMapping?.absolutePath, // result resultOfUnused = setOfUnusedResources, From 65d50fecfb864e94f5e301f623a7310e981ad01a Mon Sep 17 00:00:00 2001 From: yvesluo Date: Mon, 26 Sep 2022 17:06:01 +0800 Subject: [PATCH 175/263] matrix-res-plugin: append hashcode of leaked Activity to ref_key --- .../com/tencent/matrix/resource/watcher/ActivityRefWatcher.java | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/watcher/ActivityRefWatcher.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/watcher/ActivityRefWatcher.java index ba6b53845..39e30a970 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/watcher/ActivityRefWatcher.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/watcher/ActivityRefWatcher.java @@ -202,6 +202,7 @@ && isPublished(activityName)) { final UUID uuid = UUID.randomUUID(); final StringBuilder keyBuilder = new StringBuilder(); keyBuilder.append(ACTIVITY_REFKEY_PREFIX).append(activityName) + .append("@").append(activity.hashCode()) .append('_').append(Long.toHexString(uuid.getMostSignificantBits())).append(Long.toHexString(uuid.getLeastSignificantBits())); final String key = keyBuilder.toString(); final DestroyedActivityInfo destroyedActivityInfo From 5afb556b9ebd8178d984919a91bf4f5f51ff851a Mon Sep 17 00:00:00 2001 From: yvesluo Date: Mon, 26 Sep 2022 17:43:03 +0800 Subject: [PATCH 176/263] matrix-res-plugin: fix check expired logic --- .../java/com/tencent/matrix/resource/ResourcePlugin.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ResourcePlugin.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ResourcePlugin.java index 3a4187dd1..c9887fbd5 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ResourcePlugin.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ResourcePlugin.java @@ -28,6 +28,7 @@ import com.tencent.matrix.resource.dumper.HprofFileManager; import com.tencent.matrix.resource.processor.BaseLeakProcessor; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; +import com.tencent.matrix.util.MatrixHandlerThread; import com.tencent.matrix.util.MatrixLog; /** @@ -69,7 +70,6 @@ public void init(Application app, PluginListener listener) { return; } mWatcher = new ActivityRefWatcher(app, this); - HprofFileManager.INSTANCE.checkExpiredFile(); } @Override @@ -80,6 +80,12 @@ public void start() { return; } mWatcher.start(); + MatrixHandlerThread.getDefaultHandler().post(new Runnable() { + @Override + public void run() { + HprofFileManager.INSTANCE.checkExpiredFile(); + } + }); } @Override From e66ac91c726521ba7230a695787ecd444b8f065a Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 27 Sep 2022 14:14:03 +0800 Subject: [PATCH 177/263] matrix-res-plugin: add hprof expired log --- .../java/com/tencent/matrix/resource/dumper/HprofFileManager.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt index d4a811fca..cfa5f6e54 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt @@ -36,6 +36,7 @@ object HprofFileManager { current - it.lastModified() > EXPIRED_TIME_MILLIS }?.forEach { if (it.exists()) { + MatrixLog.i(TAG, "expired: ${it.absolutePath}") it.delete() } } From 3cb80ebeb8662cae6872560bf6ed2266f1d95ef7 Mon Sep 17 00:00:00 2001 From: aurorani Date: Fri, 23 Sep 2022 11:47:18 +0800 Subject: [PATCH 178/263] fix: Do not hardcode resource directory path prefix. --- .../com/tencent/matrix/shrinker/ApkUtil.java | 21 ++++++++++++------- .../task/RemoveUnusedResourcesTaskV2.kt | 21 +++++++++---------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java index b24f9dcfc..c859c3ac2 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java @@ -21,6 +21,7 @@ import com.tencent.matrix.javalib.util.Util; import org.gradle.api.GradleException; +import org.jetbrains.annotations.Nullable; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -61,10 +62,10 @@ public static String parseResourceId(String resId) { return ""; } - public static String entryToResourceName(String entry) { + public static String entryToResourceName(String entry, @Nullable String obfuscatedDirName) { String resourceName = ""; if (!Util.isNullOrNil(entry)) { - String typeName = parseEntryResourceType(entry); + String typeName = parseEntryResourceType(entry, obfuscatedDirName); String resName = entry.substring(entry.lastIndexOf('/') + 1, entry.indexOf('.')); if (!Util.isNullOrNil(typeName) && !Util.isNullOrNil(resName)) { resourceName = "R." + typeName + "." + resName; @@ -73,9 +74,13 @@ public static String entryToResourceName(String entry) { return resourceName; } - public static String parseEntryResourceType(String entry) { - if (!Util.isNullOrNil(entry) && entry.length() > 4) { - String typeName = entry.substring(4, entry.lastIndexOf('/')); + public static String parseEntryResourceType(String entry, @Nullable String obfuscatedDirName) { + int prefixLength = 4; // "res/" + if (obfuscatedDirName != null) { + prefixLength = obfuscatedDirName.length() + 1; + } + if (!Util.isNullOrNil(entry) && entry.length() > prefixLength) { + String typeName = entry.substring(prefixLength, entry.lastIndexOf('/')); if (!Util.isNullOrNil(typeName)) { int index = typeName.indexOf('-'); if (index >= 0) { @@ -87,15 +92,15 @@ public static String parseEntryResourceType(String entry) { return ""; } - public static boolean isSameResourceType(Set entries) { + public static boolean isSameResourceType(Set entries, @Nullable String obfuscatedDirName) { String resType = ""; for (String entry : entries) { if (!Util.isNullOrNil(entry)) { if (Util.isNullOrNil(resType)) { - resType = parseEntryResourceType(entry); + resType = parseEntryResourceType(entry, obfuscatedDirName); continue; } - if (!resType.equals(parseEntryResourceType(entry))) { + if (!resType.equals(parseEntryResourceType(entry, obfuscatedDirName))) { return false; } } else { diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt index ad549a1fd..a3eff27e9 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt @@ -208,10 +208,10 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { val replaceIterator = mapOfDuplicatesReplacements.keys.iterator() while (replaceIterator.hasNext()) { val sourceFile = replaceIterator.next() - val sourceRes = ApkUtil.entryToResourceName(sourceFile) + val sourceRes = ApkUtil.entryToResourceName(sourceFile, obfuscatedResourcesDirectoryName) val sourceId = mapOfResources[sourceRes]!! val targetFile = mapOfDuplicatesReplacements[sourceFile] - val targetRes = ApkUtil.entryToResourceName(targetFile) + val targetRes = ApkUtil.entryToResourceName(targetFile, obfuscatedResourcesDirectoryName) val targetId = mapOfResources[targetRes]!! val success = ArscUtil.replaceFileResource(resTable, sourceId, sourceFile, targetId, targetFile) if (!success) { @@ -243,11 +243,12 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { val compressedEntry = HashSet() for (zipEntry in zipInputFile.entries()) { + if (zipEntry.isDirectory) continue var destFile = unzipDir.canonicalPath + File.separator + zipEntry.name.replace('/', File.separatorChar) - if (zipEntry.name.startsWith("res/")) { - val resourceName = ApkUtil.entryToResourceName(zipEntry.name) + if (zipEntry.name.startsWith(obfuscatedResourcesDirectoryName ?: "res/")) { + val resourceName = ApkUtil.entryToResourceName(zipEntry.name, obfuscatedResourcesDirectoryName) if (!Util.isNullOrNil(resourceName)) { if (mapOfResourcesGonnaRemoved.containsKey(resourceName)) { Log.i(TAG, "remove unused resource %s file %s", resourceName, zipEntry.name) @@ -277,10 +278,8 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { if (zipEntry.method == ZipEntry.DEFLATED) { compressedEntry.add(destFile) } - if (!zipEntry.isDirectory) { - Log.d(TAG, "unzip %s to file %s", zipEntry.name, destFile) - ApkUtil.unzipEntry(zipInputFile, zipEntry, destFile) - } + Log.d(TAG, "unzip %s to file %s", zipEntry.name, destFile) + ApkUtil.unzipEntry(zipInputFile, zipEntry, destFile) } } else { Log.w(TAG, "parse entry %s resource name failed!", zipEntry.name) @@ -290,7 +289,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { if (zipEntry.method == ZipEntry.DEFLATED) { compressedEntry.add(destFile) } - if (!zipEntry.isDirectory && zipEntry.name != ARSC_FILE_NAME) { // has already unzip resources.arsc before + if (zipEntry.name != ARSC_FILE_NAME) { // has already unzip resources.arsc before Log.d(TAG, "unzip %s to file %s", zipEntry.name, destFile) ApkUtil.unzipEntry(zipInputFile, zipEntry, destFile) } @@ -524,13 +523,13 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { Log.w(TAG, " %s is not resource file!", entry) continue } else { - duplicatesNames[entry] = ApkUtil.entryToResourceName(entry) + duplicatesNames[entry] = ApkUtil.entryToResourceName(entry, obfuscatedResourcesDirectoryName) } } } if (duplicatesNames.size > 0) { - if (!ApkUtil.isSameResourceType(duplicatesNames.keys)) { + if (!ApkUtil.isSameResourceType(duplicatesNames.keys, obfuscatedResourcesDirectoryName)) { Log.w(TAG, "the type of duplicated resources %s are not same!", duplicatesEntries) continue } else { From bae20846444236a103d47433458dcabff4542465 Mon Sep 17 00:00:00 2001 From: aurorani Date: Fri, 23 Sep 2022 23:39:08 +0800 Subject: [PATCH 179/263] =?UTF-8?q?fix:=20OK,=20now=20RUR=20should=20compa?= =?UTF-8?q?tible=20with=20resguard,=20right=3F=20=F0=9F=A4=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apk/model/task/UnusedResourcesTask.java | 6 +- .../matrix/apk/model/task/UnzipTask.java | 56 +--------------- .../apk/model/task/util/ResguardUtil.java | 67 +++++++++++++++++++ .../com/tencent/matrix/shrinker/ApkUtil.java | 33 ++++++--- .../task/RemoveUnusedResourcesTaskV2.kt | 28 ++++---- .../matrix/resguard/ResguardMapping.kt | 59 ++++++++++++++++ 6 files changed, 171 insertions(+), 78 deletions(-) create mode 100644 matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/ResguardUtil.java create mode 100644 matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/resguard/ResguardMapping.kt diff --git a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java index f3acf63e6..0f5c4443f 100644 --- a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java +++ b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java @@ -29,6 +29,7 @@ import com.tencent.matrix.apk.model.result.TaskResultFactory; import com.tencent.matrix.apk.model.task.util.ApkResourceDecoder; import com.tencent.matrix.apk.model.task.util.ApkUtil; +import com.tencent.matrix.apk.model.task.util.ResguardUtil; import com.tencent.matrix.javalib.util.FileUtil; import com.tencent.matrix.javalib.util.Log; import com.tencent.matrix.javalib.util.Util; @@ -69,6 +70,7 @@ public class UnusedResourcesTask extends ApkTask { private File resMappingTxt; private final List dexFileNameList; private final Map rclassProguardMap; + private final Map resguardMap; private final Map resourceDefMap; private final Map> styleableMap; private final Set resourceRefSet; @@ -83,6 +85,7 @@ public UnusedResourcesTask(JobConfig config, Map params) { dexFileNameList = new ArrayList<>(); ignoreSet = new HashSet<>(); rclassProguardMap = new HashMap<>(); + resguardMap = new HashMap<>(); resourceDefMap = new HashMap<>(); styleableMap = new HashMap<>(); resourceRefSet = new HashSet<>(); @@ -390,8 +393,6 @@ private void decodeResources() throws IOException, InterruptedException, Androli ApkResourceDecoder.decodeResourcesRef(manifestFile, arscFile, resDir, fileResMap, valuesReferences); - Map resguardMap = config.getResguardMap(); - for (String resource : fileResMap.keySet()) { Set result = new HashSet<>(); for (String resName : fileResMap.get(resource)) { @@ -461,6 +462,7 @@ public TaskResult call() throws TaskExecuteException { long startTime = System.currentTimeMillis(); readMappingTxtFile(); readResourceTxtFile(); + ResguardUtil.readResMappingTxtFile(resMappingTxt, null, resguardMap); unusedResSet.addAll(resourceDefMap.values()); Log.i(TAG, "find resource declarations %d items.", unusedResSet.size()); decodeCode(); diff --git a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnzipTask.java b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnzipTask.java index 409f36dcd..f7156e793 100644 --- a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnzipTask.java +++ b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnzipTask.java @@ -25,6 +25,7 @@ import com.tencent.matrix.apk.model.result.TaskResult; import com.tencent.matrix.apk.model.result.TaskResultFactory; import com.android.utils.Pair; +import com.tencent.matrix.apk.model.task.util.ResguardUtil; import com.tencent.matrix.javalib.util.FileUtil; import com.tencent.matrix.javalib.util.Log; import com.tencent.matrix.javalib.util.Util; @@ -134,59 +135,6 @@ private void readMappingTxtFile() throws IOException { } } - private String parseResourceNameFromResguard(String resName) { - if (!Util.isNullOrNil(resName)) { - int index = resName.indexOf('R'); - if (index >= 0) { - return resName.substring(index); - } - } - return ""; - } - - - private void readResMappingTxtFile() throws IOException { - if (resMappingTxt != null) { - BufferedReader bufferedReader = new BufferedReader(new FileReader(resMappingTxt)); - try { - String line = bufferedReader.readLine(); - boolean readResStart = false; - boolean readPathStart = false; - while (line != null) { - if (line.trim().equals("res path mapping:")) { - readPathStart = true; - } else if (line.trim().equals("res id mapping:")) { - readResStart = true; - readPathStart = false; - } else if (readPathStart) { - String[] columns = line.split("->"); - if (columns.length == 2) { - String before = columns[0].trim(); - String after = columns[1].trim(); - if (!Util.isNullOrNil(before) && !Util.isNullOrNil(after)) { - Log.d(TAG, "%s->%s", before, after); - resDirMap.put(after, before); - } - } - } else if (readResStart) { - String[] columns = line.split("->"); - if (columns.length == 2) { - String before = parseResourceNameFromResguard(columns[0].trim()); - String after = parseResourceNameFromResguard(columns[1].trim()); - if (!Util.isNullOrNil(before) && !Util.isNullOrNil(after)) { - Log.d(TAG, "%s->%s", before, after); - resguardMap.put(after, before); - } - } - } - line = bufferedReader.readLine(); - } - } finally { - bufferedReader.close(); - } - } - } - private String parseResourceNameFromPath(String dir, String filename) { if (Util.isNullOrNil(dir) || Util.isNullOrNil(filename)) { return ""; @@ -310,7 +258,7 @@ public TaskResult call() throws TaskExecuteException { readMappingTxtFile(); config.setProguardClassMap(proguardClassMap); - readResMappingTxtFile(); + ResguardUtil.readResMappingTxtFile(resMappingTxt, resDirMap, resguardMap); config.setResguardMap(resguardMap); Enumeration entries = zipFile.entries(); diff --git a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/ResguardUtil.java b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/ResguardUtil.java new file mode 100644 index 000000000..c13b89c85 --- /dev/null +++ b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/ResguardUtil.java @@ -0,0 +1,67 @@ +package com.tencent.matrix.apk.model.task.util; + +import com.tencent.matrix.javalib.util.Log; +import com.tencent.matrix.javalib.util.Util; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Map; + +public class ResguardUtil { + + private static final String TAG = "Matrix.ResguardUtil"; + + public static void readResMappingTxtFile(File resMappingTxt, Map resDirMap, Map resguardMap) throws IOException { + if (resMappingTxt != null) { + BufferedReader bufferedReader = new BufferedReader(new FileReader(resMappingTxt)); + try { + String line = bufferedReader.readLine(); + boolean readResStart = false; + boolean readPathStart = false; + while (line != null) { + if (line.trim().equals("res path mapping:")) { + readPathStart = true; + } else if (line.trim().equals("res id mapping:")) { + readResStart = true; + readPathStart = false; + } else if (readPathStart && resDirMap != null) { + String[] columns = line.split("->"); + if (columns.length == 2) { + String before = columns[0].trim(); + String after = columns[1].trim(); + if (!Util.isNullOrNil(before) && !Util.isNullOrNil(after)) { + Log.d(TAG, "%s->%s", before, after); + resDirMap.put(after, before); + } + } + } else if (readResStart && resguardMap != null) { + String[] columns = line.split("->"); + if (columns.length == 2) { + String before = parseResourceNameFromResguard(columns[0].trim()); + String after = parseResourceNameFromResguard(columns[1].trim()); + if (!Util.isNullOrNil(before) && !Util.isNullOrNil(after)) { + Log.d(TAG, "%s->%s", before, after); + resguardMap.put(after, before); + } + } + } + line = bufferedReader.readLine(); + } + } finally { + bufferedReader.close(); + } + } + } + + private static String parseResourceNameFromResguard(String resName) { + if (!Util.isNullOrNil(resName)) { + int index = resName.indexOf('R'); + if (index >= 0) { + return resName.substring(index); + } + } + return ""; + } +} diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java index c859c3ac2..ce5bf720c 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java @@ -20,6 +20,7 @@ import com.tencent.matrix.javalib.util.Pair; import com.tencent.matrix.javalib.util.Util; +import com.tencent.matrix.resguard.ResguardMapping; import org.gradle.api.GradleException; import org.jetbrains.annotations.Nullable; @@ -62,11 +63,25 @@ public static String parseResourceId(String resId) { return ""; } - public static String entryToResourceName(String entry, @Nullable String obfuscatedDirName) { + public static String entryToResourceName(String entry, @Nullable ResguardMapping resguardMapping) { String resourceName = ""; if (!Util.isNullOrNil(entry)) { - String typeName = parseEntryResourceType(entry, obfuscatedDirName); + String typeName; + if (resguardMapping != null) { + int lastIndex = entry.lastIndexOf('/'); + if (lastIndex == -1) return ""; + String obfuscatedPath = entry.substring(0, lastIndex); + String originPath = resguardMapping.originPath(obfuscatedPath); + typeName = parseEntryResourceType(originPath + "/"); + } else { + typeName = parseEntryResourceType(entry); + } + String resName = entry.substring(entry.lastIndexOf('/') + 1, entry.indexOf('.')); + if (resguardMapping != null) { + resName = resguardMapping.originID(typeName, resName); + } + if (!Util.isNullOrNil(typeName) && !Util.isNullOrNil(resName)) { resourceName = "R." + typeName + "." + resName; } @@ -74,12 +89,10 @@ public static String entryToResourceName(String entry, @Nullable String obfuscat return resourceName; } - public static String parseEntryResourceType(String entry, @Nullable String obfuscatedDirName) { - int prefixLength = 4; // "res/" - if (obfuscatedDirName != null) { - prefixLength = obfuscatedDirName.length() + 1; - } - if (!Util.isNullOrNil(entry) && entry.length() > prefixLength) { + public static String parseEntryResourceType(String entry) { + int prefixLength = entry.indexOf('/'); + if (prefixLength == -1) return ""; + if (!Util.isNullOrNil(entry)) { String typeName = entry.substring(prefixLength, entry.lastIndexOf('/')); if (!Util.isNullOrNil(typeName)) { int index = typeName.indexOf('-'); @@ -97,10 +110,10 @@ public static boolean isSameResourceType(Set entries, @Nullable String o for (String entry : entries) { if (!Util.isNullOrNil(entry)) { if (Util.isNullOrNil(resType)) { - resType = parseEntryResourceType(entry, obfuscatedDirName); + resType = parseEntryResourceType(entry); continue; } - if (!resType.equals(parseEntryResourceType(entry, obfuscatedDirName))) { + if (!resType.equals(parseEntryResourceType(entry))) { return false; } } else { diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt index a3eff27e9..ae7703944 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt @@ -27,6 +27,7 @@ import com.tencent.matrix.javalib.util.Util import com.tencent.matrix.plugin.compat.AgpCompat import com.tencent.matrix.plugin.compat.CreationConfig import com.tencent.matrix.plugin.extension.MatrixRemoveUnusedResExtension +import com.tencent.matrix.resguard.ResguardMapping import com.tencent.matrix.shrinker.ApkUtil import com.tencent.matrix.shrinker.ProguardStringBuilder import com.tencent.mm.arscutil.ArscUtil @@ -71,7 +72,8 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { private var obfuscatedResourcesDirectoryName: String? = null private var overrideInputApkFiles: List = emptyList() - private var resguardMapping: File? = null + private var resguardMappingFile: File? = null + private var resguardMapping: ResguardMapping? = null private lateinit var pathOfApkChecker: String private lateinit var pathOfApkSigner: String @@ -85,7 +87,8 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { } fun withResguardMapping(path: String) { - resguardMapping = File(path) + resguardMappingFile = File(path) + resguardMapping = ResguardMapping(resguardMappingFile!!) } @TaskAction @@ -208,10 +211,10 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { val replaceIterator = mapOfDuplicatesReplacements.keys.iterator() while (replaceIterator.hasNext()) { val sourceFile = replaceIterator.next() - val sourceRes = ApkUtil.entryToResourceName(sourceFile, obfuscatedResourcesDirectoryName) + val sourceRes = ApkUtil.entryToResourceName(sourceFile, resguardMapping) val sourceId = mapOfResources[sourceRes]!! val targetFile = mapOfDuplicatesReplacements[sourceFile] - val targetRes = ApkUtil.entryToResourceName(targetFile, obfuscatedResourcesDirectoryName) + val targetRes = ApkUtil.entryToResourceName(targetFile, resguardMapping) val targetId = mapOfResources[targetRes]!! val success = ArscUtil.replaceFileResource(resTable, sourceId, sourceFile, targetId, targetFile) if (!success) { @@ -248,7 +251,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { var destFile = unzipDir.canonicalPath + File.separator + zipEntry.name.replace('/', File.separatorChar) if (zipEntry.name.startsWith(obfuscatedResourcesDirectoryName ?: "res/")) { - val resourceName = ApkUtil.entryToResourceName(zipEntry.name, obfuscatedResourcesDirectoryName) + val resourceName = ApkUtil.entryToResourceName(zipEntry.name, resguardMapping) if (!Util.isNullOrNil(resourceName)) { if (mapOfResourcesGonnaRemoved.containsKey(resourceName)) { Log.i(TAG, "remove unused resource %s file %s", resourceName, zipEntry.name) @@ -371,7 +374,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { pathOfOriginalApk: String, pathOfMapping: String, pathOfRTxt: String, - pathOfResguardMapping: String?, + resguardMappingFile: File?, resultOfUnused: MutableSet, resultOfDuplicates: MutableMap> ) { @@ -394,15 +397,16 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { parameters.add(pathOfMapping) } + if (resguardMappingFile?.exists() == true) { + parameters.add("--resMappingTxt") + parameters.add(resguardMappingFile.absolutePath) + } + parameters.add("--format") parameters.add("json") parameters.add("-unusedResources") parameters.add("--rTxt") parameters.add(pathOfRTxt) - if (pathOfResguardMapping != null) { - parameters.add("--resMappingTxt") - parameters.add(pathOfResguardMapping) - } val parametersOfIgnoredResources = StringBuilder() if (configOfIgnoredResources.isNotEmpty()) { @@ -523,7 +527,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { Log.w(TAG, " %s is not resource file!", entry) continue } else { - duplicatesNames[entry] = ApkUtil.entryToResourceName(entry, obfuscatedResourcesDirectoryName) + duplicatesNames[entry] = ApkUtil.entryToResourceName(entry, resguardMapping) } } } @@ -690,7 +694,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { pathOfOriginalApk = originalApkPath, pathOfMapping = mappingTxtFile.absolutePath, pathOfRTxt = rTxtFile.absolutePath, - pathOfResguardMapping = resguardMapping?.absolutePath, + resguardMappingFile = resguardMappingFile, // result resultOfUnused = setOfUnusedResources, diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/resguard/ResguardMapping.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/resguard/ResguardMapping.kt new file mode 100644 index 000000000..b320bb3df --- /dev/null +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/resguard/ResguardMapping.kt @@ -0,0 +1,59 @@ +package com.tencent.matrix.resguard + +import java.io.File + +internal class ResguardMapping(mappingFile: File) { + + private enum class ParseState { + None, Path, ID; + } + + private val pathMapping: Map + + private val idMapping: Map> + + companion object { + private val parsePathRegex = "^\\s+(.*) -> (.*)\$".toRegex() + private val parseIDRegex = "^\\s+(\\S+)?R\\.(\\S+?)\\.(\\S+) -> (\\S+)?R\\.(\\S+?)\\.(\\S+)\$".toRegex() + } + + init { + var state = ParseState.None + val pathMappingRaw = mutableMapOf() + val idMappingRaw = mutableMapOf>() + mappingFile.forEachLine { line -> + when { + line == "res path mapping:" -> { + state = ParseState.Path + } + line == "res id mapping:" -> { + state = ParseState.ID + } + line.isEmpty() -> { + state = ParseState.None + } + else -> { + if (state == ParseState.Path) { + parsePathRegex.matchEntire(line)?.groupValues?.let { + pathMappingRaw[it[2]] = it[1] + } + } else if (state == ParseState.ID) { + parseIDRegex.matchEntire(line)?.groupValues?.let { + idMappingRaw.getOrPut(it[2]) { mutableMapOf() }[it[6]] = it[3] + } + } + } + } + } + pathMapping = pathMappingRaw + idMapping = idMappingRaw + } + + fun originPath(path: String): String { + return pathMapping[path] ?: path + } + + fun originID(type: String, name: String): String { + return idMapping[type]?.get(name) ?: name + } +} \ No newline at end of file From 776676b23ab5bdbf62264a464dc43d7667ae3a36 Mon Sep 17 00:00:00 2001 From: aurorani Date: Mon, 26 Sep 2022 21:35:38 +0800 Subject: [PATCH 180/263] fix: WHY RESOURCE ID FORMAT FROM AAPT AND ARSC IS DIFFERENT??? --- .../apk/model/task/util/ResguardUtil.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/ResguardUtil.java b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/ResguardUtil.java index c13b89c85..a4ce95b5d 100644 --- a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/ResguardUtil.java +++ b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/ResguardUtil.java @@ -8,6 +8,8 @@ import java.io.FileReader; import java.io.IOException; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ResguardUtil { @@ -55,13 +57,25 @@ public static void readResMappingTxtFile(File resMappingTxt, Map } } + private static final Pattern RESOURCE_ID_PATTERN = Pattern.compile("^(\\S+\\.)*R\\.(\\S+?)\\.(\\S+)"); + private static String parseResourceNameFromResguard(String resName) { - if (!Util.isNullOrNil(resName)) { - int index = resName.indexOf('R'); - if (index >= 0) { - return resName.substring(index); - } + if (Util.isNullOrNil(resName)) return ""; + final Matcher matcher = RESOURCE_ID_PATTERN.matcher(resName); + if (matcher.find()) { + final StringBuilder builder = new StringBuilder(); + builder.append("R."); + builder.append(matcher.group(2)); + /* + The resource ID from resguard is read from ARSC file, which format is package-like + (for example: R.style.Theme.AppCompat.Light.DarkActionBar). We should convert it as the regular format + in code (for example: R.style.Theme_AppCompat_Light_DarkActionBar). + */ + builder.append('.'); + builder.append(matcher.group(3).replace('.', '_')); + return builder.toString(); + } else { + return ""; } - return ""; } } From 08a402a37f74160050fe5515724c01653b678e48 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Wed, 19 Oct 2022 18:17:39 +0800 Subject: [PATCH 181/263] Update healthstats with acc collector support --- .../batterycanary/stats/HealthStatsTest.java | 63 ++++- .../monitor/feature/CompositeMonitors.java | 39 ++- .../monitor/feature/MonitorFeature.java | 18 ++ .../stats/HealthStatsFeature.java | 260 ++++++++++++++++-- 4 files changed, 348 insertions(+), 32 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java index 4522abe0c..f03c1b7c3 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/stats/HealthStatsTest.java @@ -20,22 +20,18 @@ import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorManager; -import android.os.Debug; import android.os.health.HealthStats; import android.os.health.SystemHealthManager; import android.os.health.TimerStat; import android.os.health.UidHealthStats; import com.tencent.matrix.Matrix; -import com.tencent.matrix.batterycanary.BatteryCanary; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; import com.tencent.matrix.batterycanary.monitor.feature.CpuStatFeature; -import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; import com.tencent.matrix.batterycanary.stats.HealthStatsFeature.HealthStatsSnapshot; import com.tencent.matrix.batterycanary.utils.PowerProfile; -import com.tencent.matrix.util.MatrixLog; import org.junit.After; import org.junit.Assert; @@ -44,7 +40,6 @@ import org.junit.runner.RunWith; import java.io.IOException; -import java.io.PipedWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; @@ -56,11 +51,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; -import static com.tencent.matrix.batterycanary.stats.HealthStatsHelper.getMeasure; -import static com.tencent.matrix.batterycanary.stats.HealthStatsHelper.getTimerTime; -import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.JIFFY_MILLIS; -import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_HOR; - @RunWith(AndroidJUnit4.class) public class HealthStatsTest { @@ -708,6 +698,59 @@ public void testGetCurrSnapshot() { Assert.assertEquals(delta.dlt.getTotalPower(), end.getTotalPower() - bgn.getTotalPower(), 0.001d); } + @Test + public void testHealthStatsAccCollecting() throws InterruptedException { + HealthStatsFeature feature = new HealthStatsFeature(); + feature.configure(mockMonitor()); + feature.onTurnOn(); + + Assert.assertNotNull(feature.currHealthStats()); + + HealthStatsSnapshot bgn = feature.currHealthStatsSnapshot(); + Assert.assertNotNull(bgn); + + Assert.assertNull(bgn.accCollector); + HealthStatsSnapshot.AccCollector accCollector = bgn.startAccCollecting(); + Assert.assertNotNull(accCollector); + Assert.assertSame(bgn.accCollector, accCollector); + Assert.assertSame(bgn, accCollector.last); + + int accCount = 2; + long intervalMs = 2000L; + long accDuringMs = 0L; + for (int i = 0; i < accCount; i++) { + Thread.sleep(intervalMs); + HealthStatsSnapshot curr = feature.currHealthStatsSnapshot(); + Delta delta = bgn.accCollect(curr); + Assert.assertNotNull(delta); + Assert.assertEquals(i + 1, accCollector.count); + Assert.assertEquals(accDuringMs += delta.during, accCollector.duringMs); + } + + Thread.sleep(intervalMs); + HealthStatsSnapshot end = feature.currHealthStatsSnapshot(); + Assert.assertNotNull(end); + + Assert.assertEquals(accCount, accCollector.count); + Delta deltaByAcc = end.diffByAccCollector(bgn); + Assert.assertNotNull(deltaByAcc); + Assert.assertTrue(deltaByAcc instanceof Delta.SimpleDelta); + Assert.assertEquals(accCount + 1, accCollector.count); + + Delta delta = end.diff(bgn); + Assert.assertNotNull(delta); + Assert.assertFalse(delta instanceof Delta.SimpleDelta); + + Assert.assertSame(delta.bgn, deltaByAcc.bgn); + Assert.assertSame(delta.end, deltaByAcc.end); + Assert.assertEquals(delta.during, deltaByAcc.during); + Assert.assertEquals(delta.dlt.isDelta, deltaByAcc.dlt.isDelta); + Assert.assertEquals(delta.dlt.getTotalPower(), deltaByAcc.dlt.getTotalPower(), 0.0001d); + + Assert.assertSame(delta.end, accCollector.last); + Assert.assertEquals(delta.during, accCollector.duringMs); + } + @Test public void testCalcAvgPowerPerPacket() throws IOException { PowerProfile powerProfile = PowerProfile.init(mContext); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java index 2b13dcb80..6b31f12d6 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/CompositeMonitors.java @@ -405,6 +405,13 @@ protected void configureBgnSnapshots() { Snapshot currSnapshot = statCurrSnapshot(item); if (currSnapshot != null) { mBgnSnapshots.put(item, currSnapshot); + + // Start acc collecting for HealthStatsSnapshot + if (currSnapshot instanceof HealthStatsSnapshot) { + if (mSampleRegs.containsKey(HealthStatsSnapshot.class)) { + ((HealthStatsSnapshot) currSnapshot).startAccCollecting(); + } + } } } } @@ -417,7 +424,13 @@ protected void configureEndDeltas() { Class> snapshotClass = item.getKey(); Snapshot currSnapshot = statCurrSnapshot(snapshotClass); if (currSnapshot != null && currSnapshot.getClass() == lastSnapshot.getClass()) { - putDelta(snapshotClass, currSnapshot.diff(lastSnapshot)); + Delta delta; + if (lastSnapshot instanceof HealthStatsSnapshot && ((HealthStatsSnapshot) lastSnapshot).accCollector != null) { + delta = ((HealthStatsSnapshot) currSnapshot).diffByAccCollector((HealthStatsSnapshot) lastSnapshot); + } else { + delta = currSnapshot.diff(lastSnapshot); + } + putDelta(snapshotClass, delta); } } } @@ -797,6 +810,10 @@ public Number apply(Snapshot.Sampler sampler) { sampler = new MonitorFeature.Snapshot.Sampler("batt-curr", mMonitor.getHandler(), new Function() { @Override public Number apply(Snapshot.Sampler sampler) { + if (BatteryCanaryUtil.isDeviceCharging(mMonitor.getContext())) { + // battery currency is meaningless when charging + return Snapshot.Sampler.INVALID; + } long value = BatteryCanaryUtil.getBatteryCurrencyImmediately(mMonitor.getContext()); MatrixLog.i(TAG, "onSampling " + sampler.mCount + " " + sampler.mTag + ", val = " + value); if (value == -1L) { @@ -809,6 +826,24 @@ public Number apply(Snapshot.Sampler sampler) { } return sampler; } + if (snapshotClass == HealthStatsSnapshot.class) { + final HealthStatsFeature feature = getFeature(HealthStatsFeature.class); + if (feature != null && mMonitor != null) { + sampler = new MonitorFeature.Snapshot.Sampler("health-stats", mMonitor.getHandler(), new Function() { + @Override + public Number apply(Snapshot.Sampler sampler) { + Snapshot snapshot = mBgnSnapshots.get(HealthStatsSnapshot.class); + if (snapshot instanceof HealthStatsSnapshot) { + MatrixLog.i(TAG, "onAcc " + sampler.mCount + " " + sampler.mTag); + ((HealthStatsSnapshot) snapshot).accCollect(feature.currHealthStatsSnapshot()); + } + return Snapshot.Sampler.INVALID; + } + }); + mSamplers.put(snapshotClass, sampler); + } + return sampler; + } return null; } @@ -1076,7 +1111,7 @@ protected void tuningPowers(final HealthStatsFeature.HealthStatsSnapshot snapsho if (monitor == null) { return; } - + snapshot.extras = new HashMap<>(); final boolean tunning = monitor.getConfig().isTuningPowers; final Tuner tuner = new Tuner(); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java index ba2a28484..176d4b8ab 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorFeature.java @@ -68,11 +68,29 @@ public Delta(RECORD bgn, RECORD end) { dlt.isDelta = true; } + public Delta(RECORD bgn, RECORD end, RECORD dlt) { + this.bgn = bgn; + this.end = end; + this.during = end.time - bgn.time; + this.dlt = dlt; + dlt.isDelta = true; + } + public boolean isValid() { return bgn.isValid() && end.isValid(); } protected abstract RECORD computeDelta(); + + public static class SimpleDelta extends Delta { + public SimpleDelta(RECORD bgn, RECORD end, RECORD dlt) { + super(bgn, end, dlt); + } + @Override + protected RECORD computeDelta() { + throw new RuntimeException("stub!"); + } + } } public abstract static class Entry { diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java index 59a1d31b2..089f879a9 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/HealthStatsFeature.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -257,9 +256,13 @@ public HealthStatsSnapshot currHealthStatsSnapshot() { } public static class HealthStatsSnapshot extends Snapshot { + @Nullable + public AccCollector accCollector; + @VisibleForTesting @Nullable public HealthStats healthStats; + // For test & tunings values public Map extras = Collections.emptyMap(); // Estimated Powers @@ -363,14 +366,33 @@ public double getTotalPower() { + idlePower.get(); } - @Override - public Delta diff(HealthStatsSnapshot bgn) { + public AccCollector startAccCollecting() { + accCollector = new AccCollector(this); + return accCollector; + } + + @Nullable + public Delta accCollect(HealthStatsSnapshot curr) { + if (accCollector == null) { + throw new IllegalStateException("Call start collect first!"); + } + return accCollector.collect(curr); + } + + public Delta diffByAccCollector(HealthStatsSnapshot bgn) { + if (bgn.accCollector == null) { + throw new IllegalStateException("Call start collect first!"); + } + bgn.accCollect(this); + HealthStatsSnapshot delta = bgn.accCollector.accDelta; + return new Delta.SimpleDelta<>(bgn, this, delta); + } + + Delta diffInternal(HealthStatsSnapshot bgn) { return new Delta(bgn, this) { @Override protected HealthStatsSnapshot computeDelta() { HealthStatsSnapshot delta = new HealthStatsSnapshot(); - // For test & tunings - delta.extras = new LinkedHashMap<>(); // UID delta.cpuPower = Differ.DigitDiffer.globalDiff(bgn.cpuPower, end.cpuPower); @@ -458,7 +480,7 @@ protected HealthStatsSnapshot computeDelta() { } map.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); } - delta.procStatsCpuUsrTimeMs = decrease(map); + delta.procStatsCpuUsrTimeMs = map; } { Map> map = new HashMap<>(); @@ -472,7 +494,7 @@ protected HealthStatsSnapshot computeDelta() { } map.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); } - delta.procStatsCpuSysTimeMs = decrease(map); + delta.procStatsCpuSysTimeMs = map; } { Map> map = new HashMap<>(); @@ -486,24 +508,34 @@ protected HealthStatsSnapshot computeDelta() { } map.put(key, Differ.DigitDiffer.globalDiff(DigitEntry.of(bgnValue), endEntry)); } - delta.procStatsCpuFgTimeMs = decrease(map); + delta.procStatsCpuFgTimeMs = map; } return delta; } + }; + } - private Map> decrease(Map> input) { - return BatteryCanaryUtil.sortMapByValue(input, new Comparator>>() { - @Override - public int compare(Map.Entry> o1, Map.Entry> o2) { - long sumLeft = o1.getValue().get(), sumRight = o2.getValue().get(); - long minus = sumLeft - sumRight; - if (minus == 0) return 0; - if (minus > 0) return -1; - return 1; - } - }); + @Override + public Delta diff(HealthStatsSnapshot bgn) { + Delta delta = diffInternal(bgn); + // Sort + delta.dlt.procStatsCpuUsrTimeMs = decrease(procStatsCpuUsrTimeMs); + delta.dlt.procStatsCpuSysTimeMs = decrease(procStatsCpuSysTimeMs); + delta.dlt.procStatsCpuFgTimeMs = decrease(procStatsCpuFgTimeMs); + return delta; + } + + private Map> decrease(Map> input) { + return BatteryCanaryUtil.sortMapByValue(input, new Comparator>>() { + @Override + public int compare(Map.Entry> o1, Map.Entry> o2) { + long sumLeft = o1.getValue().get(), sumRight = o2.getValue().get(); + long minus = sumLeft - sumRight; + if (minus == 0) return 0; + if (minus > 0) return -1; + return 1; } - }; + }); } public static double getPower(@NonNull Map extra, String key) { @@ -513,5 +545,193 @@ public static double getPower(@NonNull Map extra, String key) { } return 0; } + + + public static class AccCollector { + public int count; + public long beginMs; + public long duringMs; + public HealthStatsSnapshot last; + public HealthStatsSnapshot accDelta; + + public AccCollector(HealthStatsSnapshot bgn) { + beginMs = bgn.time; + last = bgn; + accDelta = new HealthStatsSnapshot(); + accDelta.procStatsCpuUsrTimeMs = new HashMap<>(); + accDelta.procStatsCpuSysTimeMs = new HashMap<>(); + accDelta.procStatsCpuFgTimeMs = new HashMap<>(); + } + + @Nullable + public Delta collect(HealthStatsSnapshot curr) { + Delta delta = null; + if (isHealthStatsNotReset(last, curr)) { + delta = curr.diffInternal(last); + + accDelta.cpuPower = DigitEntry.of(accDelta.cpuPower.get() + delta.dlt.cpuPower.get()); + accDelta.wakelocksPower = DigitEntry.of(accDelta.wakelocksPower.get() + delta.dlt.wakelocksPower.get()); + accDelta.mobilePower = DigitEntry.of(accDelta.mobilePower.get() + delta.dlt.mobilePower.get()); + accDelta.wifiPower = DigitEntry.of(accDelta.wifiPower.get() + delta.dlt.wifiPower.get()); + accDelta.blueToothPower = DigitEntry.of(accDelta.blueToothPower.get() + delta.dlt.blueToothPower.get()); + accDelta.gpsPower = DigitEntry.of(accDelta.gpsPower.get() + delta.dlt.gpsPower.get()); + accDelta.sensorsPower = DigitEntry.of(accDelta.sensorsPower.get() + delta.dlt.sensorsPower.get()); + accDelta.cameraPower = DigitEntry.of(accDelta.cameraPower.get() + delta.dlt.cameraPower.get()); + accDelta.flashLightPower = DigitEntry.of(accDelta.flashLightPower.get() + delta.dlt.flashLightPower.get()); + accDelta.audioPower = DigitEntry.of(accDelta.audioPower.get() + delta.dlt.audioPower.get()); + accDelta.videoPower = DigitEntry.of(accDelta.videoPower.get() + delta.dlt.videoPower.get()); + accDelta.screenPower = DigitEntry.of(accDelta.screenPower.get() + delta.dlt.screenPower.get()); + accDelta.systemServicePower = DigitEntry.of(accDelta.systemServicePower.get() + delta.dlt.systemServicePower.get()); + accDelta.idlePower = DigitEntry.of(accDelta.idlePower.get() + delta.dlt.idlePower.get()); + + accDelta.cpuPowerMams = DigitEntry.of(accDelta.cpuPowerMams.get() + delta.dlt.cpuPowerMams.get()); + accDelta.cpuUsrTimeMs = DigitEntry.of(accDelta.cpuUsrTimeMs.get() + delta.dlt.cpuUsrTimeMs.get()); + accDelta.cpuSysTimeMs = DigitEntry.of(accDelta.cpuSysTimeMs.get() + delta.dlt.cpuSysTimeMs.get()); + accDelta.realTimeMs = DigitEntry.of(accDelta.realTimeMs.get() + delta.dlt.realTimeMs.get()); + accDelta.upTimeMs = DigitEntry.of(accDelta.upTimeMs.get() + delta.dlt.upTimeMs.get()); + + accDelta.mobilePowerMams = DigitEntry.of(accDelta.mobilePowerMams.get() + delta.dlt.mobilePowerMams.get()); + accDelta.mobileRadioActiveMs = DigitEntry.of(accDelta.mobileRadioActiveMs.get() + delta.dlt.mobileRadioActiveMs.get()); + accDelta.mobileIdleMs = DigitEntry.of(accDelta.mobileIdleMs.get() + delta.dlt.mobileIdleMs.get()); + accDelta.mobileRxMs = DigitEntry.of(accDelta.mobileRxMs.get() + delta.dlt.mobileRxMs.get()); + accDelta.mobileTxMs = DigitEntry.of(accDelta.mobileTxMs.get() + delta.dlt.mobileTxMs.get()); + accDelta.mobileRxBytes = DigitEntry.of(accDelta.mobileRxBytes.get() + delta.dlt.mobileRxBytes.get()); + accDelta.mobileTxBytes = DigitEntry.of(accDelta.mobileTxBytes.get() + delta.dlt.mobileTxBytes.get()); + accDelta.mobileRxPackets = DigitEntry.of(accDelta.mobileRxPackets.get() + delta.dlt.mobileRxPackets.get()); + accDelta.mobileTxPackets = DigitEntry.of(accDelta.mobileTxPackets.get() + delta.dlt.mobileTxPackets.get()); + + + accDelta.wifiPowerMams = DigitEntry.of(accDelta.wifiPowerMams.get() + delta.dlt.wifiPowerMams.get()); + accDelta.wifiIdleMs = DigitEntry.of(accDelta.wifiIdleMs.get() + delta.dlt.wifiIdleMs.get()); + accDelta.wifiRxMs = DigitEntry.of(accDelta.wifiRxMs.get() + delta.dlt.wifiRxMs.get()); + accDelta.wifiTxMs = DigitEntry.of(accDelta.wifiTxMs.get() + delta.dlt.wifiTxMs.get()); + accDelta.wifiRunningMs = DigitEntry.of(accDelta.wifiRunningMs.get() + delta.dlt.wifiRunningMs.get()); + accDelta.wifiLockMs = DigitEntry.of(accDelta.wifiLockMs.get() + delta.dlt.wifiLockMs.get()); + accDelta.wifiScanMs = DigitEntry.of(accDelta.wifiScanMs.get() + delta.dlt.wifiScanMs.get()); + accDelta.wifiMulticastMs = DigitEntry.of(accDelta.wifiMulticastMs.get() + delta.dlt.wifiMulticastMs.get()); + accDelta.wifiRxBytes = DigitEntry.of(accDelta.wifiRxBytes.get() + delta.dlt.wifiRxBytes.get()); + accDelta.wifiTxBytes = DigitEntry.of(accDelta.wifiTxBytes.get() + delta.dlt.wifiTxBytes.get()); + accDelta.wifiRxPackets = DigitEntry.of(accDelta.wifiRxPackets.get() + delta.dlt.wifiRxPackets.get()); + accDelta.wifiTxPackets = DigitEntry.of(accDelta.wifiTxPackets.get() + delta.dlt.wifiTxPackets.get()); + + accDelta.blueToothPowerMams = DigitEntry.of(accDelta.blueToothPowerMams.get() + delta.dlt.blueToothPowerMams.get()); + accDelta.blueToothIdleMs = DigitEntry.of(accDelta.blueToothIdleMs.get() + delta.dlt.blueToothIdleMs.get()); + accDelta.blueToothRxMs = DigitEntry.of(accDelta.blueToothRxMs.get() + delta.dlt.blueToothRxMs.get()); + accDelta.blueToothTxMs = DigitEntry.of(accDelta.blueToothTxMs.get() + delta.dlt.blueToothTxMs.get()); + + accDelta.wakelocksPartialMs = DigitEntry.of(accDelta.wakelocksPartialMs.get() + delta.dlt.wakelocksPartialMs.get()); + accDelta.wakelocksFullMs = DigitEntry.of(accDelta.wakelocksFullMs.get() + delta.dlt.wakelocksFullMs.get()); + accDelta.wakelocksWindowMs = DigitEntry.of(accDelta.wakelocksWindowMs.get() + delta.dlt.wakelocksWindowMs.get()); + accDelta.wakelocksDrawMs = DigitEntry.of(accDelta.wakelocksDrawMs.get() + delta.dlt.wakelocksDrawMs.get()); + accDelta.wakelocksPidSum = DigitEntry.of(accDelta.wakelocksPidSum.get() + delta.dlt.wakelocksPidSum.get()); + accDelta.gpsMs = DigitEntry.of(accDelta.gpsMs.get() + delta.dlt.gpsMs.get()); + accDelta.sensorsPowerMams = DigitEntry.of(accDelta.sensorsPowerMams.get() + delta.dlt.sensorsPowerMams.get()); + accDelta.cameraMs = DigitEntry.of(accDelta.cameraMs.get() + delta.dlt.cameraMs.get()); + accDelta.flashLightMs = DigitEntry.of(accDelta.flashLightMs.get() + delta.dlt.flashLightMs.get()); + accDelta.audioMs = DigitEntry.of(accDelta.audioMs.get() + delta.dlt.audioMs.get()); + accDelta.videoMs = DigitEntry.of(accDelta.videoMs.get() + delta.dlt.videoMs.get()); + accDelta.jobsMs = DigitEntry.of(accDelta.jobsMs.get() + delta.dlt.jobsMs.get()); + accDelta.syncMs = DigitEntry.of(accDelta.syncMs.get() + delta.dlt.syncMs.get()); + + accDelta.fgActMs = DigitEntry.of(accDelta.fgActMs.get() + delta.dlt.fgActMs.get()); + accDelta.procTopAppMs = DigitEntry.of(accDelta.procTopAppMs.get() + delta.dlt.procTopAppMs.get()); + accDelta.procTopSleepMs = DigitEntry.of(accDelta.procTopSleepMs.get() + delta.dlt.procTopSleepMs.get()); + accDelta.procFgMs = DigitEntry.of(accDelta.procFgMs.get() + delta.dlt.procFgMs.get()); + accDelta.procFgSrvMs = DigitEntry.of(accDelta.procFgSrvMs.get() + delta.dlt.procFgSrvMs.get()); + accDelta.procBgMs = DigitEntry.of(accDelta.procBgMs.get() + delta.dlt.procBgMs.get()); + accDelta.procCacheMs = DigitEntry.of(accDelta.procCacheMs.get() + delta.dlt.procCacheMs.get()); + + for (Map.Entry> entry : delta.dlt.procStatsCpuUsrTimeMs.entrySet()) { + String key = entry.getKey(); + DigitEntry val = entry.getValue(); + DigitEntry acc = accDelta.procStatsCpuUsrTimeMs.get(key); + accDelta.procStatsCpuUsrTimeMs.put(key, DigitEntry.of(val.get() + (acc == null ? 0 : acc.get()))); + } + for (Map.Entry> entry : delta.dlt.procStatsCpuSysTimeMs.entrySet()) { + String key = entry.getKey(); + DigitEntry val = entry.getValue(); + DigitEntry acc = accDelta.procStatsCpuSysTimeMs.get(key); + accDelta.procStatsCpuSysTimeMs.put(key, DigitEntry.of(val.get() + (acc == null ? 0 : acc.get()))); + } + for (Map.Entry> entry : delta.dlt.procStatsCpuFgTimeMs.entrySet()) { + String key = entry.getKey(); + DigitEntry val = entry.getValue(); + DigitEntry acc = accDelta.procStatsCpuFgTimeMs.get(key); + accDelta.procStatsCpuFgTimeMs.put(key, DigitEntry.of(val.get() + (acc == null ? 0 : acc.get()))); + } + + count++; + duringMs += delta.during; + + } + last = curr; + return delta; + } + + public static boolean isHealthStatsNotReset(HealthStatsSnapshot bgn, HealthStatsSnapshot end) { + try { + assertNotNegative("cpuPowerMams", bgn.cpuPowerMams.get(), end.cpuPowerMams.get()); + assertNotNegative("cpuUsrTimeMs", bgn.cpuUsrTimeMs.get(), end.cpuUsrTimeMs.get()); + assertNotNegative("cpuSysTimeMs", bgn.cpuSysTimeMs.get(), end.cpuSysTimeMs.get()); + assertNotNegative("realTimeMs", bgn.realTimeMs.get(), end.realTimeMs.get()); + assertNotNegative("upTimeMs", bgn.upTimeMs.get(), end.upTimeMs.get()); + assertNotNegative("offRealTimeMs", bgn.offRealTimeMs.get(), end.offRealTimeMs.get()); + assertNotNegative("offUpTimeMs", bgn.offUpTimeMs.get(), end.offUpTimeMs.get()); + + assertNotNegative("mobilePowerMams", bgn.mobilePowerMams.get(), end.mobilePowerMams.get()); + assertNotNegative("mobileRadioActiveMs", bgn.mobileRadioActiveMs.get(), end.mobileRadioActiveMs.get()); + assertNotNegative("mobileIdleMs", bgn.mobileIdleMs.get(), end.mobileIdleMs.get()); + assertNotNegative("mobileRxMs", bgn.mobileRxMs.get(), end.mobileRxMs.get()); + assertNotNegative("mobileTxMs", bgn.mobileTxMs.get(), end.mobileTxMs.get()); + assertNotNegative("mobileRxBytes", bgn.mobileRxBytes.get(), end.mobileRxBytes.get()); + assertNotNegative("mobileTxBytes", bgn.mobileTxBytes.get(), end.mobileTxBytes.get()); + assertNotNegative("mobileRxPackets", bgn.mobileRxPackets.get(), end.mobileRxPackets.get()); + assertNotNegative("mobileTxPackets", bgn.mobileTxPackets.get(), end.mobileTxPackets.get()); + + assertNotNegative("wifiPowerMams", bgn.wifiPowerMams.get(), end.wifiPowerMams.get()); + assertNotNegative("wifiIdleMs", bgn.wifiIdleMs.get(), end.wifiIdleMs.get()); + assertNotNegative("wifiRxMs", bgn.wifiRxMs.get(), end.wifiRxMs.get()); + assertNotNegative("wifiTxMs", bgn.wifiTxMs.get(), end.wifiTxMs.get()); + assertNotNegative("wifiRunningMs", bgn.wifiRunningMs.get(), end.wifiRunningMs.get()); + assertNotNegative("wifiLockMs", bgn.wifiLockMs.get(), end.wifiLockMs.get()); + assertNotNegative("wifiScanMs", bgn.wifiScanMs.get(), end.wifiScanMs.get()); + assertNotNegative("wifiMulticastMs", bgn.wifiMulticastMs.get(), end.wifiMulticastMs.get()); + assertNotNegative("wifiRxBytes", bgn.wifiRxBytes.get(), end.wifiRxBytes.get()); + assertNotNegative("wifiTxBytes", bgn.wifiTxBytes.get(), end.wifiTxBytes.get()); + assertNotNegative("wifiRxPackets", bgn.wifiRxPackets.get(), end.wifiRxPackets.get()); + assertNotNegative("wifiTxPackets", bgn.wifiTxPackets.get(), end.wifiTxPackets.get()); + + assertNotNegative("blueToothPowerMams", bgn.blueToothPowerMams.get(), end.blueToothPowerMams.get()); + assertNotNegative("blueToothIdleMs", bgn.blueToothIdleMs.get(), end.blueToothIdleMs.get()); + assertNotNegative("blueToothRxMs", bgn.blueToothRxMs.get(), end.blueToothRxMs.get()); + assertNotNegative("blueToothTxMs", bgn.blueToothTxMs.get(), end.blueToothTxMs.get()); + + assertNotNegative("wakelocksPartialMs", bgn.wakelocksPartialMs.get(), end.wakelocksPartialMs.get()); + assertNotNegative("wakelocksFullMs", bgn.wakelocksFullMs.get(), end.wakelocksFullMs.get()); + assertNotNegative("wakelocksWindowMs", bgn.wakelocksWindowMs.get(), end.wakelocksWindowMs.get()); + assertNotNegative("wakelocksDrawMs", bgn.wakelocksDrawMs.get(), end.wakelocksDrawMs.get()); + assertNotNegative("wakelocksPidSum", bgn.wakelocksPidSum.get(), end.wakelocksPidSum.get()); + assertNotNegative("gpsMs", bgn.gpsMs.get(), end.gpsMs.get()); + assertNotNegative("sensorsPowerMams", bgn.sensorsPowerMams.get(), end.sensorsPowerMams.get()); + assertNotNegative("cameraMs", bgn.cameraMs.get(), end.cameraMs.get()); + assertNotNegative("flashLightMs", bgn.flashLightMs.get(), end.flashLightMs.get()); + assertNotNegative("audioMs", bgn.audioMs.get(), end.audioMs.get()); + assertNotNegative("videoMs", bgn.videoMs.get(), end.videoMs.get()); + assertNotNegative("jobsMs", bgn.jobsMs.get(), end.jobsMs.get()); + assertNotNegative("syncMs", bgn.syncMs.get(), end.syncMs.get()); + + return true; + } catch (Exception e) { + MatrixLog.w(TAG, "skip, " + e.getMessage()); + return false; + } + } + + static void assertNotNegative(String key, long bgn, long end) { + if (bgn > end) { + throw new IllegalStateException("negative stats: " + key); + } + } + } } } From 796f5bd96389114c2d329b8eae8b2fdf3f08743f Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 20 Oct 2022 16:49:07 +0800 Subject: [PATCH 182/263] AppBgSumPssMonitor: add extra pss factory --- .../canary/monitor/AppBgSumPssMonitor.kt | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt index 3f51defca..3a99282bc 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt @@ -4,9 +4,7 @@ import com.tencent.matrix.lifecycle.IBackgroundStatefulOwner import com.tencent.matrix.lifecycle.IMatrixBackgroundCallback import com.tencent.matrix.lifecycle.supervisor.AppStagedBackgroundOwner import com.tencent.matrix.lifecycle.supervisor.ProcessSupervisor -import com.tencent.matrix.util.MatrixHandlerThread -import com.tencent.matrix.util.MatrixLog -import com.tencent.matrix.util.MemInfo +import com.tencent.matrix.util.* import java.util.concurrent.TimeUnit private const val TAG = "Matrix.monitor.AppBgSumPssMonitor" @@ -18,8 +16,8 @@ class AppBgSumPssMonitorConfig( val enable: Boolean = true, val bgStatefulOwner: IBackgroundStatefulOwner = AppStagedBackgroundOwner, val checkInterval: Long = TimeUnit.MINUTES.toMillis(3), - amsPssThresholdKB: Long = 2 * 1024 * 1024L + 500 * 1024L, // 2.5G - debugPssThresholdKB: Long = 2 * 1024 * 1024L + 500 * 1024L, // 2.5G + amsPssThresholdKB: Long = Long.MAX_VALUE, + debugPssThresholdKB: Long = Long.MAX_VALUE, checkTimes: Int = 3, val callback: (amsPssSumKB: Int, debugPssSumKB: Int, amsMemInfos: Array, debugMemInfos: Array) -> Unit = { amsSumPssKB, debugSumPssKB, amsMemInfos, debugMemInfos -> MatrixLog.e( @@ -29,7 +27,8 @@ class AppBgSumPssMonitorConfig( "\n==========\n" + "debugMemDetail: ${debugMemInfos.contentToString()}" ) - } + }, + val extraPssFactory: () -> Array = { emptyArray() } /*{ arrayOf(MemInfo(processInfo = ProcessInfo(pid = -1, name = "extra_isolate", activity = "none"), amsPssInfo = PssInfo(totalPssK = 0)))}*/ ) { internal val amsPssThresholdKB = amsPssThresholdKB.asThreshold(checkTimes, TimeUnit.MINUTES.toMillis(5)) @@ -37,7 +36,7 @@ class AppBgSumPssMonitorConfig( // internal val override fun toString(): String { - return "AppBgSumPssMonitorConfig(enable=$enable, bgStatefulOwner=$bgStatefulOwner, checkInterval=$checkInterval, callback=${callback.javaClass.name}, thresholdKB=$amsPssThresholdKB)" + return "AppBgSumPssMonitorConfig(enable=$enable, bgStatefulOwner=$bgStatefulOwner, checkInterval=$checkInterval, callback=${callback.javaClass.name}, thresholdKB=$amsPssThresholdKB, extraPssFactory=${extraPssFactory.javaClass.name})" } } @@ -101,17 +100,24 @@ internal class AppBgSumPssMonitor( configs.forEach { config -> var shouldCallback = false + val extraPssInfo = config.extraPssFactory() + val extraPssSum = extraPssInfo.onEach { + MatrixLog.i(TAG, + "${it.processInfo!!.pid}-${it.processInfo!!.name}: extra total pss = ${it.amsPssInfo!!.totalPssK} KB" + ) + }.sumBy { it.amsPssInfo!!.totalPssK }.also { MatrixLog.i(TAG, "extra sum pss = $it KB") } + val overThreshold = config.run { // @formatter:off - arrayOf("amsPss" to amsPssThresholdKB.check(amsPssSum.toLong()) { shouldCallback = true }, - "debugPss" to debugPssThresholdKB.check(debugPssSum.toLong()) { shouldCallback = true } + arrayOf("amsPss" to amsPssThresholdKB.check((amsPssSum + extraPssSum).toLong()) { shouldCallback = true }, + "debugPss" to debugPssThresholdKB.check((debugPssSum + extraPssSum).toLong()) { shouldCallback = true } ).onEach { MatrixLog.i(TAG, "is over threshold? $it") }.any { it.second } // @formatter:on } if (overThreshold && shouldCallback) { MatrixLog.i(TAG, "report over threshold") - config.callback.invoke(amsPssSum, debugPssSum, amsMemInfos, debugMemInfos) + config.callback.invoke(amsPssSum + extraPssSum, debugPssSum + extraPssSum, amsMemInfos + extraPssInfo, debugMemInfos + extraPssInfo) } } } From 225489a5b3d6839ba087eb20b01abd7c3d384950 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 20 Oct 2022 16:58:56 +0800 Subject: [PATCH 183/263] AppBgSumPssMonitor: filter log --- .../tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt index 3a99282bc..dc482b21f 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt @@ -105,7 +105,7 @@ internal class AppBgSumPssMonitor( MatrixLog.i(TAG, "${it.processInfo!!.pid}-${it.processInfo!!.name}: extra total pss = ${it.amsPssInfo!!.totalPssK} KB" ) - }.sumBy { it.amsPssInfo!!.totalPssK }.also { MatrixLog.i(TAG, "extra sum pss = $it KB") } + }.sumBy { it.amsPssInfo!!.totalPssK }.also { if (extraPssInfo.isNotEmpty()) { MatrixLog.i(TAG, "extra sum pss = $it KB") } } val overThreshold = config.run { // @formatter:off From afbc57b25c195b91beb25cacfdb46bae557fa605 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Thu, 20 Oct 2022 17:23:48 +0800 Subject: [PATCH 184/263] Update battery stats thread cfg --- .../tencent/matrix/batterycanary/stats/BatteryStatsFeature.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/BatteryStatsFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/BatteryStatsFeature.java index 30df7d54b..40cf45e7e 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/BatteryStatsFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/stats/BatteryStatsFeature.java @@ -49,7 +49,7 @@ public void onTurnOn() { mBatteryRecorder = mCore.getConfig().batteryRecorder; mBatteryStats = mCore.getConfig().batteryStats; if (mBatteryRecorder != null) { - mStatsThread = MatrixHandlerThread.getNewHandlerThread("matrix_stats", Thread.MIN_PRIORITY); + mStatsThread = MatrixHandlerThread.getNewHandlerThread("matrix_stats", Thread.NORM_PRIORITY); mStatsHandler = new Handler(mStatsThread.getLooper()); mStatsHandler.post(new Runnable() { @Override From 713d4c03a7cde7a29b39d9398aa4b59ffa7cc861 Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 21 Oct 2022 12:01:04 +0800 Subject: [PATCH 185/263] Fix multi-thread hashset modification exception --- .../main/java/com/tencent/matrix/util/MatrixHandlerThread.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MatrixHandlerThread.java b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MatrixHandlerThread.java index 743ec9dbf..9e035eb94 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MatrixHandlerThread.java +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MatrixHandlerThread.java @@ -75,7 +75,7 @@ public static Handler getDefaultHandler() { return defaultHandler; } - public static HandlerThread getNewHandlerThread(String name, int priority) { + public static synchronized HandlerThread getNewHandlerThread(String name, int priority) { for (Iterator i = handlerThreads.iterator(); i.hasNext(); ) { HandlerThread element = i.next(); if (!element.isAlive()) { From 5abdbd61b4149e41f70cda28cd69c26e3c8b7276 Mon Sep 17 00:00:00 2001 From: aurorani Date: Tue, 25 Oct 2022 22:52:47 +0800 Subject: [PATCH 186/263] fix: Fix unused resources finding issue of apk canary by analyzing r8-obfuscated apk. --- .../apk/model/task/UnusedResourcesTask.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java index 0f5c4443f..1e738d216 100644 --- a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java +++ b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnusedResourcesTask.java @@ -52,6 +52,8 @@ import java.util.Map; import java.util.Set; import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import brut.androlib.AndrolibException; @@ -160,6 +162,8 @@ private String parseResourceId(String resId) { return ""; } + private static final Pattern sRClassPattern = Pattern.compile("(([a-zA-Z0-9_]*\\.)*)R\\$([a-z]+)"); + private String parseResourceNameFromProguard(String entry) { if (!Util.isNullOrNil(entry)) { String[] columns = entry.split("->"); @@ -173,7 +177,17 @@ private String parseResourceNameFromProguard(String entry) { if (rclassProguardMap.containsKey(resource)) { return rclassProguardMap.get(resource); } else { - return ""; + final Matcher matcher = sRClassPattern.matcher(className); + if (matcher.find()) { + final StringBuilder resultBuilder = new StringBuilder(); + resultBuilder.append("R."); + resultBuilder.append(matcher.group(3)); + resultBuilder.append("."); + resultBuilder.append(fieldName); + return resultBuilder.toString(); + } else { + return ""; + } } } else { if (ApkUtil.isRClassName(ApkUtil.getPureClassName(className))) { From 81dd439ee26abe1319bd2ea143da44cae1e92631 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 26 Oct 2022 12:05:41 +0800 Subject: [PATCH 187/263] res-plugin: fix manual dump api --- .../resource/config/SharePluginInfo.java | 2 + .../resource/processor/BaseLeakProcessor.java | 5 + .../processor/ManualDumpProcessor.java | 101 ++++-------------- 3 files changed, 30 insertions(+), 78 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/SharePluginInfo.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/SharePluginInfo.java index cbf2632eb..4db4b158c 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/SharePluginInfo.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/SharePluginInfo.java @@ -32,7 +32,9 @@ public class SharePluginInfo { public static final String ISSUE_COST_MILLIS = "cost_millis"; public static final String ISSUE_RETRY_COUNT = "retry_count"; public static final String ISSUE_LEAK_PROCESS = "leak_process"; + @Deprecated public static final String ISSUE_DUMP_DATA = "dump_data"; + public static final String ISSUE_HPROF_PATH = "hprof_path"; public static final String ISSUE_NOTIFICATION_ID = "notification_id"; public static final class IssueType { diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java index 906463306..0145fdf99 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/BaseLeakProcessor.java @@ -102,6 +102,10 @@ final protected void publishIssue(int issueType, ResourceConfig.DumpMode dumpMod } final protected void publishIssue(int issueType, ResourceConfig.DumpMode dumpMode, String activity, String refKey, String detail, String cost, int retryCount) { + publishIssue(issueType, dumpMode, activity, refKey, detail, cost, retryCount, null); + } + + final protected void publishIssue(int issueType, ResourceConfig.DumpMode dumpMode, String activity, String refKey, String detail, String cost, int retryCount, String hprofPath) { Issue issue = new Issue(issueType); JSONObject content = new JSONObject(); try { @@ -111,6 +115,7 @@ final protected void publishIssue(int issueType, ResourceConfig.DumpMode dumpMod content.put(SharePluginInfo.ISSUE_LEAK_DETAIL, detail); content.put(SharePluginInfo.ISSUE_COST_MILLIS, cost); content.put(SharePluginInfo.ISSUE_RETRY_COUNT, retryCount); + content.put(SharePluginInfo.ISSUE_HPROF_PATH, hprofPath); } catch (JSONException jsonException) { MatrixLog.printErrStackTrace(TAG, jsonException, ""); } diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java index b325d960e..578b862ce 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java @@ -1,5 +1,7 @@ package com.tencent.matrix.resource.processor; +import static android.os.Build.VERSION.SDK_INT; + import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -7,8 +9,7 @@ import android.content.Context; import android.content.Intent; import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; +import android.util.Pair; import com.tencent.matrix.resource.MemoryUtil; import com.tencent.matrix.resource.R; @@ -18,7 +19,6 @@ import com.tencent.matrix.resource.config.SharePluginInfo; import com.tencent.matrix.resource.dumper.HprofFileManager; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; -import com.tencent.matrix.util.MatrixHandlerThread; import com.tencent.matrix.util.MatrixLog; import com.tencent.matrix.util.MatrixUtil; @@ -29,10 +29,6 @@ import java.util.Locale; import java.util.concurrent.TimeUnit; -import static android.os.Build.VERSION.SDK_INT; - -import androidx.annotation.Nullable; - /** * 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 @@ -75,24 +71,21 @@ public boolean process(final DestroyedActivityInfo destroyedActivityInfo) { return true; } - dumpAndAnalyzeAsync(destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey, new ManualDumpCallback() { - @Override - public void onDumpComplete(@Nullable ManualDumpData data) { - if (data != null) { - if (!isMuted) { - MatrixLog.i(TAG, "shown notification!!!3"); - sendResultNotification(destroyedActivityInfo, data); - } else { - MatrixLog.i(TAG, "mute mode, notification will not be shown."); - } - } + Pair data = dumpAndAnalyse(destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey); + if (data != null) { + if (!isMuted) { + MatrixLog.i(TAG, "shown notification!!!3"); + sendResultNotification(destroyedActivityInfo, data.first, data.second); + } else { + MatrixLog.i(TAG, "mute mode, notification will not be shown."); } - }); + } + return true; } - private void sendResultNotification(DestroyedActivityInfo activityInfo, ManualDumpData data) { + private void sendResultNotification(DestroyedActivityInfo activityInfo, String hprofPath, String refChain) { final Context context = getWatcher().getContext(); Intent targetIntent = new Intent(); @@ -100,7 +93,8 @@ private void sendResultNotification(DestroyedActivityInfo activityInfo, ManualDu targetIntent.putExtra(SharePluginInfo.ISSUE_ACTIVITY_NAME, activityInfo.mActivityName); targetIntent.putExtra(SharePluginInfo.ISSUE_REF_KEY, activityInfo.mKey); targetIntent.putExtra(SharePluginInfo.ISSUE_LEAK_PROCESS, MatrixUtil.getProcessName(context)); - targetIntent.putExtra(SharePluginInfo.ISSUE_DUMP_DATA, data); + targetIntent.putExtra(SharePluginInfo.ISSUE_HPROF_PATH, hprofPath); + targetIntent.putExtra(SharePluginInfo.ISSUE_LEAK_DETAIL, refChain); PendingIntent pIntent = PendingIntent.getActivity(context, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT); @@ -151,19 +145,6 @@ public void setMuted(boolean mute) { isMuted = mute; } - private void dumpAndAnalyzeAsync(final String activity, final String refString, final ManualDumpCallback callback) { - MatrixHandlerThread.getDefaultHandler().postAtFrontOfQueue(new Runnable() { - @Override - public void run() { - callback.onDumpComplete(dumpAndAnalyse(activity, refString)); - } - }); - } - - private interface ManualDumpCallback { - void onDumpComplete(@Nullable ManualDumpData data); - } - /** * run in leaked process * @@ -171,7 +152,7 @@ private interface ManualDumpCallback { * @param key * @return */ - private ManualDumpData dumpAndAnalyse(String activity, String key) { + private Pair dumpAndAnalyse(String activity, String key) { getWatcher().triggerGc(); @@ -192,57 +173,21 @@ private ManualDumpData dumpAndAnalyse(String activity, String key) { final String leakChain = result.toString(); publishIssue( SharePluginInfo.IssueType.LEAK_FOUND, - ResourceConfig.DumpMode.FORK_ANALYSE, - activity, key, leakChain, String.valueOf(result.mAnalysisDurationMs) + ResourceConfig.DumpMode.MANUAL_DUMP, + activity, key, leakChain, String.valueOf(result.mAnalysisDurationMs), + 0, + file.getAbsolutePath() ); - return new ManualDumpData(file.getAbsolutePath(), leakChain); + return new Pair<>(file.getAbsolutePath(), leakChain); } else if (result.mFailure != null) { publishIssue( SharePluginInfo.IssueType.ERR_EXCEPTION, - ResourceConfig.DumpMode.FORK_ANALYSE, + ResourceConfig.DumpMode.MANUAL_DUMP, activity, key, result.mFailure.toString(), "0" ); return null; } else { - return new ManualDumpData(file.getAbsolutePath(), null); - } - } - - public static class ManualDumpData implements Parcelable { - public final String hprofPath; - public final String refChain; - - public ManualDumpData(String hprofPath, String refChain) { - this.hprofPath = hprofPath; - this.refChain = refChain; - } - - protected ManualDumpData(Parcel in) { - hprofPath = in.readString(); - refChain = in.readString(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(hprofPath); - dest.writeString(refChain); + return new Pair<>(file.getAbsolutePath(), null); } - - @Override - public int describeContents() { - return 0; - } - - public static final Creator CREATOR = new Creator() { - @Override - public ManualDumpData createFromParcel(Parcel in) { - return new ManualDumpData(in); - } - - @Override - public ManualDumpData[] newArray(int size) { - return new ManualDumpData[size]; - } - }; } } From 9bd76bff6b23f19802b05b87b358341842434ef2 Mon Sep 17 00:00:00 2001 From: opdeng Date: Sat, 29 Oct 2022 11:27:51 +0800 Subject: [PATCH 188/263] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20tid=20=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix-opengl-leak/src/main/cpp/my_functions.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h index d7122bf47..79864349d 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h @@ -16,6 +16,7 @@ #include #include "StackMeta.h" #include +#include #ifndef OPENGL_API_HOOK_MY_FUNCTIONS_H #define OPENGL_API_HOOK_MY_FUNCTIONS_H @@ -84,7 +85,7 @@ void enable_javastack(bool enable) { is_javastack_enabled = enable; } -void thread_id_to_string(thread::id thread_id, char *&result) { +void thread_id_to_string(int thread_id, char *&result) { stringstream stream; stream << thread_id; result = new char[stream.str().size() + 1]; @@ -193,7 +194,7 @@ gen_jni_callback(int alloc_count, GLuint *copy_resource, int throwable, const th env->SetIntArrayRegion(newArr, 0, alloc_count, result); char *thread_id_c_str; - thread_id_to_string(thread_id, thread_id_c_str); + thread_id_to_string(gettid(), thread_id_c_str); jstring j_thread_id = env->NewStringUTF(thread_id_c_str); jstring j_activity_info = env->NewStringUTF(activity_info); From 85521397b156f20ef58eff6264efe3a478f49b4f Mon Sep 17 00:00:00 2001 From: opdeng Date: Mon, 31 Oct 2022 10:11:55 +0800 Subject: [PATCH 189/263] egl leak check --- .../src/main/cpp/common/HookCommon.h | 1 + .../matrix-opengl-leak/CMakeLists.txt | 2 + ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 29 ++++- ...encent_matrix_openglleak_hook_OpenGLHook.h | 8 ++ .../src/main/cpp/my_functions.h | 116 ++++++++++++++++-- .../matrix-opengl-leak/src/main/cpp/type.h | 6 + .../matrix/openglleak/OpenglLeakPlugin.java | 5 + .../matrix/openglleak/hook/OpenGLHook.java | 26 ++++ .../statistics/resource/OpenGLInfo.java | 2 +- 9 files changed, 182 insertions(+), 13 deletions(-) diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h b/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h index d38c1c1a2..a6642e099 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h @@ -34,6 +34,7 @@ #define HOOK_REQUEST_GROUPID_PTHREAD 0x04 #define HOOK_REQUEST_GROUPID_MEMGUARD 0x05 #define HOOK_REQUEST_GROUPID_MEMGUARD_2 0x06 +#define HOOK_REQUEST_GROUPID_EGL_HOOK 0x07 #define GET_CALLER_ADDR(__caller_addr) \ void * __caller_addr = __builtin_return_address(0) diff --git a/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt b/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt index 47c3ffaa1..28dac4690 100644 --- a/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt +++ b/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt @@ -76,6 +76,8 @@ target_link_libraries( # Specifies the target library. GLESv2 GLESv3 EGL + PRIVATE ${EXT_DEP}/lib/${ANDROID_ABI}/libxhook.a + PRIVATE ${EXT_DEP}/lib/${ANDROID_ABI}/libsemi_dlfcn.a PRIVATE ${EXT_DEP}/lib/${ANDROID_ABI}/libwechatbacktrace.so ) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp index 042551161..1322ad544 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp @@ -12,6 +12,9 @@ #include "get_tls.h" #include "type.h" #include "my_functions.h" +#include + +#define HOOK_REQUEST_GROUPID_EGL_HOOK 0x07 extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_OpenGLHook_init (JNIEnv *env, jobject thiz) { @@ -62,6 +65,11 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_getThrowable = env->GetStaticMethodID(class_OpenGLHook, "getThrowable", "()I"); + method_onEglContextCreate = env->GetStaticMethodID(class_OpenGLHook, "onEglContextCreate", + "(Ljava/lang/String;IJJLjava/lang/String;)V"); + method_onEglContextDestroy = env->GetStaticMethodID(class_OpenGLHook, "onEglContextDestroy", + "(Ljava/lang/String;J)V"); + messages_containers = new BufferManagement(); messages_containers->start_process(); pthread_key_create(&g_thread_name_key, [](void *thread_name) { @@ -94,6 +102,24 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { } +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "opdeng" , __VA_ARGS__) // 定义LOGI类型 + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglCreate(JNIEnv *env, jclass clazz) { + LOGI("start hook egl context"); + return xhook_grouped_register(HOOK_REQUEST_GROUPID_EGL_HOOK, ".*\\.so$", "eglCreateContext", + (void *) my_egl_context_create, (void **) (&system_eglCreateContext)) == 0; +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglDestory(JNIEnv *env, jclass clazz) { + return xhook_grouped_register(HOOK_REQUEST_GROUPID_EGL_HOOK, ".*\\.so$", "eglDestroyContext", + (void *) my_egl_context_destroy, + (void **) (&system_eglDestroyContext)) == 0; +} + /* * Class: com_tencent_matrix_openglleak_hook_OpenGLHook * Method: hookGlGenTextures @@ -571,7 +597,8 @@ Java_com_tencent_matrix_openglleak_hook_OpenGLHook_isEglContextAlive( extern "C" JNIEXPORT jint JNICALL -Java_com_tencent_matrix_openglleak_hook_OpenGLHook_getResidualQueueSize(JNIEnv *env, jobject clazz) { +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_getResidualQueueSize(JNIEnv *env, + jobject clazz) { return messages_containers->get_queue_size(); } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.h index dde337945..15bdd9542 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.h @@ -159,6 +159,14 @@ extern "C" JNIEXPORT jint JNICALL Java_com_tencent_matrix_openglleak_hook_OpenGLHook_getResidualQueueSize(JNIEnv *env, jobject clazz); +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglCreate(JNIEnv *env, jclass clazz); + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglDestory(JNIEnv *env, jclass clazz); + #ifdef __cplusplus } #endif diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h index 79864349d..c64daaa7e 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h @@ -44,6 +44,8 @@ static System_GlBind_TYPE system_glBindFramebuffer = NULL; static System_GlBind_TYPE system_glBindRenderbuffer = NULL; static System_GlBufferData system_glBufferData = NULL; static System_GlRenderbufferStorage system_glRenderbufferStorage = NULL; +static System_eglCreateContext system_eglCreateContext = NULL; +static System_eglDestroyContext system_eglDestroyContext = NULL; static JavaVM *m_java_vm; @@ -66,6 +68,8 @@ static jmethodID method_onGlTexImage3D; static jmethodID method_onGlBufferData; static jmethodID method_onGlRenderbufferStorage; static jmethodID method_getThrowable; +static jmethodID method_onEglContextCreate; +static jmethodID method_onEglContextDestroy; const size_t BUF_SIZE = 1024; static pthread_once_t g_onceInitTls = PTHREAD_ONCE_INIT; @@ -75,7 +79,7 @@ static bool is_stacktrace_enabled = true; static bool is_javastack_enabled = true; static matrix::BufferManagement *messages_containers; -static char* curr_activity_info = nullptr; +static char *curr_activity_info = nullptr; void enable_stacktrace(bool enable) { is_stacktrace_enabled = enable; @@ -182,7 +186,7 @@ void gen_jni_callback(int alloc_count, GLuint *copy_resource, int throwable, const thread::id thread_id, wechat_backtrace::Backtrace *backtracePtr, EGLContext egl_context, EGLSurface egl_draw_surface, EGLSurface egl_read_surface, - char* activity_info, jmethodID jmethodId) { + char *activity_info, jmethodID jmethodId) { JNIEnv *env = GET_ENV(); int *result = new int[alloc_count]; @@ -243,7 +247,7 @@ void delete_jni_callback(int delete_count, GLuint *copy_resource, const thread:: env->SetIntArrayRegion(newArr, 0, delete_count, result); char *thread_id_c_str; - thread_id_to_string(thread_id, thread_id_c_str); + thread_id_to_string(gettid(), thread_id_c_str); jstring j_thread_id = env->NewStringUTF(thread_id_c_str); env->CallStaticVoidMethod(class_OpenGLHook, @@ -287,7 +291,7 @@ GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { EGLSurface egl_draw_surface = eglGetCurrentSurface(EGL_DRAW); EGLSurface egl_read_surface = eglGetCurrentSurface(EGL_READ); - char* activity_info = static_cast(malloc(BUF_SIZE)); + char *activity_info = static_cast(malloc(BUF_SIZE)); if (curr_activity_info != nullptr) { strcpy(activity_info, curr_activity_info); } else { @@ -299,7 +303,8 @@ GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { [n, copy_textures, throwable, thread_id, backtracePrt, egl_context, egl_read_surface, egl_draw_surface, activity_info]() { gen_jni_callback(n, copy_textures, throwable, thread_id, - backtracePrt, egl_context, egl_draw_surface, egl_read_surface, + backtracePrt, egl_context, egl_draw_surface, + egl_read_surface, activity_info, method_onGlGenTextures); }); @@ -354,7 +359,7 @@ GL_APICALL void GL_APIENTRY my_glGenBuffers(GLsizei n, GLuint *buffers) { EGLSurface egl_draw_surface = eglGetCurrentSurface(EGL_DRAW); EGLSurface egl_read_surface = eglGetCurrentSurface(EGL_READ); - char* activity_info = static_cast(malloc(BUF_SIZE)); + char *activity_info = static_cast(malloc(BUF_SIZE)); if (curr_activity_info != nullptr) { strcpy(activity_info, curr_activity_info); } else { @@ -365,7 +370,8 @@ GL_APICALL void GL_APIENTRY my_glGenBuffers(GLsizei n, GLuint *buffers) { [n, copy_buffers, throwable, thread_id, backtracePrt, egl_context, egl_draw_surface, egl_read_surface, activity_info]() { gen_jni_callback(n, copy_buffers, throwable, thread_id, - backtracePrt, egl_context, egl_draw_surface,egl_read_surface, + backtracePrt, egl_context, egl_draw_surface, + egl_read_surface, activity_info, method_onGlGenBuffers); }); @@ -420,7 +426,7 @@ GL_APICALL void GL_APIENTRY my_glGenFramebuffers(GLsizei n, GLuint *buffers) { EGLSurface egl_draw_surface = eglGetCurrentSurface(EGL_DRAW); EGLSurface egl_read_surface = eglGetCurrentSurface(EGL_READ); - char* activity_info = static_cast(malloc(BUF_SIZE)); + char *activity_info = static_cast(malloc(BUF_SIZE)); if (curr_activity_info != nullptr) { strcpy(activity_info, curr_activity_info); } else { @@ -432,7 +438,8 @@ GL_APICALL void GL_APIENTRY my_glGenFramebuffers(GLsizei n, GLuint *buffers) { [n, copy_buffers, throwable, thread_id, backtracePrt, egl_context, egl_draw_surface, egl_read_surface, activity_info]() { gen_jni_callback(n, copy_buffers, throwable, thread_id, - backtracePrt, egl_context, egl_draw_surface,egl_read_surface, + backtracePrt, egl_context, egl_draw_surface, + egl_read_surface, activity_info, method_onGlGenFramebuffers); }); @@ -487,7 +494,7 @@ GL_APICALL void GL_APIENTRY my_glGenRenderbuffers(GLsizei n, GLuint *buffers) { EGLSurface egl_draw_surface = eglGetCurrentSurface(EGL_DRAW); EGLSurface egl_read_surface = eglGetCurrentSurface(EGL_READ); - char* activity_info = static_cast(malloc(BUF_SIZE)); + char *activity_info = static_cast(malloc(BUF_SIZE)); if (curr_activity_info != nullptr) { strcpy(activity_info, curr_activity_info); } else { @@ -499,7 +506,8 @@ GL_APICALL void GL_APIENTRY my_glGenRenderbuffers(GLsizei n, GLuint *buffers) { [n, copy_buffers, throwable, thread_id, backtracePrt, egl_context, egl_draw_surface, egl_read_surface, activity_info]() { gen_jni_callback(n, copy_buffers, throwable, thread_id, - backtracePrt, egl_context, egl_draw_surface,egl_read_surface, + backtracePrt, egl_context, egl_draw_surface, + egl_read_surface, activity_info, method_onGlGenRenderbuffers); }); @@ -801,5 +809,91 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL } } +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "opdeng" , __VA_ARGS__) // 定义LOGI类型 + +EGLAPI EGLContext EGLAPIENTRY +my_egl_context_create(EGLDisplay dpy, EGLConfig config, EGLContext share_context, + const EGLint *attrib_list) { + LOGI("- - - - - - - - - - my_egl_context_create - - - - - - - - - -"); + EGLContext ret = NULL; + if (NULL != system_eglCreateContext) { + ret = system_eglCreateContext(dpy, config, share_context, attrib_list); + + if (is_render_thread()) { + return ret; + } + + wechat_backtrace::Backtrace *backtracePrt = get_native_backtrace(); + + int throwable = get_java_throwable(); + + char *thread_id_c_str; + thread_id_to_string(gettid(), thread_id_c_str); + jstring j_thread_id = GET_ENV()->NewStringUTF(thread_id_c_str); + + char *activity_info = static_cast(malloc(BUF_SIZE)); + if (curr_activity_info != nullptr) { + strcpy(activity_info, curr_activity_info); + } else { + strcpy(activity_info, "null"); + } + + messages_containers + ->enqueue_message((uintptr_t) ret, + [backtracePrt, throwable, j_thread_id, ret, activity_info]() { + + JNIEnv *env = GET_ENV(); + + wechat_backtrace::Backtrace *backtrace = deduplicate_backtrace( + backtracePrt); + + jstring j_activity_info = env->NewStringUTF(activity_info); + + env->CallStaticVoidMethod(class_OpenGLHook, + method_onEglContextCreate, + j_thread_id, + (jint) throwable, + (jlong) backtrace, + (jlong) ret, j_activity_info); + + env->DeleteLocalRef(j_activity_info); + + if (activity_info != nullptr) { + free(activity_info); + } + }); + } + return ret; +} + +EGLAPI EGLBoolean EGLAPIENTRY my_egl_context_destroy(EGLDisplay dpy, EGLContext ctx) { + EGLBoolean ret; + if (NULL != system_eglDestroyContext) { + ret = system_eglDestroyContext(dpy, ctx); + + if (is_render_thread()) { + return ret; + } + + char *thread_id_c_str; + thread_id_to_string(gettid(), thread_id_c_str); + jstring j_thread_id = GET_ENV()->NewStringUTF(thread_id_c_str); + + EGLContext egl_context = eglGetCurrentContext(); + + messages_containers + ->enqueue_message((uintptr_t) egl_context, + [j_thread_id, egl_context]() { + + JNIEnv *env = GET_ENV(); + + env->CallStaticVoidMethod(class_OpenGLHook, + method_onEglContextDestroy, + j_thread_id, + (jlong) egl_context); + }); + } + return ret; +} #endif //OPENGL_API_HOOK_MY_FUNCTIONS_H \ No newline at end of file diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.h index 3c34fa337..22c4d535c 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.h @@ -13,6 +13,7 @@ #include #include #include +#include #ifndef OPENGL_API_HOOK_TYPE_H #define OPENGL_API_HOOK_TYPE_H @@ -61,6 +62,11 @@ typedef void (*System_GlRenderbufferStorage)(GLenum target, GLsizei width, GLsizei height); +typedef EGLContext (*System_eglCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, + const EGLint *attrib_list); + +typedef EGLBoolean (*System_eglDestroyContext)(EGLDisplay dpy, EGLContext ctx); + System_GlNormal_TYPE get_target_func_ptr(const char *func_name); System_GlBind_TYPE get_bind_func_ptr(const char *func_name); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java index e83edbce0..ebf19dcbf 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java @@ -7,6 +7,7 @@ import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; +import android.util.Log; import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.detector.IOpenglIndexDetector; @@ -116,6 +117,10 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_RENDERBUFFER, map.get(FuncNameString.GL_BIND_RENDERBUFFER)); OpenGLHook.getInstance().hook(FuncNameString.GL_BUFFER_DATA, map.get(FuncNameString.GL_BUFFER_DATA)); OpenGLHook.getInstance().hook(FuncNameString.GL_RENDER_BUFFER_STORAGE, map.get(FuncNameString.GL_RENDER_BUFFER_STORAGE)); + boolean ret = OpenGLHook.getInstance().hookEglCreate(); + Log.e("opdeng", "create :" + ret); + ret = OpenGLHook.getInstance().hookEglDestory(); + Log.e("opdeng", "destroy :" + ret); MatrixLog.e(TAG, "hook finish"); } catch (Throwable e) { e.printStackTrace(); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java index 496418895..1b5b54150 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java @@ -131,6 +131,10 @@ public boolean hook(String targetFuncName, int index) { private static native boolean hookGlRenderbufferStorage(int index); + public static native boolean hookEglCreate(); + + public static native boolean hookEglDestory(); + public static native String dumpNativeStack(long nativeStackPtr); public static native void releaseNative(long nativeStackPtr); @@ -259,6 +263,28 @@ public static void onGlDeleteRenderbuffers(int[] ids, String threadId, final lon } } + public static void onEglContextCreate(String threadId, final int throwable, long nativeStackPtr, final long eglContext, String activityInfo) { + AtomicInteger counter = new AtomicInteger(1); + + JavaStacktrace.Trace trace = JavaStacktrace.getBacktraceValue(throwable); + + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.EGL_CONTEXT, -1, threadId, eglContext, 0, 0, trace, nativeStackPtr, ActivityRecorder.revertActivityInfo(activityInfo), counter); + ResRecordManager.getInstance().gen(openGLInfo); + + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlGenRenderbuffers(openGLInfo); + } + } + + public static void onEglContextDestroy(String threadId, final long eglContext) { + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.EGL_CONTEXT, -1, threadId, eglContext); + ResRecordManager.getInstance().delete(openGLInfo); + + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlDeleteRenderbuffers(openGLInfo); + } + } + public static void onGetError(int eid) { if (getInstance().mErrorListener != null) { getInstance().mErrorListener.onGlError(eid); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java index 1ae790b1b..ef2b85d5d 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java @@ -24,7 +24,7 @@ public class OpenGLInfo { private AtomicInteger counter; public enum TYPE { - TEXTURE, BUFFER, FRAME_BUFFERS, RENDER_BUFFERS + TEXTURE, BUFFER, FRAME_BUFFERS, RENDER_BUFFERS, EGL_CONTEXT } public OpenGLInfo(OpenGLInfo clone) { From 3305e90eabe817f30af5142d5284607c35fcdaab Mon Sep 17 00:00:00 2001 From: opdeng Date: Mon, 31 Oct 2022 11:49:51 +0800 Subject: [PATCH 190/263] =?UTF-8?q?egl=20=E6=B3=84=E6=BC=8F=E7=9B=91?= =?UTF-8?q?=E6=8E=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...com_tencent_matrix_openglleak_hook_OpenGLHook.cpp | 12 ++++++------ .../matrix-opengl-leak/src/main/cpp/my_functions.h | 8 +++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp index 1322ad544..f04e6aa96 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp @@ -101,23 +101,23 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_VERSION_1_6; } - -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "opdeng" , __VA_ARGS__) // 定义LOGI类型 - extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglCreate(JNIEnv *env, jclass clazz) { - LOGI("start hook egl context"); - return xhook_grouped_register(HOOK_REQUEST_GROUPID_EGL_HOOK, ".*\\.so$", "eglCreateContext", + bool ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_EGL_HOOK, ".*\\.so$", "eglCreateContext", (void *) my_egl_context_create, (void **) (&system_eglCreateContext)) == 0; + xhook_refresh(true); + return ret; } extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglDestory(JNIEnv *env, jclass clazz) { - return xhook_grouped_register(HOOK_REQUEST_GROUPID_EGL_HOOK, ".*\\.so$", "eglDestroyContext", + bool ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_EGL_HOOK, ".*\\.so$", "eglDestroyContext", (void *) my_egl_context_destroy, (void **) (&system_eglDestroyContext)) == 0; + xhook_refresh(true); + return ret; } /* diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h index c64daaa7e..1caa88365 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h @@ -809,12 +809,9 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL } } -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "opdeng" , __VA_ARGS__) // 定义LOGI类型 - EGLAPI EGLContext EGLAPIENTRY my_egl_context_create(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) { - LOGI("- - - - - - - - - - my_egl_context_create - - - - - - - - - -"); EGLContext ret = NULL; if (NULL != system_eglCreateContext) { ret = system_eglCreateContext(dpy, config, share_context, attrib_list); @@ -829,7 +826,6 @@ my_egl_context_create(EGLDisplay dpy, EGLConfig config, EGLContext share_context char *thread_id_c_str; thread_id_to_string(gettid(), thread_id_c_str); - jstring j_thread_id = GET_ENV()->NewStringUTF(thread_id_c_str); char *activity_info = static_cast(malloc(BUF_SIZE)); if (curr_activity_info != nullptr) { @@ -840,7 +836,7 @@ my_egl_context_create(EGLDisplay dpy, EGLConfig config, EGLContext share_context messages_containers ->enqueue_message((uintptr_t) ret, - [backtracePrt, throwable, j_thread_id, ret, activity_info]() { + [backtracePrt, throwable, thread_id_c_str, ret, activity_info]() { JNIEnv *env = GET_ENV(); @@ -848,6 +844,7 @@ my_egl_context_create(EGLDisplay dpy, EGLConfig config, EGLContext share_context backtracePrt); jstring j_activity_info = env->NewStringUTF(activity_info); + jstring j_thread_id = env->NewStringUTF(thread_id_c_str); env->CallStaticVoidMethod(class_OpenGLHook, method_onEglContextCreate, @@ -857,6 +854,7 @@ my_egl_context_create(EGLDisplay dpy, EGLConfig config, EGLContext share_context (jlong) ret, j_activity_info); env->DeleteLocalRef(j_activity_info); + env->DeleteLocalRef(j_thread_id); if (activity_info != nullptr) { free(activity_info); From 700e0d55b99cfad9834cce0eefa5bf37eb191da3 Mon Sep 17 00:00:00 2001 From: opdeng Date: Mon, 31 Oct 2022 16:09:13 +0800 Subject: [PATCH 191/263] delete log --- .../com/tencent/matrix/openglleak/OpenglLeakPlugin.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java index ebf19dcbf..03663007f 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java @@ -117,10 +117,8 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_RENDERBUFFER, map.get(FuncNameString.GL_BIND_RENDERBUFFER)); OpenGLHook.getInstance().hook(FuncNameString.GL_BUFFER_DATA, map.get(FuncNameString.GL_BUFFER_DATA)); OpenGLHook.getInstance().hook(FuncNameString.GL_RENDER_BUFFER_STORAGE, map.get(FuncNameString.GL_RENDER_BUFFER_STORAGE)); - boolean ret = OpenGLHook.getInstance().hookEglCreate(); - Log.e("opdeng", "create :" + ret); - ret = OpenGLHook.getInstance().hookEglDestory(); - Log.e("opdeng", "destroy :" + ret); + OpenGLHook.getInstance().hookEglCreate(); + OpenGLHook.getInstance().hookEglDestory(); MatrixLog.e(TAG, "hook finish"); } catch (Throwable e) { e.printStackTrace(); From 6cbe31f2efebe35e33da2743f0112ea9903c05bc Mon Sep 17 00:00:00 2001 From: opdeng Date: Mon, 31 Oct 2022 16:09:41 +0800 Subject: [PATCH 192/263] =?UTF-8?q?=E5=88=A0=E9=99=A4=20log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java index 03663007f..7c1de5599 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java @@ -7,8 +7,6 @@ import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; -import android.util.Log; - import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.detector.IOpenglIndexDetector; import com.tencent.matrix.openglleak.detector.OpenglIndexDetectorService; From 290ed5a507e4fb9e09c12a3c2124d54fbb9980e5 Mon Sep 17 00:00:00 2001 From: opdeng Date: Mon, 31 Oct 2022 17:13:36 +0800 Subject: [PATCH 193/263] =?UTF-8?q?=E6=9A=82=E6=97=B6=E5=B1=8F=E8=94=BD=20?= =?UTF-8?q?egl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java index 7c1de5599..5bb3c9453 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java @@ -115,8 +115,8 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_RENDERBUFFER, map.get(FuncNameString.GL_BIND_RENDERBUFFER)); OpenGLHook.getInstance().hook(FuncNameString.GL_BUFFER_DATA, map.get(FuncNameString.GL_BUFFER_DATA)); OpenGLHook.getInstance().hook(FuncNameString.GL_RENDER_BUFFER_STORAGE, map.get(FuncNameString.GL_RENDER_BUFFER_STORAGE)); - OpenGLHook.getInstance().hookEglCreate(); - OpenGLHook.getInstance().hookEglDestory(); +// OpenGLHook.getInstance().hookEglCreate(); +// OpenGLHook.getInstance().hookEglDestory(); MatrixLog.e(TAG, "hook finish"); } catch (Throwable e) { e.printStackTrace(); From 359fc7005fd16b488932a2ee616eb9db87020621 Mon Sep 17 00:00:00 2001 From: opdeng Date: Mon, 31 Oct 2022 17:25:49 +0800 Subject: [PATCH 194/263] crash fix --- .../matrix-opengl-leak/src/main/cpp/my_functions.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h index 1caa88365..4572bff79 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h @@ -875,20 +875,22 @@ EGLAPI EGLBoolean EGLAPIENTRY my_egl_context_destroy(EGLDisplay dpy, EGLContext char *thread_id_c_str; thread_id_to_string(gettid(), thread_id_c_str); - jstring j_thread_id = GET_ENV()->NewStringUTF(thread_id_c_str); EGLContext egl_context = eglGetCurrentContext(); messages_containers ->enqueue_message((uintptr_t) egl_context, - [j_thread_id, egl_context]() { + [thread_id_c_str, egl_context]() { JNIEnv *env = GET_ENV(); + jstring j_thread_id = env->NewStringUTF(thread_id_c_str); env->CallStaticVoidMethod(class_OpenGLHook, method_onEglContextDestroy, j_thread_id, (jlong) egl_context); + + env->DeleteLocalRef(j_thread_id); }); } return ret; From 324bbeb5fc42fcc193d697864da5261a1b6c3597 Mon Sep 17 00:00:00 2001 From: opdeng Date: Mon, 31 Oct 2022 17:27:53 +0800 Subject: [PATCH 195/263] =?UTF-8?q?=E6=89=93=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java index 5bb3c9453..7c1de5599 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java @@ -115,8 +115,8 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_RENDERBUFFER, map.get(FuncNameString.GL_BIND_RENDERBUFFER)); OpenGLHook.getInstance().hook(FuncNameString.GL_BUFFER_DATA, map.get(FuncNameString.GL_BUFFER_DATA)); OpenGLHook.getInstance().hook(FuncNameString.GL_RENDER_BUFFER_STORAGE, map.get(FuncNameString.GL_RENDER_BUFFER_STORAGE)); -// OpenGLHook.getInstance().hookEglCreate(); -// OpenGLHook.getInstance().hookEglDestory(); + OpenGLHook.getInstance().hookEglCreate(); + OpenGLHook.getInstance().hookEglDestory(); MatrixLog.e(TAG, "hook finish"); } catch (Throwable e) { e.printStackTrace(); From c13b9d76cb0057a631d4bf1669f3255665165612 Mon Sep 17 00:00:00 2001 From: opdeng Date: Tue, 1 Nov 2022 17:35:12 +0800 Subject: [PATCH 196/263] disable isEglContextReleased --- .../statistics/resource/ResRecordManager.java | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java index f6170f600..8fb17fcf3 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java @@ -178,24 +178,25 @@ public void clear() { } public boolean isEglContextReleased(OpenGLInfo info) { - synchronized (mReleaseContext) { - long eglContextNativeHandle = info.getEglContextNativeHandle(); - if (0L == eglContextNativeHandle) { - return true; - } - - for (long item : mReleaseContext) { - if (item == eglContextNativeHandle) { - return true; - } - } - - boolean alive = OpenGLHook.isEglContextAlive(info.getEglContextNativeHandle()); - if (!alive) { - mReleaseContext.add(info.getEglContextNativeHandle()); - } - return !alive; - } + return false; +// synchronized (mReleaseContext) { +// long eglContextNativeHandle = info.getEglContextNativeHandle(); +// if (0L == eglContextNativeHandle) { +// return true; +// } +// +// for (long item : mReleaseContext) { +// if (item == eglContextNativeHandle) { +// return true; +// } +// } +// +// boolean alive = OpenGLHook.isEglContextAlive(info.getEglContextNativeHandle()); +// if (!alive) { +// mReleaseContext.add(info.getEglContextNativeHandle()); +// } +// return !alive; +// } } public boolean isEglSurfaceReleased(OpenGLInfo info) { From 777f31747190966bc3bd7d7b42d6ae08083f90a2 Mon Sep 17 00:00:00 2001 From: aurorani Date: Tue, 1 Nov 2022 20:50:11 +0800 Subject: [PATCH 197/263] feat: Remove unnecessary log printing from remove unused resources task. --- .../com/tencent/mm/arscutil/ArscUtil.java | 6 +-- .../MatrixRemoveUnusedResExtension.kt | 1 + .../task/RemoveUnusedResourcesTaskV2.kt | 50 ++++++++++++++----- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/matrix/matrix-android/matrix-arscutil/src/main/java/com/tencent/mm/arscutil/ArscUtil.java b/matrix/matrix-android/matrix-arscutil/src/main/java/com/tencent/mm/arscutil/ArscUtil.java index d666e4a1f..54c358e99 100644 --- a/matrix/matrix-android/matrix-arscutil/src/main/java/com/tencent/mm/arscutil/ArscUtil.java +++ b/matrix/matrix-android/matrix-arscutil/src/main/java/com/tencent/mm/arscutil/ArscUtil.java @@ -115,7 +115,7 @@ public static void removeResource(ResTable resTable, int resourceId, String reso resType.refresh(); } if (resNameStringPoolIndex != -1) { - Log.i(TAG, "try to remove %s (%H), find resource %s", resourceName, resourceId, ResStringBlock.resolveStringPoolEntry(resPackage.getResNamePool().getStrings().get(resNameStringPoolIndex).array(), resPackage.getResNamePool().getCharSet())); + Log.d(TAG, "try to remove %s (%H), find resource %s", resourceName, resourceId, ResStringBlock.resolveStringPoolEntry(resPackage.getResNamePool().getStrings().get(resNameStringPoolIndex).array(), resPackage.getResNamePool().getCharSet())); } resPackage.shrinkResNameStringPool(); resPackage.refresh(); @@ -126,7 +126,7 @@ public static void removeResource(ResTable resTable, int resourceId, String reso public static boolean replaceFileResource(ResTable resTable, int sourceResId, String sourceFile, int targetResId, String targetFile) throws IOException { int sourcePkgId = getPackageId(sourceResId); int targetPkgId = getPackageId(targetResId); - Log.i(TAG, "try to replace %H(%s) with %H(%s)", sourceResId, sourceFile, targetResId, targetFile); + Log.d(TAG, "try to replace %H(%s) with %H(%s)", sourceResId, sourceFile, targetResId, targetFile); if (sourcePkgId == targetPkgId) { ResPackage resPackage = findResPackage(resTable, sourcePkgId); if (resPackage != null) { @@ -252,7 +252,7 @@ public static void replaceResEntryName(ResTable resTable, Map r } public static boolean replaceResFileName(ResTable resTable, int resId, String srcFileName, String targetFileName) { - Log.i(TAG, "try to replace resource (%H) file %s with %s", resId, srcFileName, targetFileName); + Log.d(TAG, "try to replace resource (%H) file %s with %s", resId, srcFileName, targetFileName); ResPackage resPackage = findResPackage(resTable, getPackageId(resId)); boolean result = false; if (resPackage != null) { diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/extension/MatrixRemoveUnusedResExtension.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/extension/MatrixRemoveUnusedResExtension.kt index 1232274a6..4deb5364e 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/extension/MatrixRemoveUnusedResExtension.kt +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/extension/MatrixRemoveUnusedResExtension.kt @@ -38,6 +38,7 @@ open class MatrixRemoveUnusedResExtension( var embedResGuard: Boolean = false, var sevenZipPath: String = "", var zipAlignPath: String = "", + var report: String? = null, // Deprecated var unusedResources: HashSet = HashSet() diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt index ae7703944..778a052fb 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt @@ -82,6 +82,8 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { private lateinit var rulesOfIgnore: Set + private var reportFile: File? = null + fun overrideInputApkFiles(inputApkFiles: List) { this.overrideInputApkFiles = inputApkFiles.map { File(it) } } @@ -140,6 +142,13 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { task.pathOfSevenZip = sevenZipPath task.rulesOfIgnore = ignoreResources + + task.reportFile = report?.let { + File(it).apply { + parentFile.mkdirs() + if (exists()) delete() + } + } } task.parametersInvalidation() @@ -254,10 +263,10 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { val resourceName = ApkUtil.entryToResourceName(zipEntry.name, resguardMapping) if (!Util.isNullOrNil(resourceName)) { if (mapOfResourcesGonnaRemoved.containsKey(resourceName)) { - Log.i(TAG, "remove unused resource %s file %s", resourceName, zipEntry.name) + Log.d(TAG, "remove unused resource %s file %s", resourceName, zipEntry.name) continue } else if (mapOfDuplicatesReplacements.containsKey(zipEntry.name)) { - Log.i(TAG, "remove duplicated resource file %s", zipEntry.name) + Log.d(TAG, "remove duplicated resource file %s", zipEntry.name) continue } else { if (arsc != null && isResGuardEnabled) { @@ -269,7 +278,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { val proguardDir = dirProguard.generateNextProguardFileName() resultOfObfuscatedDirs[dir] = "$RES_DIR_PROGUARD_NAME/$proguardDir" dirFileProguard[dir] = ProguardStringBuilder() - Log.i(TAG, "dir %s, proguard builder", dir) + Log.d(TAG, "dir %s, proguard builder", dir) } resultOfObfuscatedFiles[zipEntry.name] = resultOfObfuscatedDirs[dir] + "/" + dirFileProguard[dir]!!.generateNextProguardFileName() + suffix val success = ArscUtil.replaceResFileName(resTable, mapOfResources[resourceName]!!, zipEntry.name, resultOfObfuscatedFiles[zipEntry.name]) @@ -316,7 +325,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { ApkUtil.sevenZipFile(pathOfSevenZip, unzipDir.canonicalPath + "${File.separator}*", toShrunkApkFile.canonicalPath, false) if (compressedEntry.isNotEmpty()) { - Log.i(TAG, "7zip %d DEFLATED files to apk", compressedEntry.size) + Log.d(TAG, "7zip %d DEFLATED files to apk", compressedEntry.size) val deflateDir = File(fromOriginalApkFile.parentFile, fromOriginalApkFile.name.substring(0, fromOriginalApkFile.name.lastIndexOf(".")) + "_deflated") FileUtils.deleteRecursivelyIfExists(deflateDir) deflateDir.mkdir() @@ -358,7 +367,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { } else { val zipEntry = ZipEntry(file.canonicalPath.substring(rootDir.length + 1)) val method = if (compressedEntry.contains(file.canonicalPath)) ZipEntry.DEFLATED else ZipEntry.STORED - Log.i(TAG, "zip file %s -> entry %s, DEFLATED %s", file.canonicalPath, zipEntry.name, method == ZipEntry.DEFLATED) + Log.d(TAG, "zip file %s -> entry %s, DEFLATED %s", file.canonicalPath, zipEntry.name, method == ZipEntry.DEFLATED) zipEntry.method = method ApkUtil.addZipEntry(zipOutputStream, zipEntry, file) } @@ -511,7 +520,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { resultOfResourcesGonnaRemoved[resName] = resId } } else { - Log.i(TAG, "ignore remove unused resources %s", resName) + Log.d(TAG, "ignore remove unused resources %s", resName) } } @@ -551,7 +560,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { val replace = it.next() while (it.hasNext()) { val dup = it.next() - Log.i(TAG, "replace %s with %s", dup, replace) + Log.d(TAG, "replace %s with %s", dup, replace) resultOfDuplicatesReplacements[dup] = replace } } @@ -579,7 +588,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { if (!checkIfIgnored(resName, regexpRules)) { resultOfObfuscatedNames[resName] = "R." + resType + "." + resTypeBuilder.generateNextProguard() } else { - Log.i(TAG, "ignore proguard resource name %s", resName) + Log.d(TAG, "ignore proguard resource name %s", resName) } } } @@ -609,7 +618,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { } } if (attrs.isNotEmpty() && j == attrs.size) { - Log.i(TAG, "removed styleable $styleable") + Log.d(TAG, "removed styleable $styleable") styleableIterator.remove() } } @@ -704,7 +713,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { Log.i(TAG, "find out %d unused resources:\n %s", setOfUnusedResources.size, setOfUnusedResources) Log.i(TAG, "find out %d duplicated resources:", mapOfDuplicatedResources.size) for (md5 in mapOfDuplicatedResources.keys) { - Log.i(TAG, "> md5:%s, files:%s", md5, mapOfDuplicatedResources[md5]) + Log.d(TAG, "> md5:%s, files:%s", md5, mapOfDuplicatedResources[md5]) } Log.i(TAG, "find unused resources cost time %fs ", (System.currentTimeMillis() - startTime) / 1000.0f) @@ -763,7 +772,7 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { // Zip align if (isZipAlignEnabled) { val alignedApk = originalApkFile.parentFile.canonicalPath + File.separator + originalApkFile.name.substring(0, originalApkFile.name.indexOf(".")) + "_aligned.apk" - Log.i(TAG, "Zipalign apk...") + Log.d(TAG, "Zipalign apk...") ApkUtil.zipAlignApk(shrunkApkPath, alignedApk, pathOfZipAlign) shrunkApkFile.delete() FileUtils.copyFile(File(alignedApk), shrunkApkFile) @@ -772,10 +781,27 @@ abstract class RemoveUnusedResourcesTaskV2 : DefaultTask() { // Signing apk if (isSigningEnabled) { - Log.i(TAG, "Signing apk...") + Log.d(TAG, "Signing apk...") ApkUtil.signApk(shrunkApkPath, pathOfApkSigner, signingConfig) } + reportFile?.bufferedWriter()?.use { writer -> + writer.write("removed resources:") + writer.newLine() + mapOfResourcesGonnaRemoved.keys.forEach { name -> + writer.write(" $name") + writer.newLine() + } + writer.newLine() + + writer.write("duplicated resources:") + writer.newLine() + mapOfDuplicatesReplacements.forEach { (origin, replacement) -> + writer.write(" $origin -> $replacement") + writer.newLine() + } + } + // Backup original apk and swap shrunk apk FileUtils.copyFile(originalApkFile, File(fileOfBackup, "backup.apk")) originalApkFile.delete() From e56faf6e20f5fd8a8ee438e02134fd9b0cc4103f Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 3 Nov 2022 17:55:26 +0800 Subject: [PATCH 198/263] opengl-hook: change gettid api --- .../matrix-opengl-leak/src/main/cpp/my_functions.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h index 4572bff79..dd1c7dc33 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h @@ -16,7 +16,6 @@ #include #include "StackMeta.h" #include -#include #ifndef OPENGL_API_HOOK_MY_FUNCTIONS_H #define OPENGL_API_HOOK_MY_FUNCTIONS_H @@ -198,7 +197,7 @@ gen_jni_callback(int alloc_count, GLuint *copy_resource, int throwable, const th env->SetIntArrayRegion(newArr, 0, alloc_count, result); char *thread_id_c_str; - thread_id_to_string(gettid(), thread_id_c_str); + thread_id_to_string(pthread_gettid_np(pthread_self()), thread_id_c_str); jstring j_thread_id = env->NewStringUTF(thread_id_c_str); jstring j_activity_info = env->NewStringUTF(activity_info); @@ -247,7 +246,7 @@ void delete_jni_callback(int delete_count, GLuint *copy_resource, const thread:: env->SetIntArrayRegion(newArr, 0, delete_count, result); char *thread_id_c_str; - thread_id_to_string(gettid(), thread_id_c_str); + thread_id_to_string(pthread_gettid_np(pthread_self()), thread_id_c_str); jstring j_thread_id = env->NewStringUTF(thread_id_c_str); env->CallStaticVoidMethod(class_OpenGLHook, @@ -825,7 +824,7 @@ my_egl_context_create(EGLDisplay dpy, EGLConfig config, EGLContext share_context int throwable = get_java_throwable(); char *thread_id_c_str; - thread_id_to_string(gettid(), thread_id_c_str); + thread_id_to_string(pthread_gettid_np(pthread_self()), thread_id_c_str); char *activity_info = static_cast(malloc(BUF_SIZE)); if (curr_activity_info != nullptr) { @@ -874,7 +873,7 @@ EGLAPI EGLBoolean EGLAPIENTRY my_egl_context_destroy(EGLDisplay dpy, EGLContext } char *thread_id_c_str; - thread_id_to_string(gettid(), thread_id_c_str); + thread_id_to_string(pthread_gettid_np(pthread_self()), thread_id_c_str); EGLContext egl_context = eglGetCurrentContext(); From 38d29536f80394f8ea10417558f9f885a0a431a5 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 3 Nov 2022 19:03:54 +0800 Subject: [PATCH 199/263] opengl-hook: fix compile error --- matrix/matrix-android/matrix-opengl-leak/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/build.gradle b/matrix/matrix-android/matrix-opengl-leak/build.gradle index e44c150f6..0ffb14c84 100644 --- a/matrix/matrix-android/matrix-opengl-leak/build.gradle +++ b/matrix/matrix-android/matrix-opengl-leak/build.gradle @@ -7,7 +7,7 @@ android { buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion + minSdkVersion MIN_SDK_VERSION_FOR_HOOK targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName rootProject.ext.VERSION_NAME From f49a30a2f38ed2b00136f05038217495c49330bd Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 4 Nov 2022 11:29:42 +0800 Subject: [PATCH 200/263] MemInfo: add Process Pid to Log --- .../src/main/java/com/tencent/matrix/util/MemInfoFactory.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt index 3f3d3d62f..cfec82108 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt @@ -64,11 +64,12 @@ data class ProcessInfo( override fun toString(): String { return String.format( - "%-21s\t%-21s %-21s %-21s", + "%-21s\t%-21s %-21s %-21s %-21s", name, "Activity=$activity", "AppForeground=$isAppFg", - "ProcessForeground=$isProcessFg" + "ProcessForeground=$isProcessFg", + "Pid=$pid" ) } From 52fc2acb3e412da0799901b1546d8bd608130c0b Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 4 Nov 2022 20:39:07 +0800 Subject: [PATCH 201/263] Fix battery full charged event overheat bug --- .../batterycanary/BatteryEventDelegate.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java index 3f7219f0c..e55051a26 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryEventDelegate.java @@ -155,17 +155,6 @@ public void onReceive(Context context, final Intent intent) { // Received 'ACTION_BATTERY_CHANGED' frequently, // should be frequency-controlled & handled with worker thread if (mCore != null) { - int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); - if (status == BatteryManager.BATTERY_STATUS_FULL) { - mCore.getHandler().post(new Runnable() { - @Override - public void run() { - onBatteryFullCharged(); - } - }); - return; - } - boolean limited = false; long currMs = System.currentTimeMillis(); if (mLastBatteryChangedHandleMs > 0 && currMs - mLastBatteryChangedHandleMs < ONE_MIN) { @@ -176,6 +165,13 @@ public void run() { mCore.getHandler().post(new Runnable() { @Override public void run() { + // Full charged + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + if (status == BatteryManager.BATTERY_STATUS_FULL) { + onBatteryFullCharged(); + return; + } + // Power percentage int currPct = BatteryCanaryUtil.getBatteryPercentage(mContext); if (currPct >= 0 && currPct <= 1000) { @@ -190,6 +186,7 @@ public void run() { onBatteryPowerChanged(currPct); } } + // Battery temperature try { int currTemp = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1); From ee54ea0ecf94ad082baff14b1c0ed98dfa634e7f Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 9 Nov 2022 15:25:00 +0800 Subject: [PATCH 202/263] =?UTF-8?q?=E6=97=B6=E5=BA=8F=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix-opengl-leak/src/main/cpp/my_functions.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h index 4572bff79..dc19491b6 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h @@ -876,11 +876,9 @@ EGLAPI EGLBoolean EGLAPIENTRY my_egl_context_destroy(EGLDisplay dpy, EGLContext char *thread_id_c_str; thread_id_to_string(gettid(), thread_id_c_str); - EGLContext egl_context = eglGetCurrentContext(); - messages_containers - ->enqueue_message((uintptr_t) egl_context, - [thread_id_c_str, egl_context]() { + ->enqueue_message((uintptr_t) ctx, + [thread_id_c_str, ctx]() { JNIEnv *env = GET_ENV(); jstring j_thread_id = env->NewStringUTF(thread_id_c_str); @@ -888,7 +886,7 @@ EGLAPI EGLBoolean EGLAPIENTRY my_egl_context_destroy(EGLDisplay dpy, EGLContext env->CallStaticVoidMethod(class_OpenGLHook, method_onEglContextDestroy, j_thread_id, - (jlong) egl_context); + (jlong) ctx); env->DeleteLocalRef(j_thread_id); }); From 646e8db377ffc4d3d785dbc22f54dde633c2de59 Mon Sep 17 00:00:00 2001 From: aurorani Date: Tue, 15 Nov 2022 23:01:21 +0800 Subject: [PATCH 203/263] fix: Fix remove unused resources resguard-mapping parsing error. --- .../src/main/java/com/tencent/matrix/shrinker/ApkUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java index ce5bf720c..63c440dc1 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java @@ -93,7 +93,7 @@ public static String parseEntryResourceType(String entry) { int prefixLength = entry.indexOf('/'); if (prefixLength == -1) return ""; if (!Util.isNullOrNil(entry)) { - String typeName = entry.substring(prefixLength, entry.lastIndexOf('/')); + String typeName = entry.substring(prefixLength + 1, entry.lastIndexOf('/')); if (!Util.isNullOrNil(typeName)) { int index = typeName.indexOf('-'); if (index >= 0) { From 30f4d7fc8f47bc0738a8aba3793787cfc9a2f95c Mon Sep 17 00:00:00 2001 From: tangyinsheng Date: Thu, 17 Nov 2022 02:49:03 +0800 Subject: [PATCH 204/263] [runtime_verify_mute] Add first version. --- matrix/matrix-android/gradle.properties | 2 +- .../matrix-hooks/CMakeLists.txt | 17 +++++ .../src/main/cpp/art/RuntimeVerifyMute.cpp | 69 +++++++++++++++++++ .../src/main/cpp/art/RuntimeVerifyMute.h | 16 +++++ .../src/main/cpp/art/RuntimeVerifyMuteJNI.cpp | 11 +++ .../src/main/cpp/art/art_misc.ver | 6 ++ .../matrix/hook/art/RuntimeVerifyMute.java | 56 +++++++++++++++ 7 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp create mode 100644 matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.h create mode 100644 matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMuteJNI.cpp create mode 100644 matrix/matrix-android/matrix-hooks/src/main/cpp/art/art_misc.ver create mode 100644 matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/art/RuntimeVerifyMute.java diff --git a/matrix/matrix-android/gradle.properties b/matrix/matrix-android/gradle.properties index 8baf7a8d9..5c014a977 100644 --- a/matrix/matrix-android/gradle.properties +++ b/matrix/matrix-android/gradle.properties @@ -15,7 +15,7 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro #Tue Jun 20 10:24:33 CST 2017 VERSION_NAME_PREFIX=2.0.8 -VERSION_NAME_SUFFIX= +VERSION_NAME_SUFFIX=-TOMv1 ## two options: Internal (for wechat), External (for public repo) PUBLISH_CHANNEL=Internal android.useAndroidX=true diff --git a/matrix/matrix-android/matrix-hooks/CMakeLists.txt b/matrix/matrix-android/matrix-hooks/CMakeLists.txt index 209eb6620..293ab5e25 100644 --- a/matrix/matrix-android/matrix-hooks/CMakeLists.txt +++ b/matrix/matrix-android/matrix-hooks/CMakeLists.txt @@ -95,4 +95,21 @@ target_link_libraries( PRIVATE matrix-hookcommon PRIVATE -Wl,--version-script=${SOURCE_DIR}/pthread/pthread.ver ) +################################################################################# + +################################# ART Misc ################################## +set(TARGET matrix-artmisc) + +add_library( + ${TARGET} + SHARED + ${SOURCE_DIR}/art/RuntimeVerifyMuteJNI.cpp + ${SOURCE_DIR}/art/RuntimeVerifyMute.cpp +) + +target_link_libraries( + ${TARGET} + PRIVATE matrix-hookcommon + PRIVATE -Wl,--version-script=${SOURCE_DIR}/art/art_misc.ver +) ################################################################################# \ No newline at end of file diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp new file mode 100644 index 000000000..0333ea1a3 --- /dev/null +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp @@ -0,0 +1,69 @@ +// +// Created by tomystang on 2022/11/17. +// + +#include +#include +#include +#include +#include +#include +#include +#include "RuntimeVerifyMute.h" + +#define LOG_TAG "Matrix.RuntimeVerifyMute" + +static bool sInitialized = false; +static std::mutex sInitLock; + +bool matrix::art_misc::Install(JNIEnv* env) { + if (sInitialized) { + LOGI(LOG_TAG, "[!] Already installed."); + return true; + } + std::lock_guard lock(sInitLock); + if (sInitialized) { + LOGI(LOG_TAG, "[!] Already installed."); + return true; + } + + int sdk_ver = android_get_device_api_level(); + if (sdk_ver == -1) { + LOGE(LOG_TAG, "[-] Fail to get sdk version."); + return false; + } + if (sdk_ver < __ANDROID_API_Q__) { + LOGE(LOG_TAG, "[-] SDK version is lower than Q."); + return false; + } + + void* h_libart = semi_dlopen("libart.so"); + if (h_libart == nullptr) { + LOGE(LOG_TAG, "[-] Fail to open libart.so."); + return false; + } + auto h_libart_cleaner = MakeScopedCleaner([&h_libart]() { + if (h_libart != nullptr) { + semi_dlclose(h_libart); + } + }); + + void** art_runtime_instance_ptr = + reinterpret_cast(semi_dlsym(h_libart, "_ZN3art7Runtime9instance_E")); + if (art_runtime_instance_ptr == nullptr) { + LOGE(LOG_TAG, "[-] Fail to find Runtime::instance_."); + return false; + } + void (*art_runtime_disable_verifier_fn)(void*) = + reinterpret_cast(semi_dlsym(h_libart, "_ZN3art7Runtime15DisableVerifierEv")); + if (art_runtime_disable_verifier_fn == nullptr) { + LOGE(LOG_TAG, "[-] Fail to find Runtime::DisableVerifier()."); + return false; + } + + art_runtime_disable_verifier_fn(*art_runtime_instance_ptr); + + LOGI(LOG_TAG, "[+] Runtime::DisableVerifier() was invoked."); + + return true; +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.h b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.h new file mode 100644 index 000000000..60c62426c --- /dev/null +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.h @@ -0,0 +1,16 @@ +// +// Created by tomystang on 2022/11/17. +// + +#ifndef MATRIX_ANDROID_RUNTIMEVERIFYMUTE_H +#define MATRIX_ANDROID_RUNTIMEVERIFYMUTE_H + + +namespace matrix { + namespace art_misc { + bool Install(JNIEnv* env); + } +} + + +#endif //MATRIX_ANDROID_RUNTIMEVERIFYMUTE_H diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMuteJNI.cpp b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMuteJNI.cpp new file mode 100644 index 000000000..0111fb7c8 --- /dev/null +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMuteJNI.cpp @@ -0,0 +1,11 @@ +// +// Created by tomystang on 2022/11/17. +// + +#include +#include "RuntimeVerifyMute.h" + +extern "C" jboolean JNIEXPORT +Java_com_tencent_matrix_hook_art_RuntimeVerifyMute_nativeInstall(JNIEnv* env, jobject) { + return matrix::art_misc::Install(env) ? JNI_TRUE : JNI_FALSE; +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/art/art_misc.ver b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/art_misc.ver new file mode 100644 index 000000000..9490940fd --- /dev/null +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/art_misc.ver @@ -0,0 +1,6 @@ +{ + global: + JNI_OnLoad; + JNI_OnUnload; + Java_*; +}; \ No newline at end of file diff --git a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/art/RuntimeVerifyMute.java b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/art/RuntimeVerifyMute.java new file mode 100644 index 000000000..07efcc95f --- /dev/null +++ b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/art/RuntimeVerifyMute.java @@ -0,0 +1,56 @@ +package com.tencent.matrix.hook.art; + +import androidx.annotation.Nullable; + +import com.tencent.matrix.hook.HookManager.NativeLibraryLoader; +import com.tencent.matrix.util.MatrixLog; + +/** + * Created by tomystang on 2022/11/16. + */ +public final class RuntimeVerifyMute { + private static final String TAG = "Matrix.RuntimeVerifyMute"; + + public static final RuntimeVerifyMute INSTANCE = new RuntimeVerifyMute(); + + private NativeLibraryLoader mNativeLibLoader = null; + private boolean mNativeLibLoaded = false; + + public RuntimeVerifyMute setNativeLibraryLoader(@Nullable NativeLibraryLoader loader) { + mNativeLibLoader = loader; + return this; + } + + private boolean ensureNativeLibLoaded() { + synchronized (this) { + if (mNativeLibLoaded) { + return true; + } + try { + if (mNativeLibLoader != null) { + mNativeLibLoader.loadLibrary("matrix-hookcommon"); + mNativeLibLoader.loadLibrary("matrix-artmisc"); + } else { + System.loadLibrary("matrix-hookcommon"); + System.loadLibrary("matrix-artmisc"); + } + mNativeLibLoaded = true; + } catch (Throwable thr) { + MatrixLog.printErrStackTrace(TAG, thr, "Fail to load native library."); + mNativeLibLoaded = false; + } + return mNativeLibLoaded; + } + } + + public boolean install() { + if (!ensureNativeLibLoaded()) { + return false; + } + return nativeInstall(); + } + + private static native boolean nativeInstall(); + + private RuntimeVerifyMute() { } +} From eecc1c112a907e1f2038f64cfe1fe479ce39c721 Mon Sep 17 00:00:00 2001 From: aurorani Date: Wed, 16 Nov 2022 13:00:45 +0800 Subject: [PATCH 205/263] fix: Fix attribute type omitted. --- .../apk/model/task/util/XmlPullResourceRefDecoder.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/XmlPullResourceRefDecoder.java b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/XmlPullResourceRefDecoder.java index c160884b2..9df230a68 100644 --- a/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/XmlPullResourceRefDecoder.java +++ b/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/util/XmlPullResourceRefDecoder.java @@ -93,6 +93,16 @@ private void handleElement() { int index = value.indexOf('/'); if (index > 1) { resourceRefSet.add(ApkConstants.R_ATTR_PREFIX + "." + value.substring(index + 1).replace('.', '_')); + } else { + // Attribute reference may be omitted the type, for example: + // ?attr/xxx -> ?xxx + // ?android:attr/xxx -> ?android:xxx + int colonIndex = value.indexOf(':'); + if (colonIndex > 1) { + resourceRefSet.add(ApkConstants.R_ATTR_PREFIX + value.substring(colonIndex + 1).replace('.', '_')); + } else { + resourceRefSet.add(ApkConstants.R_ATTR_PREFIX + value.substring(1).replace('.', '_')); + } } } } From c86f237b3a4cdb29fd88433de34fbf1b5d060611 Mon Sep 17 00:00:00 2001 From: opdeng Date: Thu, 17 Nov 2022 11:42:33 +0800 Subject: [PATCH 206/263] add log --- .../statistics/resource/ResRecordManager.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java index 8fb17fcf3..968ac51a0 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java @@ -348,6 +348,7 @@ public String dumpGLToString() { List bufferList = new ArrayList<>(); List framebufferList = new ArrayList<>(); List renderbufferList = new ArrayList<>(); + List eglContextList = new ArrayList<>(); for (OpenGLDumpInfo reportInfo : infoMap.values()) { if (reportInfo.innerInfo.getType() == OpenGLInfo.TYPE.TEXTURE) { @@ -362,6 +363,9 @@ public String dumpGLToString() { if (reportInfo.innerInfo.getType() == OpenGLInfo.TYPE.RENDER_BUFFERS) { renderbufferList.add(reportInfo); } + if (reportInfo.innerInfo.getType() == OpenGLInfo.TYPE.EGL_CONTEXT) { + eglContextList.add(reportInfo); + } } Comparator comparator = new Comparator() { @@ -381,6 +385,7 @@ public int compare(OpenGLDumpInfo o1, OpenGLDumpInfo o2) { Collections.sort(bufferList, comparator); Collections.sort(framebufferList, comparator); Collections.sort(renderbufferList, comparator); + Collections.sort(eglContextList, comparator); AutoWrapBuilder builder = new AutoWrapBuilder(); builder.appendDotted() @@ -388,6 +393,7 @@ public int compare(OpenGLDumpInfo o1, OpenGLDumpInfo o2) { .appendWithSpace(String.format("buffer Count = %d", bufferList.size()), 3) .appendWithSpace(String.format("framebuffer Count = %d", framebufferList.size()), 3) .appendWithSpace(String.format("renderbuffer Count = %d", renderbufferList.size()), 3) + .appendWithSpace(String.format("egl context Count = %d", eglContextList.size()), 3) .appendDotted() .appendWave() .appendWithSpace("texture part :", 3) @@ -401,6 +407,10 @@ public int compare(OpenGLDumpInfo o1, OpenGLDumpInfo o2) { .appendWithSpace("renderbuffer part :", 3) .appendWave() .append(getResListString(renderbufferList)) + .appendWave() + .appendWithSpace("egl context part :", 3) + .appendWave() + .append(getResListString(eglContextList)) .wrap(); return builder.toString(); From d6c4754064316d1ef990d7621e662b73d11db295 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 18 Nov 2022 20:08:40 +0800 Subject: [PATCH 207/263] ManualDumpProcessor: fix api-31 compatibility issue --- .../tencent/matrix/resource/processor/ManualDumpProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java index 578b862ce..c98b8f1dd 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java @@ -96,7 +96,7 @@ private void sendResultNotification(DestroyedActivityInfo activityInfo, String h targetIntent.putExtra(SharePluginInfo.ISSUE_HPROF_PATH, hprofPath); targetIntent.putExtra(SharePluginInfo.ISSUE_LEAK_DETAIL, refChain); - PendingIntent pIntent = PendingIntent.getActivity(context, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pIntent = PendingIntent.getActivity(context, 0, targetIntent, Build.VERSION.SDK_INT >= 31 ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT); String dumpingHeapTitle = context.getString(R.string.resource_canary_leak_tip); ResourceConfig config = getWatcher().getResourcePlugin().getConfig(); From b7334ee4945df815a853fbae988b57a4d67ebd1b Mon Sep 17 00:00:00 2001 From: tomystang Date: Sun, 20 Nov 2022 02:34:25 +0800 Subject: [PATCH 208/263] [runtime_verify_mute] Adjust min support version to P. --- .../matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp index 0333ea1a3..0f0a8a1d6 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp @@ -32,7 +32,7 @@ bool matrix::art_misc::Install(JNIEnv* env) { LOGE(LOG_TAG, "[-] Fail to get sdk version."); return false; } - if (sdk_ver < __ANDROID_API_Q__) { + if (sdk_ver < __ANDROID_API_P__) { LOGE(LOG_TAG, "[-] SDK version is lower than Q."); return false; } From 134ceb6b56445dc61f29fd7436343662da2939c4 Mon Sep 17 00:00:00 2001 From: tomystang Date: Sun, 20 Nov 2022 02:35:01 +0800 Subject: [PATCH 209/263] [runtime_verify_mute] Remove version suffix. --- matrix/matrix-android/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/gradle.properties b/matrix/matrix-android/gradle.properties index 5c014a977..8baf7a8d9 100644 --- a/matrix/matrix-android/gradle.properties +++ b/matrix/matrix-android/gradle.properties @@ -15,7 +15,7 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro #Tue Jun 20 10:24:33 CST 2017 VERSION_NAME_PREFIX=2.0.8 -VERSION_NAME_SUFFIX=-TOMv1 +VERSION_NAME_SUFFIX= ## two options: Internal (for wechat), External (for public repo) PUBLISH_CHANNEL=Internal android.useAndroidX=true From 0559e10d13933c8079c486b25e5eb78720d4dc2a Mon Sep 17 00:00:00 2001 From: tomystang Date: Sun, 20 Nov 2022 06:43:40 +0800 Subject: [PATCH 210/263] [runtime_verify_mute] Fix log typo. --- .../matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp index 0f0a8a1d6..748f4e524 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/art/RuntimeVerifyMute.cpp @@ -33,7 +33,7 @@ bool matrix::art_misc::Install(JNIEnv* env) { return false; } if (sdk_ver < __ANDROID_API_P__) { - LOGE(LOG_TAG, "[-] SDK version is lower than Q."); + LOGE(LOG_TAG, "[-] SDK version is lower than P."); return false; } From 1e6b9ce172fdbcfa0340257c5600bc110f2ef054 Mon Sep 17 00:00:00 2001 From: nalecyxu Date: Sun, 20 Nov 2022 16:57:39 +0800 Subject: [PATCH 211/263] [RUR] change sevenZip level -mx9 to -mx5 --- .../src/main/java/com/tencent/matrix/shrinker/ApkUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java index ce5bf720c..fa2d807cf 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/shrinker/ApkUtil.java @@ -216,7 +216,7 @@ public static void sevenZipFile(String sevenZipPath, String inputFile, String ou new File(sevenZipPath).setExecutable(true); } ProcessBuilder processBuilder = new ProcessBuilder(); - processBuilder.command(sevenZipPath, "a", "-tzip", outputFile, inputFile, deflated ? "-mx9" : "-mx0"); + processBuilder.command(sevenZipPath, "a", "-tzip", outputFile, inputFile, deflated ? "-mx5" : "-mx0"); //Log.i(TAG, "%s", processBuilder.command()) Process process = processBuilder.start(); // process.waitForProcessOutput(System.out, System.err); From 0dfc9f73831b3d53589b5b78de8ed87d38abf03a Mon Sep 17 00:00:00 2001 From: yvesluo Date: Mon, 28 Nov 2022 15:55:53 +0800 Subject: [PATCH 212/263] matrix-hooks: weird NPE protection -- Thread.currentThread() is NULL --- .../src/main/java/com/tencent/matrix/hook/HookManager.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/HookManager.java b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/HookManager.java index 5db9f99db..ab8098b55 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/HookManager.java +++ b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/HookManager.java @@ -160,7 +160,12 @@ public HookManager clearHooks() { @Keep public static String getStack() { - return stackTraceToString(Thread.currentThread().getStackTrace()); + try { + return stackTraceToString(Thread.currentThread().getStackTrace()); + } catch (Throwable e) { + MatrixLog.printErrStackTrace(TAG, e, ""); + return ""; + } } private static String stackTraceToString(final StackTraceElement[] arr) { From ec1ea8a769696cf9eb04844a0163b317ed25a740 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 30 Nov 2022 20:19:03 +0800 Subject: [PATCH 213/263] MemInfoFactory: fix NumberFormatException --- .../com/tencent/matrix/util/MemInfoFactory.kt | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt index cfec82108..a76abd72b 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt @@ -238,21 +238,21 @@ data class PssInfo( data class StatusInfo( val state: String = "default", - val fdSize: Int = -1, - val vmSizeK: Int = -1, - val vmRssK: Int = -1, - val vmSwapK: Int = -1, - val threads: Int = -1, + val fdSize: Long = -1, + val vmSizeK: Long = -1, + val vmRssK: Long = -1, + val vmSwapK: Long = -1, + val threads: Long = -1, val oomAdj: Int = -1, val oomScoreAdj: Int = -1 ) : Parcelable { constructor(parcel: Parcel) : this( parcel.readString() ?: "default", - parcel.readInt(), - parcel.readInt(), - parcel.readInt(), - parcel.readInt(), - parcel.readInt(), + parcel.readLong(), + parcel.readLong(), + parcel.readLong(), + parcel.readLong(), + parcel.readLong(), parcel.readInt(), parcel.readInt() ) @@ -287,26 +287,26 @@ data class StatusInfo( companion object { @JvmStatic fun get(pid: Int = Process.myPid()): StatusInfo { - return convertProcStatus(pid).run { + return convertProcStatus(pid).safeLet(TAG, defVal = StatusInfo()) { fun Map.getString(key: String) = get(key) ?: "unknown" - fun Map.getInt(key: String): Int { + fun Map.getInt(key: String): Long { getString(key).let { val matcher = Pattern.compile("\\d+").matcher(it) while (matcher.find()) { - return matcher.group().toInt() + return matcher.group().toLong() } } return -2 } StatusInfo( - state = getString("State").trimIndent(), - fdSize = getInt("FDSize"), - vmSizeK = getInt("VmSize"), - vmRssK = getInt("VmRSS"), - vmSwapK = getInt("VmSwap"), - threads = getInt("Threads"), + state = it.getString("State").trimIndent(), + fdSize = it.getInt("FDSize"), + vmSizeK = it.getInt("VmSize"), + vmRssK = it.getInt("VmRSS"), + vmSwapK = it.getInt("VmSwap"), + threads = it.getInt("Threads"), oomAdj = getOomAdj(pid), oomScoreAdj = getOomScoreAdj(pid) ) @@ -357,11 +357,11 @@ data class StatusInfo( override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeString(state) - parcel.writeInt(fdSize) - parcel.writeInt(vmSizeK) - parcel.writeInt(vmRssK) - parcel.writeInt(vmSwapK) - parcel.writeInt(threads) + parcel.writeLong(fdSize) + parcel.writeLong(vmSizeK) + parcel.writeLong(vmRssK) + parcel.writeLong(vmSwapK) + parcel.writeLong(threads) parcel.writeInt(oomAdj) parcel.writeInt(oomScoreAdj) } From ac659c4125e859cf780664a3d70368479d323710 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 30 Nov 2022 21:17:09 +0800 Subject: [PATCH 214/263] sample: fix compile error --- .../matrix/resource/ManualDumpActivity.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/resource/ManualDumpActivity.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/resource/ManualDumpActivity.java index bb589d5e6..cf6018121 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/resource/ManualDumpActivity.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/resource/ManualDumpActivity.java @@ -28,14 +28,14 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { ((TextView) findViewById(R.id.leak_process)) .setText(getIntent().getStringExtra(SharePluginInfo.ISSUE_LEAK_PROCESS)); - final ManualDumpProcessor.ManualDumpData data = - getIntent().getParcelableExtra(SharePluginInfo.ISSUE_DUMP_DATA); - if (data != null) { - ((TextView) findViewById(R.id.reference_chain)) - .setText(data.refChain); - } else { - ((TextView) findViewById(R.id.reference_chain)) - .setText(R.string.empty_reference_chain); - } +// final ManualDumpProcessor.ManualDumpData data = +// getIntent().getParcelableExtra(SharePluginInfo.ISSUE_DUMP_DATA); +// if (data != null) { +// ((TextView) findViewById(R.id.reference_chain)) +// .setText(data.refChain); +// } else { +// ((TextView) findViewById(R.id.reference_chain)) +// .setText(R.string.empty_reference_chain); +// } } } From fa7b17fb7f4ba8f463c6e212c090684828d71e9a Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 2 Dec 2022 00:38:45 +0800 Subject: [PATCH 215/263] matrix-hooks: fix linker deadlock caused by hook --- .../matrix-hooks/CMakeLists.txt | 2 + .../src/main/cpp/common/HookCommon.h | 21 +++-- .../main/cpp/memory/MemoryHookFunctions.cpp | 84 ++++++++++--------- .../src/main/cpp/pthread/PthreadHook.cpp | 11 +-- .../java/com/tencent/matrix/hook/AbsHook.java | 4 +- .../com/tencent/matrix/hook/HookManager.java | 47 +++++++++++ .../matrix/hook/memory/MemoryHook.java | 4 +- .../matrix/hook/memory/WVPreAllocHook.java | 4 +- .../matrix/hook/pthread/PthreadHook.java | 2 +- 9 files changed, 118 insertions(+), 61 deletions(-) diff --git a/matrix/matrix-android/matrix-hooks/CMakeLists.txt b/matrix/matrix-android/matrix-hooks/CMakeLists.txt index 293ab5e25..48486ca39 100644 --- a/matrix/matrix-android/matrix-hooks/CMakeLists.txt +++ b/matrix/matrix-android/matrix-hooks/CMakeLists.txt @@ -74,6 +74,7 @@ add_library( target_link_libraries( ${TARGET} PRIVATE matrix-hookcommon + PRIVATE -Wl,--whole-archive ${EXT_DEP}/lib/${ANDROID_ABI}/libsemi_dlfcn.a -Wl,--no-whole-archive PRIVATE -Wl,--version-script=${SOURCE_DIR}/memory/memory.ver ) ################################################################################# @@ -93,6 +94,7 @@ add_library( target_link_libraries( ${TARGET} PRIVATE matrix-hookcommon + PRIVATE -Wl,--whole-archive ${EXT_DEP}/lib/${ANDROID_ABI}/libsemi_dlfcn.a -Wl,--no-whole-archive PRIVATE -Wl,--version-script=${SOURCE_DIR}/pthread/pthread.ver ) ################################################################################# diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h b/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h index a6642e099..ebdfb9d96 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h @@ -27,6 +27,7 @@ #include #include "JNICommon.h" #include "Macros.h" +#include "semi_dlfcn.h" // 0x01 was occupied by thread priority trace hook in MatrixTracer.cc. #define HOOK_REQUEST_GROUPID_DLOPEN_MON 0x02 @@ -62,20 +63,24 @@ } \ } -#define CALL_ORIGIN_FUNC_RET(retType, ret, sym, params...) \ - if (!ORIGINAL_FUNC_NAME(sym)) { \ - void *handle = dlopen(ORIGINAL_LIB, RTLD_LAZY); \ +#define CALL_ORIGIN_FUNC_RET(handle, retType, ret, sym, params...) \ + if (!ORIGINAL_FUNC_NAME(sym)) { \ + if (!handle) { \ + handle = semi_dlopen(ORIGINAL_LIB); \ + } \ if (handle) { \ - ORIGINAL_FUNC_NAME(sym) = (FUNC_TYPE(sym))dlsym(handle, #sym); \ + ORIGINAL_FUNC_NAME(sym) = (FUNC_TYPE(sym)) semi_dlsym(handle, #sym); \ } \ } \ retType ret = ORIGINAL_FUNC_NAME(sym)(params) -#define CALL_ORIGIN_FUNC_VOID(sym, params...) \ - if (!ORIGINAL_FUNC_NAME(sym)) { \ - void *handle = dlopen(ORIGINAL_LIB, RTLD_LAZY); \ +#define CALL_ORIGIN_FUNC_VOID(handle, sym, params...) \ + if (!ORIGINAL_FUNC_NAME(sym)) { \ + if (!handle) { \ + handle = semi_dlopen(ORIGINAL_LIB); \ + } \ if (handle) { \ - ORIGINAL_FUNC_NAME(sym) = (FUNC_TYPE(sym))dlsym(handle, #sym); \ + ORIGINAL_FUNC_NAME(sym) = (FUNC_TYPE(sym)) semi_dlsym(handle, #sym); \ } \ } \ ORIGINAL_FUNC_NAME(sym)(params) diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.cpp b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.cpp index 6755b58e3..6be0813bb 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.cpp +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.cpp @@ -26,6 +26,7 @@ #include "MemoryHook.h" #define ORIGINAL_LIB "libc.so" +static void *libc_handle = nullptr; #define DO_HOOK_ACQUIRE(p, size) \ GET_CALLER_ADDR(caller); \ @@ -35,21 +36,21 @@ on_free_memory(p) DEFINE_HOOK_FUN(void *, malloc, size_t __byte_count) { - CALL_ORIGIN_FUNC_RET(void*, p, malloc, __byte_count); + CALL_ORIGIN_FUNC_RET(libc_handle, void*, p, malloc, __byte_count); LOGI(TAG, "+ malloc %p", p); DO_HOOK_ACQUIRE(p, __byte_count); return p; } DEFINE_HOOK_FUN(void *, calloc, size_t __item_count, size_t __item_size) { - CALL_ORIGIN_FUNC_RET(void *, p, calloc, __item_count, __item_size); + CALL_ORIGIN_FUNC_RET(libc_handle, void *, p, calloc, __item_count, __item_size); LOGI(TAG, "+ calloc %p", p); DO_HOOK_ACQUIRE(p, __item_count * __item_size); return p; } DEFINE_HOOK_FUN(void *, realloc, void *__ptr, size_t __byte_count) { - CALL_ORIGIN_FUNC_RET(void *, p, realloc, __ptr, __byte_count); + CALL_ORIGIN_FUNC_RET(libc_handle, void *, p, realloc, __ptr, __byte_count); GET_CALLER_ADDR(caller); @@ -76,14 +77,14 @@ DEFINE_HOOK_FUN(void *, realloc, void *__ptr, size_t __byte_count) { } DEFINE_HOOK_FUN(void *, memalign, size_t __alignment, size_t __byte_count) { - CALL_ORIGIN_FUNC_RET(void *, p, memalign, __alignment, __byte_count); + CALL_ORIGIN_FUNC_RET(libc_handle, void *, p, memalign, __alignment, __byte_count); LOGI(TAG, "+ memalign %p", p); DO_HOOK_ACQUIRE(p, __byte_count); return p; } DEFINE_HOOK_FUN(int, posix_memalign, void** __memptr, size_t __alignment, size_t __size) { - CALL_ORIGIN_FUNC_RET(int, ret, posix_memalign, __memptr, __alignment, __size); + CALL_ORIGIN_FUNC_RET(libc_handle, int, ret, posix_memalign, __memptr, __alignment, __size); if (ret == 0) { LOGI(TAG, "+ posix_memalign %p", *__memptr); DO_HOOK_ACQUIRE(*__memptr, __size); @@ -94,7 +95,7 @@ DEFINE_HOOK_FUN(int, posix_memalign, void** __memptr, size_t __alignment, size_t DEFINE_HOOK_FUN(void, free, void *__ptr) { LOGI(TAG, "- free %p", __ptr); DO_HOOK_RELEASE(__ptr); - CALL_ORIGIN_FUNC_VOID(free, __ptr); + CALL_ORIGIN_FUNC_VOID(libc_handle, free, __ptr); } #if defined(__USE_FILE_OFFSET64) @@ -108,7 +109,7 @@ void*h_mmap(void* __addr, size_t __size, int __prot, int __flags, int __fd, off_ DEFINE_HOOK_FUN(void *, mmap, void *__addr, size_t __size, int __prot, int __flags, int __fd, off_t __offset) { - CALL_ORIGIN_FUNC_RET(void *, p, mmap, __addr, __size, __prot, __flags, __fd, __offset); + CALL_ORIGIN_FUNC_RET(libc_handle, void *, p, mmap, __addr, __size, __prot, __flags, __fd, __offset); if (p == MAP_FAILED) { return p;// just return } @@ -167,14 +168,14 @@ DEFINE_HOOK_FUN(int, munmap, void *__addr, size_t __size) { } DEFINE_HOOK_FUN(char*, strdup, const char *str) { - CALL_ORIGIN_FUNC_RET(char *, p, strdup, str); + CALL_ORIGIN_FUNC_RET(libc_handle, char *, p, strdup, str); LOGI(TAG, "+ strdup %p", (void *)p); DO_HOOK_ACQUIRE(p, sizeof(str)); return p; } DEFINE_HOOK_FUN(char*, strndup, const char *str, size_t n) { - CALL_ORIGIN_FUNC_RET(char *, p, strndup, str, n); + CALL_ORIGIN_FUNC_RET(libc_handle, char *, p, strndup, str, n); LOGI(TAG, "+ strndup %p", (void *)p); DO_HOOK_ACQUIRE(p, sizeof(str) < n ? sizeof(str) : n); return p; @@ -182,18 +183,19 @@ DEFINE_HOOK_FUN(char*, strndup, const char *str, size_t n) { #undef ORIGINAL_LIB #define ORIGINAL_LIB "libc++_shared.so" +static void *libcxx_handle = nullptr; #ifndef __LP64__ DEFINE_HOOK_FUN(void*, _Znwj, size_t size) { - CALL_ORIGIN_FUNC_RET(void*, p, _Znwj, size); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _Znwj, size); LOGI(TAG, "+ _Znwj %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _ZnwjSt11align_val_t, size_t size, std::align_val_t align_val) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnwjSt11align_val_t, size, align_val); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnwjSt11align_val_t, size, align_val); LOGI(TAG, "- _ZnwjSt11align_val_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; @@ -201,28 +203,28 @@ DEFINE_HOOK_FUN(void*, _ZnwjSt11align_val_t, size_t size, std::align_val_t align DEFINE_HOOK_FUN(void*, _ZnwjSt11align_val_tRKSt9nothrow_t, size_t size, std::align_val_t align_val, std::nothrow_t const& nothrow) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnwjSt11align_val_tRKSt9nothrow_t, size, align_val, nothrow); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnwjSt11align_val_tRKSt9nothrow_t, size, align_val, nothrow); LOGI(TAG, "+ _ZnwjSt11align_val_tRKSt9nothrow_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _ZnwjRKSt9nothrow_t, size_t size, std::nothrow_t const& nothrow) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnwjRKSt9nothrow_t, size, nothrow); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnwjRKSt9nothrow_t, size, nothrow); LOGI(TAG, "+ _ZnwjRKSt9nothrow_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _Znaj, size_t size) { - CALL_ORIGIN_FUNC_RET(void*, p, _Znaj, size); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _Znaj, size); LOGI(TAG, "+ _Znaj %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _ZnajSt11align_val_t, size_t size, std::align_val_t align_val) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnajSt11align_val_t, size, align_val); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnajSt11align_val_t, size, align_val); LOGI(TAG, "+ _ZnajSt11align_val_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; @@ -230,14 +232,14 @@ DEFINE_HOOK_FUN(void*, _ZnajSt11align_val_t, size_t size, std::align_val_t align DEFINE_HOOK_FUN(void*, _ZnajSt11align_val_tRKSt9nothrow_t, size_t size, std::align_val_t align_val, std::nothrow_t const& nothrow) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnajSt11align_val_tRKSt9nothrow_t, size, align_val, nothrow); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnajSt11align_val_tRKSt9nothrow_t, size, align_val, nothrow); LOGI(TAG, "+ _ZnajSt11align_val_tRKSt9nothrow_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _ZnajRKSt9nothrow_t, size_t size, std::nothrow_t const& nothrow) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnajRKSt9nothrow_t, size, nothrow); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnajRKSt9nothrow_t, size, nothrow); LOGI(TAG, "+ _ZnajRKSt9nothrow_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; @@ -246,40 +248,40 @@ DEFINE_HOOK_FUN(void*, _ZnajRKSt9nothrow_t, size_t size, std::nothrow_t const& n DEFINE_HOOK_FUN(void, _ZdaPvj, void* ptr, size_t size) { LOGI(TAG, "- _ZdaPvj %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdaPvj, ptr, size); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdaPvj, ptr, size); } DEFINE_HOOK_FUN(void, _ZdaPvjSt11align_val_t, void* ptr, size_t size, std::align_val_t align_val) { LOGI(TAG, "- _ZdaPvjSt11align_val_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdaPvjSt11align_val_t, ptr, size, align_val); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdaPvjSt11align_val_t, ptr, size, align_val); } DEFINE_HOOK_FUN(void, _ZdlPvj, void* ptr, size_t size) { LOGI(TAG, "- _ZdlPvj %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdlPvj, ptr, size); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdlPvj, ptr, size); } DEFINE_HOOK_FUN(void, _ZdlPvjSt11align_val_t, void* ptr, size_t size, std::align_val_t align_val) { LOGI(TAG, "- _ZdlPvjSt11align_val_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdlPvjSt11align_val_t, ptr, size, align_val); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdlPvjSt11align_val_t, ptr, size, align_val); } #else DEFINE_HOOK_FUN(void*, _Znwm, size_t size) { - CALL_ORIGIN_FUNC_RET(void*, p, _Znwm, size); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _Znwm, size); LOGI(TAG, "+ _Znwm %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _ZnwmSt11align_val_t, size_t size, std::align_val_t align_val) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnwmSt11align_val_t, size, align_val); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnwmSt11align_val_t, size, align_val); LOGI(TAG, "+ _ZnwmSt11align_val_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; @@ -288,28 +290,28 @@ DEFINE_HOOK_FUN(void*, _ZnwmSt11align_val_t, size_t size, std::align_val_t align DEFINE_HOOK_FUN(void*, _ZnwmSt11align_val_tRKSt9nothrow_t, size_t size, std::align_val_t align_val, std::nothrow_t const ¬hrow) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnwmSt11align_val_tRKSt9nothrow_t, size, align_val, nothrow); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnwmSt11align_val_tRKSt9nothrow_t, size, align_val, nothrow); LOGI(TAG, "+ _ZnwmSt11align_val_tRKSt9nothrow_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const ¬hrow) { - CALL_ORIGIN_FUNC_RET(void*, p, _Znwm, size); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _Znwm, size); LOGI(TAG, "+ _ZnwmRKSt9nothrow_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _Znam, size_t size) { - CALL_ORIGIN_FUNC_RET(void*, p, _Znam, size); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _Znam, size); LOGI(TAG, "+ _Znam %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _ZnamSt11align_val_t, size_t size, std::align_val_t align_val) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnamSt11align_val_t, size, align_val); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnamSt11align_val_t, size, align_val); LOGI(TAG, "+ _ZnamSt11align_val_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; @@ -318,14 +320,14 @@ DEFINE_HOOK_FUN(void*, _ZnamSt11align_val_t, size_t size, std::align_val_t align DEFINE_HOOK_FUN(void*, _ZnamSt11align_val_tRKSt9nothrow_t, size_t size, std::align_val_t align_val, std::nothrow_t const ¬hrow) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnamSt11align_val_tRKSt9nothrow_t, size, align_val, nothrow); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnamSt11align_val_tRKSt9nothrow_t, size, align_val, nothrow); LOGI(TAG, "+ _ZnamSt11align_val_tRKSt9nothrow_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; } DEFINE_HOOK_FUN(void*, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const ¬hrow) { - CALL_ORIGIN_FUNC_RET(void*, p, _ZnamRKSt9nothrow_t, size, nothrow); + CALL_ORIGIN_FUNC_RET(libcxx_handle, void*, p, _ZnamRKSt9nothrow_t, size, nothrow); LOGI(TAG, "+ _ZnamRKSt9nothrow_t %p", p); DO_HOOK_ACQUIRE(p, size); return p; @@ -334,27 +336,27 @@ DEFINE_HOOK_FUN(void*, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const &n DEFINE_HOOK_FUN(void, _ZdlPvm, void *ptr, size_t size) { LOGI(TAG, "- _ZdlPvm %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdlPvm, ptr, size); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdlPvm, ptr, size); } DEFINE_HOOK_FUN(void, _ZdlPvmSt11align_val_t, void *ptr, size_t size, std::align_val_t align_val) { LOGI(TAG, "- _ZdlPvmSt11align_val_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdlPvmSt11align_val_t, ptr, size, align_val); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdlPvmSt11align_val_t, ptr, size, align_val); } DEFINE_HOOK_FUN(void, _ZdaPvm, void *ptr, size_t size) { LOGI(TAG, "- _ZdaPvm %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdaPvm, ptr, size); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdaPvm, ptr, size); } DEFINE_HOOK_FUN(void, _ZdaPvmSt11align_val_t, void *ptr, size_t size, std::align_val_t align_val) { LOGI(TAG, "- _ZdaPvmSt11align_val_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdaPvmSt11align_val_t, ptr, size, align_val); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdaPvmSt11align_val_t, ptr, size, align_val); } #endif @@ -362,13 +364,13 @@ DEFINE_HOOK_FUN(void, _ZdaPvmSt11align_val_t, void *ptr, size_t size, DEFINE_HOOK_FUN(void, _ZdlPv, void *p) { LOGI(TAG, "- _ZdlPv %p", p); DO_HOOK_RELEASE(p); - CALL_ORIGIN_FUNC_VOID(_ZdlPv, p); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdlPv, p); } DEFINE_HOOK_FUN(void, _ZdlPvSt11align_val_t, void *ptr, std::align_val_t align_val) { LOGI(TAG, "- _ZdlPvSt11align_val_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdlPvSt11align_val_t, ptr, align_val); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdlPvSt11align_val_t, ptr, align_val); } DEFINE_HOOK_FUN(void, _ZdlPvSt11align_val_tRKSt9nothrow_t, void *ptr, @@ -376,25 +378,25 @@ DEFINE_HOOK_FUN(void, _ZdlPvSt11align_val_tRKSt9nothrow_t, void *ptr, std::nothrow_t const ¬hrow) { LOGI(TAG, "- _ZdlPvSt11align_val_tRKSt9nothrow_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdlPvSt11align_val_tRKSt9nothrow_t, ptr, align_val, nothrow); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdlPvSt11align_val_tRKSt9nothrow_t, ptr, align_val, nothrow); } DEFINE_HOOK_FUN(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const ¬hrow) { LOGI(TAG, "- _ZdlPvRKSt9nothrow_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdlPvRKSt9nothrow_t, ptr, nothrow); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdlPvRKSt9nothrow_t, ptr, nothrow); } DEFINE_HOOK_FUN(void, _ZdaPv, void *ptr) { LOGI(TAG, "- _ZdaPv %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdaPv, ptr); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdaPv, ptr); } DEFINE_HOOK_FUN(void, _ZdaPvSt11align_val_t, void *ptr, std::align_val_t align_val) { LOGI(TAG, "- _ZdaPvSt11align_val_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdaPvSt11align_val_t, ptr, align_val); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdaPvSt11align_val_t, ptr, align_val); } DEFINE_HOOK_FUN(void, _ZdaPvSt11align_val_tRKSt9nothrow_t, void *ptr, @@ -402,13 +404,13 @@ DEFINE_HOOK_FUN(void, _ZdaPvSt11align_val_tRKSt9nothrow_t, void *ptr, std::nothrow_t const ¬hrow) { LOGI(TAG, "- _ZdaPvSt11align_val_tRKSt9nothrow_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdaPvSt11align_val_tRKSt9nothrow_t, ptr, align_val, nothrow); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdaPvSt11align_val_tRKSt9nothrow_t, ptr, align_val, nothrow); } DEFINE_HOOK_FUN(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const ¬hrow) { LOGI(TAG, "- _ZdaPvRKSt9nothrow_t %p", ptr); DO_HOOK_RELEASE(ptr); - CALL_ORIGIN_FUNC_VOID(_ZdaPvRKSt9nothrow_t, ptr, nothrow); + CALL_ORIGIN_FUNC_VOID(libcxx_handle, _ZdaPvRKSt9nothrow_t, ptr, nothrow); } #undef ORIGINAL_LIB \ No newline at end of file diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/pthread/PthreadHook.cpp b/matrix/matrix-android/matrix-hooks/src/main/cpp/pthread/PthreadHook.cpp index 8f9b64cad..56a3307ae 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/pthread/PthreadHook.cpp +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/pthread/PthreadHook.cpp @@ -32,6 +32,7 @@ #define LOG_TAG "Matrix.PthreadHook" #define ORIGINAL_LIB "libc.so" +static void *pthread_handle = nullptr; static volatile bool sThreadTraceEnabled = false; static volatile bool sThreadStackShrinkEnabled = false; @@ -67,11 +68,11 @@ DEFINE_HOOK_FUN(int, pthread_create, int ret = 0; if (sThreadTraceEnabled) { auto *routine_wrapper = thread_trace::wrap_pthread_routine(start_routine, args); - CALL_ORIGIN_FUNC_RET(int, tmpRet, pthread_create, pthread, &tmpAttr, routine_wrapper->wrapped_func, + CALL_ORIGIN_FUNC_RET(pthread_handle, int, tmpRet, pthread_create, pthread, &tmpAttr, routine_wrapper->wrapped_func, routine_wrapper); ret = tmpRet; } else { - CALL_ORIGIN_FUNC_RET(int, tmpRet, pthread_create, pthread, &tmpAttr, start_routine, args); + CALL_ORIGIN_FUNC_RET(pthread_handle, int, tmpRet, pthread_create, pthread, &tmpAttr, start_routine, args); ret = tmpRet; } @@ -87,7 +88,7 @@ DEFINE_HOOK_FUN(int, pthread_create, } DEFINE_HOOK_FUN(int, pthread_setname_np, pthread_t pthread, const char* name) { - CALL_ORIGIN_FUNC_RET(int, ret, pthread_setname_np, pthread, name); + CALL_ORIGIN_FUNC_RET(pthread_handle, int, ret, pthread_setname_np, pthread, name); if (LIKELY(ret == 0) && sThreadTraceEnabled) { thread_trace::handle_pthread_setname_np(pthread, name); } @@ -95,7 +96,7 @@ DEFINE_HOOK_FUN(int, pthread_setname_np, pthread_t pthread, const char* name) { } DEFINE_HOOK_FUN(int, pthread_detach, pthread_t pthread) { - CALL_ORIGIN_FUNC_RET(int, ret, pthread_detach, pthread); + CALL_ORIGIN_FUNC_RET(pthread_handle, int, ret, pthread_detach, pthread); LOGD(LOG_TAG, "pthread_detach : %d", ret); if (LIKELY(ret == 0) && sThreadTraceEnabled) { thread_trace::handle_pthread_release(pthread); @@ -104,7 +105,7 @@ DEFINE_HOOK_FUN(int, pthread_detach, pthread_t pthread) { } DEFINE_HOOK_FUN(int, pthread_join, pthread_t pthread, void** return_value_ptr) { - CALL_ORIGIN_FUNC_RET(int, ret, pthread_join, pthread, return_value_ptr); + CALL_ORIGIN_FUNC_RET(pthread_handle, int, ret, pthread_join, pthread, return_value_ptr); LOGD(LOG_TAG, "pthread_join : %d", ret); if (LIKELY(ret == 0) && sThreadTraceEnabled) { thread_trace::handle_pthread_release(pthread); diff --git a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/AbsHook.java b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/AbsHook.java index a7f142c87..fea1c8225 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/AbsHook.java +++ b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/AbsHook.java @@ -16,7 +16,7 @@ package com.tencent.matrix.hook; -import androidx.annotation.Nullable; +import androidx.annotation.NonNull; /** * Created by Yves on 2020-03-18 @@ -40,7 +40,7 @@ public Status getStatus() { return mStatus; } - @Nullable + @NonNull protected abstract String getNativeLibraryName(); protected abstract boolean onConfigure(); diff --git a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/HookManager.java b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/HookManager.java index ab8098b55..4257db80e 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/HookManager.java +++ b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/HookManager.java @@ -16,6 +16,7 @@ package com.tencent.matrix.hook; +import android.os.Build; import android.text.TextUtils; import androidx.annotation.Keep; @@ -24,6 +25,10 @@ import com.tencent.matrix.util.MatrixLog; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; import java.util.HashSet; import java.util.Set; @@ -83,6 +88,47 @@ public void commitHooks() throws HookFailedException { } } + private boolean enableLibCxxSharedCheck = false; + public HookManager enableLibCxxSharedCheck(boolean enable) { + enableLibCxxSharedCheck = enable; + return this; + } + + private boolean checkLibCxxSharedLoaded() { + if (Build.VERSION.SDK_INT != Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT != Build.VERSION_CODES.LOLLIPOP_MR1) { + return true; + } + + try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/maps")))) { + String line; + while ((line = br.readLine()) != null) { + if (line.endsWith("libc++_shared.so")) { + return true; + } + } + } catch (IOException e) { + MatrixLog.printErrStackTrace(TAG, e, ""); + } + + return false; + } + + private void ensureLibCxxSharedLoadedForLollipop() throws RuntimeException { + if (!enableLibCxxSharedCheck) { + return; + } + enableLibCxxSharedCheck = false; // mark loaded + if (checkLibCxxSharedLoaded()) { + return; + } + if (mNativeLibLoader != null) { + mNativeLibLoader.loadLibrary("c++_shared"); + } else { + System.loadLibrary("c++_shared"); + } + } + + private void commitHooksLocked() throws HookFailedException { synchronized (mPendingHooks) { for (AbsHook hook : mPendingHooks) { @@ -91,6 +137,7 @@ private void commitHooksLocked() throws HookFailedException { continue; } try { + ensureLibCxxSharedLoadedForLollipop(); if (mNativeLibLoader != null) { mNativeLibLoader.loadLibrary(nativeLibName); } else { diff --git a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/memory/MemoryHook.java b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/memory/MemoryHook.java index 59441b1f7..24b4d10bc 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/memory/MemoryHook.java +++ b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/memory/MemoryHook.java @@ -19,7 +19,7 @@ import android.text.TextUtils; import androidx.annotation.Keep; -import androidx.annotation.Nullable; +import androidx.annotation.NonNull; import com.tencent.matrix.hook.AbsHook; import com.tencent.matrix.hook.HookManager; @@ -123,7 +123,7 @@ public void hook() throws HookManager.HookFailedException { .commitHooks(); } - @Nullable + @NonNull @Override protected String getNativeLibraryName() { return "matrix-memoryhook"; diff --git a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/memory/WVPreAllocHook.java b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/memory/WVPreAllocHook.java index f8bfb2d28..ced401446 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/memory/WVPreAllocHook.java +++ b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/memory/WVPreAllocHook.java @@ -18,14 +18,14 @@ import android.os.Build; -import androidx.annotation.Nullable; +import androidx.annotation.NonNull; import com.tencent.matrix.hook.AbsHook; public class WVPreAllocHook extends AbsHook { public static final WVPreAllocHook INSTANCE = new WVPreAllocHook(); - @Nullable + @NonNull @Override protected String getNativeLibraryName() { return "matrix-memoryhook"; diff --git a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/pthread/PthreadHook.java b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/pthread/PthreadHook.java index 4cbf51a44..1cb7917fc 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/pthread/PthreadHook.java +++ b/matrix/matrix-android/matrix-hooks/src/main/java/com/tencent/matrix/hook/pthread/PthreadHook.java @@ -146,7 +146,7 @@ public void enableLogger(boolean enable) { } } - @Nullable + @NonNull @Override protected String getNativeLibraryName() { return "matrix-pthreadhook"; From 6cf6c9030ba8bac4889142ba9370bf996d2435f4 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 2 Dec 2022 14:53:25 +0800 Subject: [PATCH 216/263] memory-canary: fix NPE crash --- .../java/com/tencent/matrix/util/MemInfoFactory.kt | 2 ++ .../memory/canary/monitor/AppBgSumPssMonitor.kt | 14 ++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt index a76abd72b..5cff2a955 100644 --- a/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt +++ b/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/util/MemInfoFactory.kt @@ -735,6 +735,8 @@ data class MemInfo( javaMemInfo = null, nativeMemInfo = null, systemInfo = systemInfo, + debugPssInfo = PssInfo(), + amsPssInfo = PssInfo() ) ) } diff --git a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt index dc482b21f..85b46c1b7 100644 --- a/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt +++ b/matrix/matrix-android/matrix-memory-canary/src/main/java/com/tencent/matrix/memory/canary/monitor/AppBgSumPssMonitor.kt @@ -87,12 +87,14 @@ internal class AppBgSumPssMonitor( ) }.sumBy { it.amsPssInfo!!.totalPssK }.also { MatrixLog.i(TAG, "sumPss = $it KB") } - val debugPssSum = debugMemInfos.onEach { - MatrixLog.i( - TAG, - "${it.processInfo?.pid}-${it.processInfo?.name}: dbgPss = ${it.debugPssInfo!!.totalPssK} KB, amsPss = ${it.amsPssInfo!!.totalPssK} KB" - ) - }.sumBy { it.debugPssInfo!!.totalPssK }.also { MatrixLog.i(TAG, "ipc sumDbgPss = $it KB") } + val debugPssSum = safeLet(tag = TAG, defVal = 0) { + debugMemInfos.filter { it.processInfo != null && it.debugPssInfo != null && it.amsPssInfo != null }.onEach { + MatrixLog.i( + TAG, + "${it.processInfo?.pid}-${it.processInfo?.name}: dbgPss = ${it.debugPssInfo!!.totalPssK} KB, amsPss = ${it.amsPssInfo!!.totalPssK} KB" + ) + }.sumBy { it.debugPssInfo!!.totalPssK }.also { MatrixLog.i(TAG, "ipc sumDbgPss = $it KB") } + } MatrixLog.i(TAG, "check with interval [$checkInterval] amsPssSum = $amsPssSum KB, ${amsMemInfos.contentToString()}") MatrixLog.i(TAG, "check with interval [$checkInterval] debugPssSum = $debugPssSum KB, ${debugMemInfos.contentToString()}") From 1a15578930b9d81fb724f407b2bb609329afa338 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Fri, 2 Dec 2022 16:43:38 +0800 Subject: [PATCH 217/263] Fix battery get bps compat issue --- .../batterycanary/utils/RadioStatUtil.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java index a96b9df6b..58499fc7f 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/RadioStatUtil.java @@ -97,15 +97,20 @@ public static RadioBps getCurrentBps(Context context) { if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { return null; } - RadioBps stat = new RadioBps(); - Pair wifi = getCurrentBps(context, "WIFI"); - stat.wifiRxBps = wifi.first == null ? 0 : wifi.first; - stat.wifiTxBps = wifi.second == null ? 0 : wifi.second; - - Pair mobile = getCurrentBps(context, "MOBILE"); - stat.mobileRxBps = mobile.first == null ? 0 : mobile.first; - stat.mobileTxBps = mobile.second == null ? 0 : mobile.second; - return stat; + try { + RadioBps stat = new RadioBps(); + Pair wifi = getCurrentBps(context, "WIFI"); + stat.wifiRxBps = wifi.first == null ? 0 : wifi.first; + stat.wifiTxBps = wifi.second == null ? 0 : wifi.second; + + Pair mobile = getCurrentBps(context, "MOBILE"); + stat.mobileRxBps = mobile.first == null ? 0 : mobile.first; + stat.mobileTxBps = mobile.second == null ? 0 : mobile.second; + return stat; + } catch (Exception e) { + MatrixLog.w(TAG, "getBps err: " + e.getMessage()); + return null; + } } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) From 1e1ef67afcf7098e1385ce2e4e701da96015e98b Mon Sep 17 00:00:00 2001 From: yvesluo Date: Sat, 3 Dec 2022 16:31:16 +0800 Subject: [PATCH 218/263] matrix-hooks: fix NPE - fetch origin function pointer before registering hooks --- .../matrix-hooks/CMakeLists.txt | 2 - .../src/main/cpp/common/HookCommon.h | 42 ++--- .../main/cpp/memory/MemoryHookFunctions.cpp | 6 +- .../src/main/cpp/memory/MemoryHookFunctions.h | 8 +- .../src/main/cpp/memory/MemoryHookJNI.cpp | 149 ++++++++++-------- .../tencent/matrix/MatrixApplication.java | 6 +- .../matrix/hooks/TestHooksActivity.java | 19 ++- .../app/src/main/jni/MemObj.cpp | 13 +- 8 files changed, 128 insertions(+), 117 deletions(-) diff --git a/matrix/matrix-android/matrix-hooks/CMakeLists.txt b/matrix/matrix-android/matrix-hooks/CMakeLists.txt index 48486ca39..293ab5e25 100644 --- a/matrix/matrix-android/matrix-hooks/CMakeLists.txt +++ b/matrix/matrix-android/matrix-hooks/CMakeLists.txt @@ -74,7 +74,6 @@ add_library( target_link_libraries( ${TARGET} PRIVATE matrix-hookcommon - PRIVATE -Wl,--whole-archive ${EXT_DEP}/lib/${ANDROID_ABI}/libsemi_dlfcn.a -Wl,--no-whole-archive PRIVATE -Wl,--version-script=${SOURCE_DIR}/memory/memory.ver ) ################################################################################# @@ -94,7 +93,6 @@ add_library( target_link_libraries( ${TARGET} PRIVATE matrix-hookcommon - PRIVATE -Wl,--whole-archive ${EXT_DEP}/lib/${ANDROID_ABI}/libsemi_dlfcn.a -Wl,--no-whole-archive PRIVATE -Wl,--version-script=${SOURCE_DIR}/pthread/pthread.ver ) ################################################################################# diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h b/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h index ebdfb9d96..885014dec 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/common/HookCommon.h @@ -27,7 +27,7 @@ #include #include "JNICommon.h" #include "Macros.h" -#include "semi_dlfcn.h" +#include "EnhanceDlsym.h" // 0x01 was occupied by thread priority trace hook in MatrixTracer.cc. #define HOOK_REQUEST_GROUPID_DLOPEN_MON 0x02 @@ -51,38 +51,30 @@ extern ORIGINAL_FUNC_PTR(sym); \ ret HANDLER_FUNC_NAME(sym)(params); +#define DECLARE_HOOK_ORIG_ATTR(ret, sym, params...) \ + typedef ret (*FUNC_TYPE(sym))(params); \ + extern ORIGINAL_FUNC_PTR(sym); \ + ret HANDLER_FUNC_NAME(sym)(params) + #define DEFINE_HOOK_FUN(ret, sym, params...) \ ORIGINAL_FUNC_PTR(sym); \ ret HANDLER_FUNC_NAME(sym)(params) -#define FETCH_ORIGIN_FUNC(sym) \ - if (!ORIGINAL_FUNC_NAME(sym)) { \ - void *handle = dlopen(ORIGINAL_LIB, RTLD_LAZY); \ +#define FETCH_ORIGIN_FUNC_OF_SO(sym, target_so) \ + if (!ORIGINAL_FUNC_NAME(sym)) { \ + void *handle = dlopen(target_so, RTLD_LAZY); \ if (handle) { \ ORIGINAL_FUNC_NAME(sym) = (FUNC_TYPE(sym))dlsym(handle, #sym); \ } \ - } + }\ + +#define FETCH_ORIGIN_FUNC(sym) \ + FETCH_ORIGIN_FUNC_OF_SO(sym, ORIGINAL_LIB) #define CALL_ORIGIN_FUNC_RET(handle, retType, ret, sym, params...) \ - if (!ORIGINAL_FUNC_NAME(sym)) { \ - if (!handle) { \ - handle = semi_dlopen(ORIGINAL_LIB); \ - } \ - if (handle) { \ - ORIGINAL_FUNC_NAME(sym) = (FUNC_TYPE(sym)) semi_dlsym(handle, #sym); \ - } \ - } \ retType ret = ORIGINAL_FUNC_NAME(sym)(params) #define CALL_ORIGIN_FUNC_VOID(handle, sym, params...) \ - if (!ORIGINAL_FUNC_NAME(sym)) { \ - if (!handle) { \ - handle = semi_dlopen(ORIGINAL_LIB); \ - } \ - if (handle) { \ - ORIGINAL_FUNC_NAME(sym) = (FUNC_TYPE(sym)) semi_dlsym(handle, #sym); \ - } \ - } \ ORIGINAL_FUNC_NAME(sym)(params) #define NOTIFY_COMMON_IGNORE_LIBS(group_id) \ @@ -109,18 +101,10 @@ xhook_grouped_ignore(group_id, ".*/libmatrix-traffic\\.so$", NULL);\ } while (0) -#include - #ifdef __cplusplus extern "C" { #endif -typedef struct { - const char *name; - void *handler_ptr; - void **origin_ptr; -} HookFunction; - EXPORT bool get_java_stacktrace(char *stack_dst, size_t size); #ifdef __cplusplus diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.cpp b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.cpp index 6be0813bb..ae025fb7e 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.cpp +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.cpp @@ -123,9 +123,8 @@ DEFINE_HOOK_FUN(void *, mmap, void *__addr, size_t __size, int __prot, int __fla #endif #if __ANDROID_API__ >= __ANDROID_API_L__ - -void *h_mmap64(void *__addr, size_t __size, int __prot, int __flags, int __fd, - off64_t __offset) __INTRODUCED_IN(21) { +DEFINE_HOOK_FUN(void *, mmap64, void *__addr, size_t __size, int __prot, int __flags, int __fd, + off64_t __offset) { void *p = mmap64(__addr, __size, __prot, __flags, __fd, __offset); if (p == MAP_FAILED) { return p;// just return @@ -135,7 +134,6 @@ void *h_mmap64(void *__addr, size_t __size, int __prot, int __flags, int __fd, on_mmap_memory(caller, p, __size); return p; } - #endif DEFINE_HOOK_FUN(void *, mremap, void *__old_addr, size_t __old_size, size_t __new_size, int __flags, diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.h b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.h index 11ec15d7e..9dd9c26f7 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.h +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookFunctions.h @@ -47,16 +47,14 @@ DECLARE_HOOK_ORIG(void *, memalign, size_t __alignment, size_t __byte_count); DECLARE_HOOK_ORIG(int, posix_memalign, void** __memptr, size_t __alignment, size_t __size); #if defined(__USE_FILE_OFFSET64) -// DECLARE_HOOK_ORIG not supports attrbute -void *h_mmap(void* __addr, size_t __size, int __prot, int __flags, int __fd, off_t __offset) __RENAME(mmap64); +DECLARE_HOOK_ORIG_ATTR(void *, mmap, void* __addr, size_t __size, int __prot, int __flags, int __fd, off_t __offset) __RENAME(mmap64); #else DECLARE_HOOK_ORIG(void *, mmap, void *__addr, size_t __size, int __prot, int __flags, int __fd, off_t __offset); #endif #if __ANDROID_API__ >= __ANDROID_API_L__ -// DECLARE_HOOK_ORIG not supports attrbute -void *h_mmap64(void *__addr, size_t __size, int __prot, int __flags, int __fd, - off64_t __offset) __INTRODUCED_IN(21); +DECLARE_HOOK_ORIG_ATTR(void *, mmap64, void *__addr, size_t __size, int __prot, int __flags, int __fd, + off64_t __offset) __INTRODUCED_IN(21); #endif DECLARE_HOOK_ORIG(void *, mremap, void*, size_t, size_t, int, ...) diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookJNI.cpp b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookJNI.cpp index 3fad302ab..050db5820 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookJNI.cpp +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookJNI.cpp @@ -26,86 +26,95 @@ #include "MemoryHookFunctions.h" #include "MemoryHook.h" +#undef LOGD +#define LOGD(TAG, FMT, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, FMT, ##args) + #ifdef __cplusplus extern "C" { #endif -// @formatter:off -const HookFunction HOOK_MALL_FUNCTIONS[] = { - {"malloc", (void *) h_malloc, NULL}, - {"calloc", (void *) h_calloc, NULL}, - {"realloc", (void *) h_realloc, NULL}, - {"free", (void *) h_free, NULL}, - {"memalign", (void *) HANDLER_FUNC_NAME(memalign), NULL}, - {"posix_memalign", (void *) HANDLER_FUNC_NAME(posix_memalign), NULL}, - // CXX functions -#ifndef __LP64__ - {"_Znwj", (void*) HANDLER_FUNC_NAME(_Znwj), NULL}, - {"_ZnwjSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZnwjSt11align_val_t), NULL}, - {"_ZnwjSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnwjSt11align_val_tRKSt9nothrow_t), NULL}, - {"_ZnwjRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnwjRKSt9nothrow_t), NULL}, - - {"_Znaj", (void*) HANDLER_FUNC_NAME(_Znaj), NULL}, - {"_ZnajSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZnajSt11align_val_t), NULL}, - {"_ZnajSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnajSt11align_val_tRKSt9nothrow_t), NULL}, - {"_ZnajRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnajRKSt9nothrow_t), NULL}, - - {"_ZdlPvj", (void*) HANDLER_FUNC_NAME(_ZdlPvj), NULL}, - {"_ZdlPvjSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdlPvjSt11align_val_t), NULL}, - {"_ZdaPvj", (void*) HANDLER_FUNC_NAME(_ZdaPvj), NULL}, - {"_ZdaPvjSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdaPvjSt11align_val_t), NULL}, -#else - {"_Znwm", (void*) HANDLER_FUNC_NAME(_Znwm), NULL}, - {"_ZnwmSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZnwmSt11align_val_t), NULL}, - {"_ZnwmSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnwmSt11align_val_tRKSt9nothrow_t), NULL}, - {"_ZnwmRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnwmRKSt9nothrow_t), NULL}, - - {"_Znam", (void*) HANDLER_FUNC_NAME(_Znam), NULL}, - {"_ZnamSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZnamSt11align_val_t), NULL}, - {"_ZnamSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnamSt11align_val_tRKSt9nothrow_t), NULL}, - {"_ZnamRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnamRKSt9nothrow_t), NULL}, - - {"_ZdlPvm", (void*) HANDLER_FUNC_NAME(_ZdlPvm), NULL}, - {"_ZdlPvmSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdlPvmSt11align_val_t), NULL}, - {"_ZdaPvm", (void*) HANDLER_FUNC_NAME(_ZdaPvm), NULL}, - {"_ZdaPvmSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdaPvmSt11align_val_t), NULL}, -#endif - {"_ZdlPv", (void*) HANDLER_FUNC_NAME(_ZdlPv), NULL}, - {"_ZdlPvSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdlPvSt11align_val_t), NULL}, - {"_ZdlPvSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdlPvSt11align_val_tRKSt9nothrow_t), NULL}, - {"_ZdlPvRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdlPvRKSt9nothrow_t), NULL}, - - {"_ZdaPv", (void*) HANDLER_FUNC_NAME(_ZdaPv), NULL}, - {"_ZdaPvSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdaPvSt11align_val_t), NULL}, - {"_ZdaPvSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdaPvSt11align_val_tRKSt9nothrow_t), NULL}, - {"_ZdaPvRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdaPvRKSt9nothrow_t), NULL}, - - {"strdup", (void*) HANDLER_FUNC_NAME(strdup), (void **) ORIGINAL_FUNC_NAME(strdup)}, - {"strndup", (void*) HANDLER_FUNC_NAME(strndup), (void **) ORIGINAL_FUNC_NAME(strndup)}, -}; - -static const HookFunction HOOK_MMAP_FUNCTIONS[] = { - {"mmap", (void *) h_mmap, NULL}, - {"munmap", (void *) h_munmap, NULL}, - {"mremap", (void *) h_mremap, NULL}, -#if __ANDROID_API__ >= __ANDROID_API_L__ - {"mmap64", (void *) h_mmap64, NULL}, -#endif -}; -// @formatter:on + +#define HOOK_REGISTER(regex, target_sym, target_so) \ + do { \ + FETCH_ORIGIN_FUNC_OF_SO(target_sym, target_so); \ + if(!ORIGINAL_FUNC_NAME(target_sym)) { \ + LOGD(TAG, "hook failed: fetch origin func failed: %s", #target_sym); \ + break; \ + } \ + int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, #target_sym, (void*) HANDLER_FUNC_NAME(target_sym), nullptr); \ + LOGD(TAG, "hook fn, regex: %s, sym: %s, ret: %d", regex, #target_sym, ret); \ + \ + } while(0); + +#define HOOK_REGISTER_REGEX_LIBC(target_sym) \ + HOOK_REGISTER(regex, target_sym, "libc.so") + +#define HOOK_REGISTER_REGEX_LIBCXX(target_sym) \ + HOOK_REGISTER(regex, target_sym, "libc++_shared.so") + bool enable_mmap_hook = false; static void hook(const char *regex) { + HOOK_REGISTER_REGEX_LIBC(malloc) + HOOK_REGISTER_REGEX_LIBC(calloc) + HOOK_REGISTER_REGEX_LIBC(realloc) + HOOK_REGISTER_REGEX_LIBC(free) + + HOOK_REGISTER_REGEX_LIBC(memalign) + HOOK_REGISTER_REGEX_LIBC(posix_memalign) + HOOK_REGISTER_REGEX_LIBC(strdup) + HOOK_REGISTER_REGEX_LIBC(strndup) + + // CXX functions +#ifndef __LP64__ + HOOK_REGISTER_REGEX_LIBCXX(_Znwj) + HOOK_REGISTER_REGEX_LIBCXX(_ZnwjSt11align_val_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZnwjSt11align_val_tRKSt9nothrow_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZnwjRKSt9nothrow_t) + + HOOK_REGISTER_REGEX_LIBCXX(_Znaj) + HOOK_REGISTER_REGEX_LIBCXX(_ZnajSt11align_val_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZnajSt11align_val_tRKSt9nothrow_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZnajRKSt9nothrow_t) + + HOOK_REGISTER_REGEX_LIBCXX(_ZdlPvj) + HOOK_REGISTER_REGEX_LIBCXX(_ZdlPvjSt11align_val_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZdaPvj) + HOOK_REGISTER_REGEX_LIBCXX(_ZdaPvjSt11align_val_t) +#else + HOOK_REGISTER_REGEX_LIBCXX(_Znwm) + HOOK_REGISTER_REGEX_LIBCXX(_ZnwmSt11align_val_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZnwmSt11align_val_tRKSt9nothrow_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZnwmRKSt9nothrow_t) + + HOOK_REGISTER_REGEX_LIBCXX(_Znam) + HOOK_REGISTER_REGEX_LIBCXX(_ZnamSt11align_val_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZnamSt11align_val_tRKSt9nothrow_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZnamRKSt9nothrow_t) + + HOOK_REGISTER_REGEX_LIBCXX(_ZdlPvm) + HOOK_REGISTER_REGEX_LIBCXX(_ZdlPvmSt11align_val_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZdaPvm) + HOOK_REGISTER_REGEX_LIBCXX(_ZdaPvmSt11align_val_t) +#endif + HOOK_REGISTER_REGEX_LIBCXX(_ZdlPv) + HOOK_REGISTER_REGEX_LIBCXX(_ZdlPvSt11align_val_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZdlPvSt11align_val_tRKSt9nothrow_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZdlPvRKSt9nothrow_t) + + HOOK_REGISTER_REGEX_LIBCXX(_ZdaPv) + HOOK_REGISTER_REGEX_LIBCXX(_ZdaPvSt11align_val_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZdaPvSt11align_val_tRKSt9nothrow_t) + HOOK_REGISTER_REGEX_LIBCXX(_ZdaPvRKSt9nothrow_t) - for (auto f : HOOK_MALL_FUNCTIONS) { - int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, f.name, f.handler_ptr, f.origin_ptr); - LOGD(TAG, "hook fn, regex: %s, sym: %s, ret: %d", regex, f.name, ret); - } LOGD(TAG, "mmap enabled ? %d", enable_mmap_hook); if (enable_mmap_hook) { - for (auto f: HOOK_MMAP_FUNCTIONS) { - xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, f.name, f.handler_ptr, f.origin_ptr); - } + HOOK_REGISTER_REGEX_LIBC(mmap) + HOOK_REGISTER_REGEX_LIBC(munmap) + HOOK_REGISTER_REGEX_LIBC(mremap) +#if __ANDROID_API__ >= __ANDROID_API_L__ + HOOK_REGISTER_REGEX_LIBC(mmap64) +#endif } } diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java index 23219cd2a..c1b47e30a 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java @@ -79,6 +79,8 @@ public static boolean is64BitRuntime() { public void onCreate() { super.onCreate(); + System.loadLibrary("c++_shared"); + if (!is64BitRuntime()) { try { final PthreadHook.ThreadStackShrinkConfig config = new PthreadHook.ThreadStackShrinkConfig() @@ -116,8 +118,8 @@ public void onCreate() { builder.plugin(memoryCanaryPlugin); // Configure trace canary. - TracePlugin tracePlugin = configureTracePlugin(dynamicConfig); - builder.plugin(tracePlugin); +// TracePlugin tracePlugin = configureTracePlugin(dynamicConfig); +// builder.plugin(tracePlugin); // Configure resource canary. ResourcePlugin resourcePlugin = configureResourcePlugin(dynamicConfig); diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java index 8ebfe5c45..961fcd18d 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/hooks/TestHooksActivity.java @@ -25,6 +25,7 @@ import com.tencent.matrix.hook.memory.MemoryHook; import com.tencent.matrix.hook.pthread.PthreadHook; import com.tencent.matrix.mallctl.MallCtl; +import com.tencent.matrix.util.MatrixLog; import java.io.File; @@ -197,20 +198,30 @@ public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { - e.printStackTrace(); + MatrixLog.printErrStackTrace(TAG, e, ""); } // malloc Log.d(TAG, "mallocTest: native heap:" + Debug.getNativeHeapSize() + ", allocated:" + Debug.getNativeHeapAllocatedSize() + ", free:" + Debug.getNativeHeapFreeSize()); - JNIObj.mallocTest(); +// JNIObj.mallocTest(); Log.d(TAG, "mallocTest after malloc: native heap:" + Debug.getNativeHeapSize() + ", allocated:" + Debug.getNativeHeapAllocatedSize() + ", free:" + Debug.getNativeHeapFreeSize()); - String output = getExternalCacheDir() + "/memory_hook.log"; - MemoryHook.INSTANCE.dump(output, output + ".json"); + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); // wait for async record + } catch (InterruptedException e) { + MatrixLog.printErrStackTrace(TAG, e, ""); + } + String output = getExternalCacheDir() + "/memory_hook.log"; + MemoryHook.INSTANCE.dump(output, output + ".json"); + } + }).start(); } public void threadTest(View view) { diff --git a/samples/sample-android/app/src/main/jni/MemObj.cpp b/samples/sample-android/app/src/main/jni/MemObj.cpp index 9332582f9..24dd1bd11 100644 --- a/samples/sample-android/app/src/main/jni/MemObj.cpp +++ b/samples/sample-android/app/src/main/jni/MemObj.cpp @@ -68,6 +68,10 @@ Java_sample_tencent_matrix_hooks_JNIObj_reallocTest(JNIEnv *env, jobject instanc } +class AllocTest { + int i; +}; + JNIEXPORT void JNICALL Java_sample_tencent_matrix_hooks_JNIObj_mallocTest(JNIEnv *env, jclass clazz) { // malloc_test(); @@ -75,8 +79,15 @@ Java_sample_tencent_matrix_hooks_JNIObj_mallocTest(JNIEnv *env, jclass clazz) { void *p = malloc(300 * 1024 * 1024); LOGD(TAG, "p = %p", p); free(p); - + p = new AllocTest; + LOGD(TAG, "p = %p", p); p = new int[1024]; // leak + LOGD(TAG, "p = %p", p); + + int *i = new int; + delete i; + int *ia = new int[100]; + delete[] ia; #undef LEN } From 9bd90143cb8a214f376a9f89f7d6a1e656cba0b2 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Sat, 3 Dec 2022 16:35:00 +0800 Subject: [PATCH 219/263] matrix-hooks: remove log --- .../matrix-hooks/src/main/cpp/memory/MemoryHookJNI.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookJNI.cpp b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookJNI.cpp index 050db5820..f48858978 100644 --- a/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookJNI.cpp +++ b/matrix/matrix-android/matrix-hooks/src/main/cpp/memory/MemoryHookJNI.cpp @@ -26,9 +26,6 @@ #include "MemoryHookFunctions.h" #include "MemoryHook.h" -#undef LOGD -#define LOGD(TAG, FMT, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, FMT, ##args) - #ifdef __cplusplus extern "C" { #endif @@ -37,12 +34,11 @@ extern "C" { do { \ FETCH_ORIGIN_FUNC_OF_SO(target_sym, target_so); \ if(!ORIGINAL_FUNC_NAME(target_sym)) { \ - LOGD(TAG, "hook failed: fetch origin func failed: %s", #target_sym); \ + LOGE(TAG, "hook failed: fetch origin func failed: %s", #target_sym); \ break; \ } \ int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, #target_sym, (void*) HANDLER_FUNC_NAME(target_sym), nullptr); \ LOGD(TAG, "hook fn, regex: %s, sym: %s, ret: %d", regex, #target_sym, ret); \ - \ } while(0); #define HOOK_REGISTER_REGEX_LIBC(target_sym) \ From 5de41b35e08bce5fe665e5de2c9aa07a72390fe1 Mon Sep 17 00:00:00 2001 From: kaedexie Date: Sun, 4 Dec 2022 15:55:24 +0800 Subject: [PATCH 220/263] Skip new added tid & pid --- .../monitor/feature/JiffiesMonitorFeature.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java index 898992643..31c93a8ba 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/JiffiesMonitorFeature.java @@ -318,7 +318,10 @@ protected JiffiesSnapshot computeDelta() { deltaThreadJiffies.name = endRecord.name; deltaThreadJiffies.stat = endRecord.stat; deltaThreadJiffies.isNewAdded = isNewAdded; - deltaThreadEntries.add(deltaThreadJiffies); + if (!isNewAdded) { + // Skip new added tid for now + deltaThreadEntries.add(deltaThreadJiffies); + } } } if (deltaThreadEntries.size() > 0) { @@ -569,8 +572,11 @@ protected UidJiffiesSnapshot computeDelta() { empty.threadNum = DigitEntry.of(0); last = empty; } - Delta deltaPidJiffies = end.diff(last); - delta.pidDeltaJiffiesList.add(deltaPidJiffies); + if (!end.isNewAdded) { + // Skip new added pid for now + Delta deltaPidJiffies = end.diff(last); + delta.pidDeltaJiffiesList.add(deltaPidJiffies); + } } Collections.sort(delta.pidDeltaJiffiesList, new Comparator>() { From fadebd50530f5abf2461c19641b68c9f44a6e092 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 9 Dec 2022 16:41:52 +0800 Subject: [PATCH 221/263] opengl-hook: add @keep for reflection --- .../com/tencent/matrix/openglleak/detector/FuncSeeker.java | 3 +++ .../java/com/tencent/matrix/openglleak/hook/OpenGLHook.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/FuncSeeker.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/FuncSeeker.java index 363a90ce8..596ca8a13 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/FuncSeeker.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/FuncSeeker.java @@ -1,7 +1,10 @@ package com.tencent.matrix.openglleak.detector; +import androidx.annotation.Keep; + import com.tencent.matrix.openglleak.comm.FuncNameString; +@Keep class FuncSeeker { public static int getFuncIndex(String targetFuncName) { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java index 1b5b54150..84baef5e9 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java @@ -2,6 +2,8 @@ import static android.opengl.GLES30.GL_PIXEL_UNPACK_BUFFER; +import androidx.annotation.Keep; + import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.BindCenter; import com.tencent.matrix.openglleak.statistics.resource.MemoryInfo; @@ -13,6 +15,7 @@ import java.util.concurrent.atomic.AtomicInteger; +@Keep public class OpenGLHook { static { From 60edc461781f1f8828e4e1fa7d7512bb2cba3d40 Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 9 Dec 2022 19:41:13 +0800 Subject: [PATCH 222/263] opengl-hook: support for share context --- ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 6 +- ...encent_matrix_openglleak_hook_OpenGLHook.h | 4 +- .../src/main/cpp/my_functions.h | 6 +- .../matrix/openglleak/OpenglLeakPlugin.java | 6 +- .../matrix/openglleak/hook/OpenGLHook.java | 24 +++-- .../statistics/resource/OpenGLInfo.java | 2 +- .../statistics/resource/ResRecordManager.java | 55 ++++++++++-- .../matrix/openglleak/utils/EGLHelper.java | 75 ++++++++++++++-- .../openglhook/OpenglHookTestActivity.java | 90 +++++++++++++++++++ .../res/layout/activity_opengl_leak_test.xml | 8 ++ 10 files changed, 243 insertions(+), 33 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp index f04e6aa96..9f81187be 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp @@ -66,7 +66,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_getThrowable = env->GetStaticMethodID(class_OpenGLHook, "getThrowable", "()I"); method_onEglContextCreate = env->GetStaticMethodID(class_OpenGLHook, "onEglContextCreate", - "(Ljava/lang/String;IJJLjava/lang/String;)V"); + "(Ljava/lang/String;IJJJLjava/lang/String;)V"); method_onEglContextDestroy = env->GetStaticMethodID(class_OpenGLHook, "onEglContextDestroy", "(Ljava/lang/String;J)V"); @@ -103,7 +103,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { extern "C" JNIEXPORT jboolean JNICALL -Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglCreate(JNIEnv *env, jclass clazz) { +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglCreateContext(JNIEnv *env, jclass clazz) { bool ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_EGL_HOOK, ".*\\.so$", "eglCreateContext", (void *) my_egl_context_create, (void **) (&system_eglCreateContext)) == 0; xhook_refresh(true); @@ -112,7 +112,7 @@ Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglCreate(JNIEnv *env, jc extern "C" JNIEXPORT jboolean JNICALL -Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglDestory(JNIEnv *env, jclass clazz) { +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglDestroyContext(JNIEnv *env, jclass clazz) { bool ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_EGL_HOOK, ".*\\.so$", "eglDestroyContext", (void *) my_egl_context_destroy, (void **) (&system_eglDestroyContext)) == 0; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.h index 15bdd9542..53349013c 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.h @@ -161,11 +161,11 @@ Java_com_tencent_matrix_openglleak_hook_OpenGLHook_getResidualQueueSize(JNIEnv * extern "C" JNIEXPORT jboolean JNICALL -Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglCreate(JNIEnv *env, jclass clazz); +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglCreateContext(JNIEnv *env, jclass clazz); extern "C" JNIEXPORT jboolean JNICALL -Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglDestory(JNIEnv *env, jclass clazz); +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookEglDestroyContext(JNIEnv *env, jclass clazz); #ifdef __cplusplus } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h index 8f87d908e..54741cfa5 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/my_functions.h @@ -835,7 +835,7 @@ my_egl_context_create(EGLDisplay dpy, EGLConfig config, EGLContext share_context messages_containers ->enqueue_message((uintptr_t) ret, - [backtracePrt, throwable, thread_id_c_str, ret, activity_info]() { + [backtracePrt, throwable, thread_id_c_str, ret, share_context, activity_info]() { JNIEnv *env = GET_ENV(); @@ -850,7 +850,9 @@ my_egl_context_create(EGLDisplay dpy, EGLConfig config, EGLContext share_context j_thread_id, (jint) throwable, (jlong) backtrace, - (jlong) ret, j_activity_info); + (jlong) ret, + (jlong) share_context, + j_activity_info); env->DeleteLocalRef(j_activity_info); env->DeleteLocalRef(j_thread_id); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java index 7c1de5599..e5cda2a8d 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java @@ -99,6 +99,8 @@ private void executeHook(IBinder iBinder) { } // hook + OpenGLHook.hookEglCreateContext(); + OpenGLHook.hookEglDestroyContext(); // hook eglCreateContext/eglDestroyContext first OpenGLHook.getInstance().hook(FuncNameString.GL_GEN_TEXTURES, map.get(FuncNameString.GL_GEN_TEXTURES)); OpenGLHook.getInstance().hook(FuncNameString.GL_DELETE_TEXTURES, map.get(FuncNameString.GL_DELETE_TEXTURES)); OpenGLHook.getInstance().hook(FuncNameString.GL_GEN_BUFFERS, map.get(FuncNameString.GL_GEN_BUFFERS)); @@ -115,11 +117,9 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_RENDERBUFFER, map.get(FuncNameString.GL_BIND_RENDERBUFFER)); OpenGLHook.getInstance().hook(FuncNameString.GL_BUFFER_DATA, map.get(FuncNameString.GL_BUFFER_DATA)); OpenGLHook.getInstance().hook(FuncNameString.GL_RENDER_BUFFER_STORAGE, map.get(FuncNameString.GL_RENDER_BUFFER_STORAGE)); - OpenGLHook.getInstance().hookEglCreate(); - OpenGLHook.getInstance().hookEglDestory(); MatrixLog.e(TAG, "hook finish"); } catch (Throwable e) { - e.printStackTrace(); + MatrixLog.printErrStackTrace(TAG, e, ""); } finally { // 销毁实验进程 try { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java index 84baef5e9..a2de3eea8 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/hook/OpenGLHook.java @@ -134,9 +134,9 @@ public boolean hook(String targetFuncName, int index) { private static native boolean hookGlRenderbufferStorage(int index); - public static native boolean hookEglCreate(); + public static native boolean hookEglCreateContext(); - public static native boolean hookEglDestory(); + public static native boolean hookEglDestroyContext(); public static native String dumpNativeStack(long nativeStackPtr); @@ -266,25 +266,27 @@ public static void onGlDeleteRenderbuffers(int[] ids, String threadId, final lon } } - public static void onEglContextCreate(String threadId, final int throwable, long nativeStackPtr, final long eglContext, String activityInfo) { + public static void onEglContextCreate(String threadId, final int throwable, long nativeStackPtr, final long eglContext, final long shareContext, String activityInfo) { AtomicInteger counter = new AtomicInteger(1); JavaStacktrace.Trace trace = JavaStacktrace.getBacktraceValue(throwable); final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.EGL_CONTEXT, -1, threadId, eglContext, 0, 0, trace, nativeStackPtr, ActivityRecorder.revertActivityInfo(activityInfo), counter); ResRecordManager.getInstance().gen(openGLInfo); + ResRecordManager.getInstance().shareContext(shareContext, eglContext); if (getInstance().mResourceListener != null) { - getInstance().mResourceListener.onGlGenRenderbuffers(openGLInfo); + getInstance().mResourceListener.onEglContextCreate(openGLInfo); } } public static void onEglContextDestroy(String threadId, final long eglContext) { final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.EGL_CONTEXT, -1, threadId, eglContext); ResRecordManager.getInstance().delete(openGLInfo); + ResRecordManager.getInstance().removeSharedContextIfNeeded(eglContext); if (getInstance().mResourceListener != null) { - getInstance().mResourceListener.onGlDeleteRenderbuffers(openGLInfo); + getInstance().mResourceListener.onEglContextDestroy(openGLInfo); } } @@ -346,7 +348,7 @@ public static void onGlBindRenderbuffer(final int target, final int id, final lo public static void onGlTexImage2D(final int target, final int level, final int internalFormat, final int width, final int height, final int border, final int format, final int type, final long size, final int throwable, final long nativeStack, final long eglContext) { final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContext, target); if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe undo glBindTextures()"); + MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe didn't call glBindTextures()"); return; } @@ -366,7 +368,7 @@ public static void onGlTexImage2D(final int target, final int level, final int i public static void onGlTexImage3D(final int target, final int level, final int internalFormat, final int width, final int height, final int depth, final int border, final int format, final int type, final long size, final int throwable, final long nativeStack, final long eglContext) { final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContext, target); if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe undo glBindTextures()"); + MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe didn't call glBindTextures()"); return; } @@ -386,7 +388,7 @@ public static void onGlTexImage3D(final int target, final int level, final int i public static void onGlBufferData(final int target, final int usage, final long size, final int throwable, final long nativeStack, final long eglContext) { final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, eglContext, target); if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe undo glBindBuffer()"); + MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe didn't call glBindBuffer()"); return; } @@ -414,7 +416,7 @@ public static void onGlBufferData(final int target, final int usage, final long public static void onGlRenderbufferStorage(final int target, final int internalformat, final int width, final int height, final long size, final int key, final long nativeStack, final long eglContext) { final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContext, target); if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe undo glBindRenderbuffer()"); + MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe didn't call glBindRenderbuffer()"); return; } @@ -463,6 +465,10 @@ public interface MemoryListener { public interface ResourceListener { + void onEglContextCreate(OpenGLInfo info); + + void onEglContextDestroy(OpenGLInfo info); + void onGlGenTextures(OpenGLInfo info); void onGlDeleteTextures(OpenGLInfo info); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java index ef2b85d5d..7b60f73ce 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java @@ -157,7 +157,7 @@ public String toString() { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || !(o instanceof OpenGLInfo)) return false; + if (!(o instanceof OpenGLInfo)) return false; OpenGLInfo that = (OpenGLInfo) o; return id == that.id && getEglContextNativeHandle() == that.getEglContextNativeHandle() && diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java index 968ac51a0..546fe7bfe 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java @@ -4,6 +4,7 @@ import com.tencent.matrix.openglleak.hook.OpenGLHook; import com.tencent.matrix.openglleak.utils.AutoWrapBuilder; +import com.tencent.matrix.util.MatrixLog; import java.io.BufferedWriter; import java.io.File; @@ -14,20 +15,24 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; public class ResRecordManager { + private static final String TAG = "Matrix.ResRecordManager"; private static final ResRecordManager mInstance = new ResRecordManager(); private final List mCallbackList = new LinkedList<>(); private final List mInfoList = new LinkedList<>(); - private final List mReleaseContext = new LinkedList<>(); private final List mReleaseSurface = new LinkedList<>(); + private final Map> mContextGroup = new HashMap<>(); + private ResRecordManager() { } @@ -36,6 +41,32 @@ public static ResRecordManager getInstance() { return mInstance; } + public void shareContext(Long shareContext, Long newContext) { + if (shareContext != 0) { + synchronized (mContextGroup) { + Set group = mContextGroup.get(shareContext); + if (group == null) { + group = new HashSet<>(); + mContextGroup.put(shareContext, group); + } + mContextGroup.put(newContext, group); + group.add(newContext); + group.add(shareContext); + } + } + } + + public void removeSharedContextIfNeeded(Long context) { + synchronized (mContextGroup) { + if (mContextGroup.containsKey(context)) { + Set group = mContextGroup.remove(context); + if (group != null) { + group.remove(context); + } + } + } + } + public void gen(final OpenGLInfo gen) { if (gen == null) { return; @@ -54,7 +85,7 @@ public void gen(final OpenGLInfo gen) { } } - public void delete(final OpenGLInfo del) { + public void delete(OpenGLInfo del) { if (del == null) { return; } @@ -62,7 +93,22 @@ public void delete(final OpenGLInfo del) { synchronized (mInfoList) { // 之前可能释放过 int index = mInfoList.indexOf(del); + + Set group = mContextGroup.get(del.getEglContextNativeHandle()); + + if (-1 == index && group != null) { // is shared context + for (Long ctx : group) { + OpenGLInfo sharedInfo = new OpenGLInfo(del.getType(), del.getId(), del.getThreadId(), ctx); + index = mInfoList.indexOf(sharedInfo); + if (index != -1) { + MatrixLog.d(TAG, "del info found with shared context: %d, %s", index, ctx); + break; + } + } + } + if (-1 == index) { + MatrixLog.d(TAG, "del info not found"); return; } @@ -89,7 +135,7 @@ public void delete(final OpenGLInfo del) { } } - mInfoList.remove(del); + mInfoList.remove(info); } synchronized (mCallbackList) { @@ -172,9 +218,6 @@ public void clear() { synchronized (mInfoList) { mInfoList.clear(); } - synchronized (mReleaseContext) { - mReleaseContext.clear(); - } } public boolean isEglContextReleased(OpenGLInfo info) { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/EGLHelper.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/EGLHelper.java index cdbce64e1..96f8cdbf1 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/EGLHelper.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/EGLHelper.java @@ -20,15 +20,15 @@ public class EGLHelper { @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) - public static void initOpenGL() { + public static EGLContext initOpenGL() { mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) { - return; + return null; } int[] version = new int[2]; if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) { - return; + return null; } int[] eglConfigAttribList = new int[]{ @@ -41,7 +41,7 @@ public static void initOpenGL() { EGLConfig[] eglConfigs = new EGLConfig[1]; if (!EGL14.eglChooseConfig(mEGLDisplay, eglConfigAttribList, 0, eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) { - return; + return null; } mEglConfig = eglConfigs[0]; @@ -53,7 +53,7 @@ public static void initOpenGL() { mEglContext = EGL14.eglCreateContext(mEGLDisplay, mEglConfig, EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0); if (mEglContext == EGL14.EGL_NO_CONTEXT) { - return; + return null; } int[] surfaceAttribList = { @@ -65,14 +65,75 @@ public static void initOpenGL() { // Java 线程不进行实际绘制,因此创建 PbufferSurface 而非 WindowSurface mEglSurface = EGL14.eglCreatePbufferSurface(mEGLDisplay, mEglConfig, surfaceAttribList, 0); if (mEglSurface == EGL14.EGL_NO_SURFACE) { - return; + return null; } if (!EGL14.eglMakeCurrent(mEGLDisplay, mEglSurface, mEglSurface, mEglContext)) { - return; + return null; } GLES20.glFlush(); + return mEglContext; } + + public static EGLContext initOpenGLSharedContext(EGLContext shareContext) { + if (shareContext == null) { + return null; + } + + EGLDisplay eGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + if (eGLDisplay == EGL14.EGL_NO_DISPLAY) { + return null; + } + + int[] version = new int[2]; + if (!EGL14.eglInitialize(eGLDisplay, version, 0, version, 1)) { + return null; + } + + int[] eglConfigAttribList = new int[]{ + EGL14.EGL_RED_SIZE, 8, + EGL14.EGL_GREEN_SIZE, 8, + EGL14.EGL_BLUE_SIZE, 8, + EGL14.EGL_NONE + }; + int[] numEglConfigs = new int[1]; + EGLConfig[] eglConfigs = new EGLConfig[1]; + if (!EGL14.eglChooseConfig(eGLDisplay, eglConfigAttribList, 0, eglConfigs, 0, + eglConfigs.length, numEglConfigs, 0)) { + return null; + } + + int[] eglContextAttribList = new int[]{ + EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, + EGL14.EGL_NONE + }; + + EGLContext eglContext = EGL14.eglCreateContext(eGLDisplay, eglConfigs[0], shareContext, eglContextAttribList, 0); + + if (eglContext == EGL14.EGL_NO_CONTEXT) { + return null; + } + + int[] surfaceAttribList = { + EGL14.EGL_WIDTH, 64, + EGL14.EGL_HEIGHT, 64, + EGL14.EGL_NONE + }; + + // Java 线程不进行实际绘制,因此创建 PbufferSurface 而非 WindowSurface + mEglSurface = EGL14.eglCreatePbufferSurface(eGLDisplay, eglConfigs[0], surfaceAttribList, 0); + if (mEglSurface == EGL14.EGL_NO_SURFACE) { + return null; + } + + if (!EGL14.eglMakeCurrent(eGLDisplay, mEglSurface, mEglSurface, eglContext)) { + return null; + } + + GLES20.glFlush(); + + return eglContext; + } } diff --git a/matrix/matrix-android/test/test-openglhook/src/main/java/com/example/openglhook/OpenglHookTestActivity.java b/matrix/matrix-android/test/test-openglhook/src/main/java/com/example/openglhook/OpenglHookTestActivity.java index 01e56a94f..6a003cce0 100644 --- a/matrix/matrix-android/test/test-openglhook/src/main/java/com/example/openglhook/OpenglHookTestActivity.java +++ b/matrix/matrix-android/test/test-openglhook/src/main/java/com/example/openglhook/OpenglHookTestActivity.java @@ -9,6 +9,7 @@ import android.app.Application; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.opengl.EGLContext; import android.opengl.GLES20; import android.opengl.GLUtils; import android.os.Bundle; @@ -26,9 +27,13 @@ import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; import com.tencent.matrix.openglleak.utils.EGLHelper; +import com.tencent.matrix.util.MatrixLog; +import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.nio.ByteBuffer; import java.nio.IntBuffer; @@ -334,4 +339,89 @@ public void onLeak(OpenGLInfo info) { // }); } + EGLContext initContext = null; + + public void testGLSharedContext(View view) { + + HandlerThread thread1 = new HandlerThread("thread1"); + thread1.start(); + Handler handler1 = new Handler(thread1.getLooper()); + + HandlerThread thread2 = new HandlerThread("thread2"); + thread2.start(); + final Handler handler2 = new Handler(thread2.getLooper()); + + + final int totalCount = 1; + final int[] textures = new int[totalCount]; + final int[] buffers = new int[totalCount]; + final int[] renderBuffers = new int[totalCount]; + final int[] frameBuffers = new int[totalCount]; + + handler1.post(new Runnable() { + @Override + public void run() { + initContext = EGLHelper.initOpenGL(); + MatrixLog.i(TAG, "init Context = %s", initContext.getNativeHandle()); + for (int i = 0; i < totalCount; i++) { + GLES20.glGenRenderbuffers(1, renderBuffers, i); + GLES20.glGenTextures(1, textures, i); + GLES20.glGenBuffers(1, buffers, i); + GLES20.glGenFramebuffers(1, frameBuffers, i); + } + + handler2.post(new Runnable() { + @Override + public void run() { + EGLContext sharedContext = EGLHelper.initOpenGLSharedContext(initContext); + MatrixLog.i(TAG, "shared Context = %s", sharedContext.getNativeHandle()); + for (int i = 0; i < totalCount; i++) { + GLES20.glDeleteRenderbuffers(1, renderBuffers, i); + GLES20.glDeleteTextures(1, textures, i); + GLES20.glDeleteBuffers(1, buffers, i); + GLES20.glDeleteFramebuffers(1, frameBuffers, i); + } + } + }); + } + }); + + handler1.postDelayed(new Runnable() { + @Override + public void run() { + MatrixLog.i(TAG, "dump..."); + dump(); + } + }, 5000); + } + + private void dump() { + final String dirPath = getApplication().getExternalCacheDir() + "/OpenGLHook"; + final String filePath = dirPath + "/" + Process.myPid() + "_opengl_dump.txt"; + File dirFile = new File(dirPath); + if (!dirFile.exists()) { + dirFile.mkdirs(); + } + File dumpFile = new File(filePath); + if (dumpFile.exists()) { + dumpFile.delete(); + } + try { + dumpFile.createNewFile(); + } catch (IOException e) { + MatrixLog.printErrStackTrace(TAG, e, ""); + } + + ResRecordManager.getInstance().dumpGLToFile(filePath); + + try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)))){ + String line; + while ((line = br.readLine()) != null) { + MatrixLog.i(TAG, line); + } + } catch (IOException e) { + MatrixLog.printErrStackTrace(TAG, e, ""); + } + } + } \ No newline at end of file diff --git a/matrix/matrix-android/test/test-openglhook/src/main/res/layout/activity_opengl_leak_test.xml b/matrix/matrix-android/test/test-openglhook/src/main/res/layout/activity_opengl_leak_test.xml index 18ec6f950..6cba47ea4 100644 --- a/matrix/matrix-android/test/test-openglhook/src/main/res/layout/activity_opengl_leak_test.xml +++ b/matrix/matrix-android/test/test-openglhook/src/main/res/layout/activity_opengl_leak_test.xml @@ -63,5 +63,13 @@ android:layout_marginBottom="10dp" android:layout_height="50dp" /> +