From 278ff0896e51248f6a2db899503996853ae240fb Mon Sep 17 00:00:00 2001 From: Fenglei Dou Date: Mon, 2 Aug 2021 14:07:19 +0800 Subject: [PATCH 001/163] Create ks2apple.py update to the latest device for iPhone and iPad --- matrix/matrix-iOS/Script/ks2apple.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-iOS/Script/ks2apple.py b/matrix/matrix-iOS/Script/ks2apple.py index 390ba8b64..78cb3f4b9 100644 --- a/matrix/matrix-iOS/Script/ks2apple.py +++ b/matrix/matrix-iOS/Script/ks2apple.py @@ -33,6 +33,11 @@ 'iPad4,4' : 'iPad mini 2G', 'iPad4,5' : 'iPad mini 2G', 'iPad4,6' : 'iPad mini 2G', + 'iPad4,7' : 'iPad mini 3', + 'iPad4,8' : 'iPad mini 3', + 'iPad4,9' : 'iPad mini 3', + 'iPad5,1' : 'iPad mini 4', + 'iPad5,2' : 'iPad mini 4', 'iPad1,1' : 'iPad 1G', 'iPad2,1' : 'iPad 2', @@ -48,6 +53,19 @@ 'iPad4,1' : 'iPad Air', 'iPad4,2' : 'iPad Air', 'iPad4,3' : 'iPad Air', + 'iPad5,3' : 'iPad Air 2', + 'iPad5,4' : 'iPad Air 2', + 'iPad6,3' : 'iPad Pro 9.7-inch', + 'iPad6,4' : 'iPad Pro 9.7-inch', + 'iPad6,7' : 'iPad Pro 12.9-inch', + 'iPad6,8' : 'iPad Pro 12.9-inch', + 'iPad6,11' : 'iPad 5', + 'iPad6,12' : 'iPad 5', + 'iPad7,11' : 'iPad 6', + 'iPad7,12' : 'iPad 6', + 'iPad7,1' : 'iPad Pro 12.9-inch 2', + 'iPad7,2' : 'iPad Pro 12.9-inch 2', + 'iPad7,3' : 'iPad Pro 10.5-inch', 'iPhone1,1' : 'iPhone', @@ -83,6 +101,13 @@ 'iPhone11,4' : 'iPhone XS Max', 'iPhone11,6' : 'iPhone XS Max', 'iPhone11,8' : 'iPhone XR', + 'iPhone12,1' : 'iPhone 11', + 'iPhone12,3' : 'iPhone 11 Pro', + 'iPhone12,5' : 'iPhone 11 Pro Max', + 'iPhone13,1' : 'iPhone 12 mini', + 'iPhone13,2' : 'iPhone 12', + 'iPhone13,3' : 'iPhone 12 Pro', + 'iPhone13,4' : 'iPhone 12 Pro Max', } def dump_json(obj): @@ -850,4 +875,4 @@ def ks_json_2_apple(report, fout): else: ks_json_2_apple(reports, fout) - fout.close() \ No newline at end of file + fout.close() From 250254279a7732ac99c219ecf7f24f15dfe0acae Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 27 Oct 2021 21:45:54 +0800 Subject: [PATCH 002/163] Refactor battery with composite monitors --- .../monitor/feature/MonitorCompositeTest.java | 148 +++ .../feature/MonitorFeatureOverAllTest.java | 3 + .../monitor/BatteryMonitorCallback.java | 945 +++++++++++------- .../monitor/feature/CompositeMonitors.java | 118 ++- 4 files changed, 826 insertions(+), 388 deletions(-) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java new file mode 100644 index 000000000..25417e521 --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java @@ -0,0 +1,148 @@ +/* + * 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.monitor.feature; + +import android.app.Application; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; + +import com.tencent.matrix.Matrix; +import com.tencent.matrix.batterycanary.BatteryEventDelegate; +import com.tencent.matrix.batterycanary.BatteryMonitorPlugin; +import com.tencent.matrix.batterycanary.TestUtils; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; + +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; + + +@RunWith(AndroidJUnit4.class) +public class MonitorCompositeTest { + static final String TAG = "Matrix.test.MonitorFeatureOverAllTest"; + + Context mContext; + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + if (!Matrix.isInstalled()) { + Matrix.init(new Matrix.Builder(((Application) mContext.getApplicationContext())).build()); + } + if (!BatteryEventDelegate.isInit()) { + BatteryEventDelegate.init((Application) mContext.getApplicationContext()); + } + } + + @After + public void shutDown() { + } + + private BatteryMonitorCore mockMonitor() { + BatteryMonitorConfig config = new BatteryMonitorConfig.Builder() + .enable(JiffiesMonitorFeature.class) + .enable(LooperTaskMonitorFeature.class) + .enable(WakeLockMonitorFeature.class) + .enable(DeviceStatMonitorFeature.class) + .enable(AlarmMonitorFeature.class) + .enable(AppStatMonitorFeature.class) + .enable(BlueToothMonitorFeature.class) + .enable(WifiMonitorFeature.class) + .enable(LocationMonitorFeature.class) + .enable(TrafficMonitorFeature.class) + .enable(NotificationMonitorFeature.class) + .enable(CpuStatFeature.class) + .enableBuiltinForegroundNotify(false) + .enableForegroundMode(true) + .wakelockTimeout(1000) + .greyJiffiesTime(100) + .foregroundLoopCheckTime(1000) + .build(); + return new BatteryMonitorCore(config); + } + + @Test + public void testMetric() { + final BatteryMonitorCore monitor = mockMonitor(); + BatteryMonitorPlugin plugin = new BatteryMonitorPlugin(monitor.getConfig()); + Matrix.with().getPlugins().add(plugin); + monitor.enableForegroundLoopCheck(true); + monitor.start(); + + CompositeMonitors compositeMonitor = new CompositeMonitors(monitor); + Assert.assertNull(compositeMonitor.mBgnSnapshots.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); + Assert.assertNull(compositeMonitor.mBgnSnapshots.get(CpuStatFeature.CpuStateSnapshot.class)); + compositeMonitor.metric(JiffiesMonitorFeature.JiffiesSnapshot.class); + compositeMonitor.configureSnapshots(); + Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); + Assert.assertNull(compositeMonitor.mBgnSnapshots.get(CpuStatFeature.CpuStateSnapshot.class)); + Assert.assertNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); + Assert.assertNull(compositeMonitor.mDeltas.get(CpuStatFeature.CpuStateSnapshot.class)); + compositeMonitor.configureDeltas(); + Assert.assertNotNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); + Assert.assertNull(compositeMonitor.mDeltas.get(CpuStatFeature.CpuStateSnapshot.class)); + + compositeMonitor.clear(); + compositeMonitor + .metric(JiffiesMonitorFeature.JiffiesSnapshot.class) + .metric(CpuStatFeature.CpuStateSnapshot.class); + compositeMonitor.configureSnapshots(); + Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); + Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(CpuStatFeature.CpuStateSnapshot.class)); + Assert.assertNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); + Assert.assertNull(compositeMonitor.mDeltas.get(CpuStatFeature.CpuStateSnapshot.class)); + compositeMonitor.configureDeltas(); + Assert.assertNotNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); + Assert.assertNotNull(compositeMonitor.mDeltas.get(CpuStatFeature.CpuStateSnapshot.class)); + } + + @Test + public void testMetricAll() { + final BatteryMonitorCore monitor = mockMonitor(); + BatteryMonitorPlugin plugin = new BatteryMonitorPlugin(monitor.getConfig()); + Matrix.with().getPlugins().add(plugin); + monitor.enableForegroundLoopCheck(true); + monitor.start(); + + CompositeMonitors compositeMonitor = new CompositeMonitors(monitor); + compositeMonitor.metricAll(); + + for (Class> item : compositeMonitor.mMetrics) { + Assert.assertNull(compositeMonitor.mBgnSnapshots.get(item)); + } + + compositeMonitor.configureSnapshots(); + + for (Class> item : compositeMonitor.mMetrics) { + Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(item)); + Assert.assertNull(compositeMonitor.mDeltas.get(item)); + } + + compositeMonitor.configureDeltas(); + + for (Class> item : compositeMonitor.mMetrics) { + Assert.assertNotNull(compositeMonitor.mDeltas.get(item)); + } + } +} 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 936a9a91e..d3b0b77fe 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 @@ -66,6 +66,9 @@ private BatteryMonitorCore mockMonitor() { .enable(AppStatMonitorFeature.class) .enable(BlueToothMonitorFeature.class) .enable(CpuStatFeature.class) + .enable(TrafficMonitorFeature.class) + .enable(WifiMonitorFeature.class) + .enable(LocationMonitorFeature.class) .enableBuiltinForegroundNotify(false) .enableForegroundMode(true) .wakelockTimeout(1000) 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 ee58efa10..022844520 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 @@ -50,7 +50,6 @@ import androidx.annotation.CallSuper; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; /** @@ -75,16 +74,16 @@ class BatteryPrinter implements BatteryMonitorCallback { protected BatteryMonitorCore mMonitor; @NonNull protected CompositeMonitors mCompositeMonitors; - protected final Printer mPrinter = new Printer(); protected long mTraceBgnMillis; protected boolean mIsForeground; - @Nullable - AppStats mAppStats; - protected final LongSparseArray> tasks = new LongSparseArray<>(); // TODO: Remove deprecated fields @Deprecated + protected Printer mPrinter = new Printer(); + @Deprecated + protected final LongSparseArray> tasks = new LongSparseArray<>(); + @Deprecated protected AlarmMonitorFeature mAlarmFeat; @Deprecated protected AppStatMonitorFeature mAppStatFeat; @@ -131,6 +130,7 @@ class BatteryPrinter implements BatteryMonitorCallback { public BatteryPrinter attach(BatteryMonitorCore monitorCore) { mMonitor = monitorCore; mCompositeMonitors = new CompositeMonitors(monitorCore); + mCompositeMonitors.metricAll(); return this; } @@ -143,9 +143,10 @@ protected boolean isForegroundReport() { return mIsForeground; } + @Deprecated protected AppStats getAppStats() { - if (mAppStats != null) { - return mAppStats; + if (mCompositeMonitors.getAppStats() != null) { + return mCompositeMonitors.getAppStats(); } return AppStats.current(); } @@ -155,7 +156,7 @@ protected AppStats getAppStats() { public void onTraceBegin() { mTraceBgnMillis = SystemClock.uptimeMillis(); mCompositeMonitors.clear(); - mCompositeMonitors.configureAllSnapshot(); + mCompositeMonitors.configureSnapshots(); // TODO: Remove deprecated statements // Configure begin snapshots @@ -216,11 +217,8 @@ public void onTraceEnd(boolean isForeground) { MatrixLog.w(TAG, "skip invalid battery tracing, bgn = " + mTraceBgnMillis + ", during = " + duringMillis); return; } - - mAppStats = AppStats.current(duringMillis).setForeground(isForeground); mCompositeMonitors.configureDeltas(); - onCanaryDump(mAppStats); - mAppStats = null; + onCanaryDump(mCompositeMonitors); } @Override @@ -340,421 +338,642 @@ public void onForegroundServiceLeak(boolean isMyself, int appImportance, int glo public void onAppSateLeak(boolean isMyself, int appImportance, ComponentName componentName, long millis) { } - - @CallSuper - protected void onCanaryDump(AppStats appStats) { - mPrinter.clear(); - - // title - mPrinter.writeTitle(); - - // sections - onWritingJiffiesSection(appStats); - onWritingSections(appStats); - onWritingAppStatSection(appStats); - - // end - mPrinter.writeEnding(); - mPrinter.dump(); - synchronized (tasks) { - tasks.clear(); - } - } - - @CallSuper - protected void onWritingJiffiesSection(final AppStats appStats) { - mCompositeMonitors.getDelta(JiffiesSnapshot.class, new Consumer>() { + protected void checkBadThreads(final CompositeMonitors monitors) { + monitors.getDelta(JiffiesSnapshot.class, new Consumer>() { @Override public void accept(final Delta delta) { - final long minute = appStats.getMinute(); - for (final ThreadJiffiesEntry threadJiffies : delta.dlt.threadEntries.getList()) { - if (!threadJiffies.stat.toUpperCase().contains("R")) { - continue; - } - mCompositeMonitors.getFeature(JiffiesMonitorFeature.class, new Consumer() { - @Override - public void accept(JiffiesMonitorFeature feature) { - // Watching thread state when thread is: - // 1. still running (status 'R') - // 2. runing time > 10min - // 3. avgJiffies > THRESHOLD - long avgJiffies = threadJiffies.get() / minute; - if (appStats.isForeground()) { - if (minute > 10 && avgJiffies > getMonitor().getConfig().fgThreadWatchingLimit) { - MatrixLog.i(TAG, "threadWatchDog fg set, name = " + delta.dlt.name - + ", pid = " + delta.dlt.pid - + ", tid = " + threadJiffies.tid); - feature.watchBackThreadSate(true, delta.dlt.pid, threadJiffies.tid); - } - } else { - if (minute > 10 && avgJiffies > getMonitor().getConfig().bgThreadWatchingLimit) { - MatrixLog.i(TAG, "threadWatchDog bg set, name = " + delta.dlt.name - + ", pid = " + delta.dlt.pid - + ", tid = " + threadJiffies.tid); - feature.watchBackThreadSate(false, delta.dlt.pid, threadJiffies.tid); - } + monitors.getAppStats(new Consumer() { + @Override + public void accept(final AppStats appStats) { + + final long minute = appStats.getMinute(); + for (final ThreadJiffiesEntry threadJiffies : delta.dlt.threadEntries.getList()) { + if (!threadJiffies.stat.toUpperCase().contains("R")) { + continue; } + monitors.getFeature(JiffiesMonitorFeature.class, new Consumer() { + @Override + public void accept(JiffiesMonitorFeature feature) { + // Watching thread state when thread is: + // 1. still running (status 'R') + // 2. runing time > 10min + // 3. avgJiffies > THRESHOLD + long avgJiffies = threadJiffies.get() / minute; + if (appStats.isForeground()) { + if (minute > 10 && avgJiffies > getMonitor().getConfig().fgThreadWatchingLimit) { + MatrixLog.i(TAG, "threadWatchDog fg set, name = " + delta.dlt.name + + ", pid = " + delta.dlt.pid + + ", tid = " + threadJiffies.tid); + feature.watchBackThreadSate(true, delta.dlt.pid, threadJiffies.tid); + } + } else { + if (minute > 10 && avgJiffies > getMonitor().getConfig().bgThreadWatchingLimit) { + MatrixLog.i(TAG, "threadWatchDog bg set, name = " + delta.dlt.name + + ", pid = " + delta.dlt.pid + + ", tid = " + threadJiffies.tid); + feature.watchBackThreadSate(false, delta.dlt.pid, threadJiffies.tid); + } + } + } + }); } - }); - } - onReportJiffies(delta); - onWritingSectionContent(delta, appStats, mPrinter); + } + }); } }); } - @CallSuper - protected void onWritingAppStatSection(final AppStats appStats) { - createSection("app_stats", new Consumer() { + protected Dumper createDumper() { + return new Dumper() { @Override - public void accept(final Printer printer) { - printer.createSubSection("stat_time"); - printer.writeLine("time", appStats.getMinute() + "(min)"); - printer.writeLine("fg", String.valueOf(appStats.appFgRatio)); - printer.writeLine("bg", String.valueOf(appStats.appBgRatio)); - printer.writeLine("fgSrv", String.valueOf(appStats.appFgSrvRatio)); - printer.writeLine("devCharging", String.valueOf(appStats.devChargingRatio)); - printer.writeLine("devScreenOff", String.valueOf(appStats.devSceneOffRatio)); - if (!TextUtils.isEmpty(appStats.sceneTop1)) { - printer.writeLine("sceneTop1", appStats.sceneTop1 + "/" + appStats.sceneTop1Ratio); - } - if (!TextUtils.isEmpty(appStats.sceneTop2)) { - printer.writeLine("sceneTop2", appStats.sceneTop2 + "/" + appStats.sceneTop2Ratio); - } - mCompositeMonitors.getFeature(AppStatMonitorFeature.class, new Consumer() { + protected void onWritingSections(CompositeMonitors monitors, Printer printer) { + super.onWritingSections(monitors, printer); + monitors.getAppStats(new Consumer() { @Override - public void accept(AppStatMonitorFeature feature) { - AppStatMonitorFeature.AppStatSnapshot currSnapshot = feature.currentAppStatSnapshot(); - printer.createSubSection("run_time"); - printer.writeLine("time", currSnapshot.uptime.get() / ONE_MIN + "(min)"); - printer.writeLine("fg", String.valueOf(currSnapshot.fgRatio.get())); - printer.writeLine("bg", String.valueOf(currSnapshot.bgRatio.get())); - printer.writeLine("fgSrv", String.valueOf(currSnapshot.fgSrvRatio.get())); + public void accept(AppStats appStats) { + BatteryPrinter.this.onWritingSections(appStats); } }); } - }); + + @Override + protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, CompositeMonitors monitors, Printer printer) { + if (!super.onWritingSectionContent(sessionDelta, monitors, printer)) { + AppStats appStats = monitors.getAppStats(); + if (appStats != null) { + return BatteryPrinter.this.onWritingSectionContent(sessionDelta, appStats, printer); + } + } + return false; + } + }; + } + + protected Printer createPrinter() { + // TODO: Remove deprecated statements + mPrinter = new Printer(); + return mPrinter; } @CallSuper - protected void onWritingSections(final AppStats appStats) { - if (/**/(mCompositeMonitors.getDelta(AlarmSnapshot.class) != null) - || (mCompositeMonitors.getDelta(WakeLockSnapshot.class) != null) - ) { - // Alarm, WakeLock - createSection("awake", new Consumer() { - @Override - public void accept(Printer printer) { - mCompositeMonitors.getDelta(AlarmSnapshot.class, new Consumer>() { - @Override - public void accept(Delta delta) { - onReportAlarm(delta); - onWritingSectionContent(delta, appStats, mPrinter); - } - }); - mCompositeMonitors.getDelta(WakeLockSnapshot.class, new Consumer>() { - @Override - public void accept(Delta delta) { - onReportWakeLock(delta); - onWritingSectionContent(delta, appStats, mPrinter); - } - }); - } - }); - } + protected void onCanaryDump(final CompositeMonitors monitors) { + monitors.getAppStats(new Consumer() { + @Override + public void accept(AppStats appStats) { + onCanaryDump(appStats); + } + }); - if (/**/(mCompositeMonitors.getDelta(BlueToothSnapshot.class) != null) - || (mCompositeMonitors.getDelta(WifiSnapshot.class) != null) - || (mCompositeMonitors.getDelta(LocationSnapshot.class) != null) - ) { - // Scanning: BL, WIFI, GPS - createSection("scanning", new Consumer() { - @Override - public void accept(Printer printer) { - // BlueTooth - mCompositeMonitors.getDelta(BlueToothSnapshot.class, new Consumer>() { - @Override - public void accept(Delta delta) { - onReportBlueTooth(delta); - onWritingSectionContent(delta, appStats, mPrinter); - } - }); - // Wifi - mCompositeMonitors.getDelta(WifiSnapshot.class, new Consumer>() { - @Override - public void accept(Delta delta) { - onReportWifi(delta); - onWritingSectionContent(delta, appStats, mPrinter); - } - }); - // Location - mCompositeMonitors.getDelta(LocationSnapshot.class, new Consumer>() { - @Override - public void accept(Delta delta) { - onReportLocation(delta); - onWritingSectionContent(delta, appStats, mPrinter); - } - }); - } - }); - } + Dumper dumper = createDumper(); + Printer printer = createPrinter(); + printer.writeTitle(); + dumper.dump(monitors, printer); + printer.writeEnding(); + printer.dump(); - if (/**/(mCompositeMonitors.getFeature(AppStatMonitorFeature.class) != null) - || (mCompositeMonitors.getDelta(CpuStateSnapshot.class) != null) - || (mCompositeMonitors.getDelta(CpuFreqSnapshot.class) != null) - || (mCompositeMonitors.getDelta(BatteryTmpSnapshot.class) != null) - ) { - // Stats: Cpu Usage, Device Status - createSection("dev_stats", new Consumer() { - @Override - public void accept(Printer printer) { - mCompositeMonitors.getDelta(CpuStateSnapshot.class, new Consumer>() { - @Override - public void accept(Delta delta) { - onReportCpuStats(delta); - onWritingSectionContent(delta, appStats, mPrinter); - } - }); - mCompositeMonitors.getDelta(CpuFreqSnapshot.class, new Consumer>() { - @Override - public void accept(Delta delta) { - onReportCpuFreq(delta); - onWritingSectionContent(delta, appStats, mPrinter); - } - }); - mCompositeMonitors.getDelta(BatteryTmpSnapshot.class, new Consumer>() { - @Override - public void accept(Delta delta) { - onReportTemperature(delta); - onWritingSectionContent(delta, appStats, mPrinter); - } - }); - } - }); + checkBadThreads(monitors); + onCanaryReport(monitors); + + synchronized (tasks) { + tasks.clear(); } + } - onWritingSections(); + protected void onPreDumping(CompositeMonitors monitors) { + checkBadThreads(monitors); } @Deprecated @CallSuper - protected void onWritingSections() { + protected void onCanaryDump(AppStats appStats) { + // mPrinter.clear(); + // + // // title + // mPrinter.writeTitle(); + // + // // sections + // onWritingJiffiesSection(appStats); + // onWritingSections(appStats); + // onWritingAppStatSection(appStats); + // + // // end + // mPrinter.writeEnding(); + // mPrinter.dump(); + // synchronized (tasks) { + // tasks.clear(); + // } } + // @Deprecated + // @CallSuper + // protected void onWritingJiffiesSection(final AppStats appStats) { + // mCompositeMonitors.getDelta(JiffiesSnapshot.class, new Consumer>() { + // @Override + // public void accept(final Delta delta) { + // final long minute = appStats.getMinute(); + // for (final ThreadJiffiesEntry threadJiffies : delta.dlt.threadEntries.getList()) { + // if (!threadJiffies.stat.toUpperCase().contains("R")) { + // continue; + // } + // mCompositeMonitors.getFeature(JiffiesMonitorFeature.class, new Consumer() { + // @Override + // public void accept(JiffiesMonitorFeature feature) { + // // Watching thread state when thread is: + // // 1. still running (status 'R') + // // 2. runing time > 10min + // // 3. avgJiffies > THRESHOLD + // long avgJiffies = threadJiffies.get() / minute; + // if (appStats.isForeground()) { + // if (minute > 10 && avgJiffies > getMonitor().getConfig().fgThreadWatchingLimit) { + // MatrixLog.i(TAG, "threadWatchDog fg set, name = " + delta.dlt.name + // + ", pid = " + delta.dlt.pid + // + ", tid = " + threadJiffies.tid); + // feature.watchBackThreadSate(true, delta.dlt.pid, threadJiffies.tid); + // } + // } else { + // if (minute > 10 && avgJiffies > getMonitor().getConfig().bgThreadWatchingLimit) { + // MatrixLog.i(TAG, "threadWatchDog bg set, name = " + delta.dlt.name + // + ", pid = " + delta.dlt.pid + // + ", tid = " + threadJiffies.tid); + // feature.watchBackThreadSate(false, delta.dlt.pid, threadJiffies.tid); + // } + // } + // } + // }); + // } + // onReportJiffies(delta); + // onWritingSectionContent(delta, appStats, mPrinter); + // } + // }); + // } + + // @Deprecated + // @CallSuper + // protected void onWritingAppStatSection(final AppStats appStats) { + // createSection("app_stats", new Consumer() { + // @Override + // public void accept(final Printer printer) { + // printer.createSubSection("stat_time"); + // printer.writeLine("time", appStats.getMinute() + "(min)"); + // printer.writeLine("fg", String.valueOf(appStats.appFgRatio)); + // printer.writeLine("bg", String.valueOf(appStats.appBgRatio)); + // printer.writeLine("fgSrv", String.valueOf(appStats.appFgSrvRatio)); + // printer.writeLine("devCharging", String.valueOf(appStats.devChargingRatio)); + // printer.writeLine("devScreenOff", String.valueOf(appStats.devSceneOffRatio)); + // if (!TextUtils.isEmpty(appStats.sceneTop1)) { + // printer.writeLine("sceneTop1", appStats.sceneTop1 + "/" + appStats.sceneTop1Ratio); + // } + // if (!TextUtils.isEmpty(appStats.sceneTop2)) { + // printer.writeLine("sceneTop2", appStats.sceneTop2 + "/" + appStats.sceneTop2Ratio); + // } + // mCompositeMonitors.getFeature(AppStatMonitorFeature.class, new Consumer() { + // @Override + // public void accept(AppStatMonitorFeature feature) { + // AppStatMonitorFeature.AppStatSnapshot currSnapshot = feature.currentAppStatSnapshot(); + // printer.createSubSection("run_time"); + // printer.writeLine("time", currSnapshot.uptime.get() / ONE_MIN + "(min)"); + // printer.writeLine("fg", String.valueOf(currSnapshot.fgRatio.get())); + // printer.writeLine("bg", String.valueOf(currSnapshot.bgRatio.get())); + // printer.writeLine("fgSrv", String.valueOf(currSnapshot.fgSrvRatio.get())); + // } + // }); + // } + // }); + // } + + @Deprecated @CallSuper - protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, AppStats appStats, final Printer printer) { - // - Dump Jiffies - if (sessionDelta.dlt instanceof JiffiesSnapshot) { - //noinspection unchecked - Delta delta = (Delta) sessionDelta; - // header - long minute = Math.max(1, delta.during / ONE_MIN); - long avgJiffies = delta.dlt.totalJiffies.get() / minute; - printer.append("| ").append("pid=").append(Process.myPid()) - .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()) - .tab().tab().append("avg(jiffies/min)=").append(avgJiffies) - .enter(); - - // jiffies sections - printer.createSection("jiffies(" + delta.dlt.threadEntries.getList().size() + ")"); - 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))) { - 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"); - } - } - } - printer.append("|\t\t......\n"); - if (avgJiffies > 1000L || !delta.isValid()) { - printer.append("| ").append(avgJiffies > 1000L ? " #overHeat" : "").append(!delta.isValid() ? " #invalid" : "").append("\n"); - } - return true; - } - - // - Dump Alarm - if (sessionDelta.dlt instanceof AlarmSnapshot) { - //noinspection unchecked - Delta delta = (Delta) sessionDelta; - printer.createSubSection("alarm"); - printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); - printer.writeLine("inc_alarm_count", String.valueOf(delta.dlt.totalCount.get())); - printer.writeLine("inc_trace_count", String.valueOf(delta.dlt.tracingCount.get())); - printer.writeLine("inc_dupli_group", String.valueOf(delta.dlt.duplicatedGroup.get())); - printer.writeLine("inc_dupli_count", String.valueOf(delta.dlt.duplicatedCount.get())); - return true; - } - - // - Dump WakeLock - if (sessionDelta.dlt instanceof WakeLockSnapshot) { - //noinspection unchecked - Delta delta = (Delta) sessionDelta; - printer.createSubSection("wake_lock"); - printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); - printer.writeLine("inc_lock_count", String.valueOf(delta.dlt.totalWakeLockCount)); - printer.writeLine("inc_time_total", String.valueOf(delta.dlt.totalWakeLockTime)); - - List> wakeLockRecordsList = delta.end.totalWakeLockRecords.getList(); - if (!wakeLockRecordsList.isEmpty()) { - printer.createSubSection("locking"); - for (BeanEntry item : wakeLockRecordsList) { - if (!item.get().isFinished()) { - printer.writeLine(item.get().toString()); - } - } - } - return true; - } - - // - Dump BlueTooth - if (sessionDelta.dlt instanceof BlueToothSnapshot) { - //noinspection unchecked - Delta delta = (Delta) sessionDelta; - printer.createSubSection("bluetooh"); - printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); - printer.writeLine("inc_regs_count", String.valueOf(delta.dlt.regsCount.get())); - printer.writeLine("inc_dics_count", String.valueOf(delta.dlt.discCount.get())); - printer.writeLine("inc_scan_count", String.valueOf(delta.dlt.scanCount.get())); - return true; - } - - // - Dump BlueTooth - if (sessionDelta.dlt instanceof WifiSnapshot) { - //noinspection unchecked - Delta delta = (Delta) sessionDelta; - printer.createSubSection("wifi"); - printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); - printer.writeLine("inc_scan_count", String.valueOf(delta.dlt.scanCount.get())); - printer.writeLine("inc_qury_count", String.valueOf(delta.dlt.queryCount.get())); - return true; - } - - // - Dump BlueTooth - if (sessionDelta.dlt instanceof LocationSnapshot) { - //noinspection unchecked - Delta delta = (Delta) sessionDelta; - printer.createSubSection("location"); - printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); - printer.writeLine("inc_scan_count", String.valueOf(delta.dlt.scanCount.get())); - return true; - } - - // - Dump CpuFreq - if (sessionDelta.dlt instanceof CpuFreqSnapshot) { - //noinspection unchecked - Delta delta = (Delta) sessionDelta; - printer.createSubSection("cpufreq"); - printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); - printer.writeLine("inc", Arrays.toString(delta.dlt.cpuFreqs.getList().toArray())); - printer.writeLine("cur", Arrays.toString(delta.end.cpuFreqs.getList().toArray())); - return true; - } - - // - Dump CpuStats - if (sessionDelta.dlt instanceof CpuStateSnapshot) { - //noinspection unchecked - final Delta delta = (Delta) sessionDelta; - // Cpu Usage - printer.createSubSection("cpu_load"); - printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); - final CpuStatFeature cpuStatFeature = mCompositeMonitors.getFeature(CpuStatFeature.class); - if (cpuStatFeature != null) { - mCompositeMonitors.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) + "%"); - } - }); - } - 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 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("cur_cpu_sip", String.format(Locale.US, "%.2f(mAh)", delta.end.configureCpuSip(powerProfile))); - // Cpu battery sip - Proc State - mCompositeMonitors.getDelta(JiffiesSnapshot.class, new Consumer>() { - @Override - public void accept(Delta jiffiesDelta) { - double procSipDelta = delta.dlt.configureProcSip(powerProfile, jiffiesDelta.dlt.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("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)); - } - } - }); - } - return true; - } + protected void onWritingSections(final AppStats appStats) { + } - // - Dump Battery Temperature - if (sessionDelta.dlt instanceof BatteryTmpSnapshot) { - //noinspection unchecked - Delta delta = (Delta) sessionDelta; - printer.createSubSection("batt_temp"); - printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); - printer.writeLine("inc", String.valueOf(delta.dlt.temp.get())); - printer.writeLine("cur", String.valueOf(delta.end.temp.get())); - return true; - } + // @Deprecated + // @CallSuper + // protected void onWritingSections() { + // } + @Deprecated + @CallSuper + protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, AppStats appStats, final Printer printer) { return false; } + @Deprecated protected void createSection(String sectionName, Consumer printerConsumer) { mPrinter.createSection(sectionName); printerConsumer.accept(mPrinter); } + protected void onCanaryReport(CompositeMonitors monitors) { + monitors.getDelta(AlarmSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onReportAlarm(delta); + } + }); + monitors.getDelta(BlueToothSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onReportBlueTooth(delta); + } + }); + monitors.getDelta(CpuFreqSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onReportCpuFreq(delta); + } + }); + monitors.getDelta(CpuStateSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onReportCpuStats(delta); + } + }); + monitors.getDelta(JiffiesSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onReportJiffies(delta); + } + }); + monitors.getDelta(BatteryTmpSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onReportTemperature(delta); + } + }); + monitors.getDelta(WakeLockSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onReportWakeLock(delta); + } + }); + monitors.getDelta(WifiSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onReportWifi(delta); + } + }); + monitors.getDelta(LocationSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onReportLocation(delta); + } + }); + } + + @Deprecated protected void onReportAlarm(@NonNull Delta delta) { } + @Deprecated protected void onReportBlueTooth(@NonNull Delta delta) { } + @Deprecated protected void onReportCpuFreq(@NonNull Delta delta) { } + @Deprecated protected void onReportCpuStats(@NonNull Delta delta) { } + @Deprecated protected void onReportJiffies(@NonNull Delta delta) { } + @Deprecated protected void onReportTemperature(@NonNull Delta delta) { } + @Deprecated protected void onReportWakeLock(@NonNull Delta delta) { } + @Deprecated protected void onReportWifi(@NonNull Delta delta) { } + @Deprecated protected void onReportLocation(@NonNull Delta delta) { } + + public static class Dumper { + public void dump(CompositeMonitors monitors, Printer printer) { + onWritingSections(monitors, printer); + onWritingAppStatSection(monitors, printer); + } + + protected void onWritingSections(final CompositeMonitors monitors, final Printer printer) { + if (monitors.getMonitor() == null || monitors.getAppStats() == null) { + return; + } + + // Thread Jiffies + monitors.getDelta(JiffiesSnapshot.class, new Consumer>() { + @Override + public void accept(final Delta delta) { + onWritingSectionContent(delta, monitors, printer); + } + }); + + + final AppStats appStats = monitors.getAppStats(); + if (/**/(monitors.getDelta(AlarmSnapshot.class) != null) + || (monitors.getDelta(WakeLockSnapshot.class) != null) + ) { + // Alarm, WakeLock + printer.createSection("awake"); + monitors.getDelta(AlarmSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onWritingSectionContent(delta, monitors, printer); + } + }); + monitors.getDelta(WakeLockSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onWritingSectionContent(delta, monitors, printer); + } + }); + } + + if (/**/(monitors.getDelta(BlueToothSnapshot.class) != null) + || (monitors.getDelta(WifiSnapshot.class) != null) + || (monitors.getDelta(LocationSnapshot.class) != null) + ) { + // Scanning: BL, WIFI, GPS + printer.createSection("scanning"); + // BlueTooth + monitors.getDelta(BlueToothSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onWritingSectionContent(delta, monitors, printer); + } + }); + // Wifi + monitors.getDelta(WifiSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onWritingSectionContent(delta, monitors, printer); + } + }); + // Location + monitors.getDelta(LocationSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onWritingSectionContent(delta, monitors, printer); + } + }); + } + + if (/**/(monitors.getFeature(AppStatMonitorFeature.class) != null) + || (monitors.getDelta(CpuStateSnapshot.class) != null) + || (monitors.getDelta(CpuFreqSnapshot.class) != null) + || (monitors.getDelta(BatteryTmpSnapshot.class) != null) + ) { + // Stats: Cpu Usage, Device Status + printer.createSection("dev_stats"); + monitors.getDelta(CpuStateSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onWritingSectionContent(delta, monitors, printer); + } + }); + monitors.getDelta(CpuFreqSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onWritingSectionContent(delta, monitors, printer); + } + }); + monitors.getDelta(BatteryTmpSnapshot.class, new Consumer>() { + @Override + public void accept(Delta delta) { + onWritingSectionContent(delta, monitors, printer); + } + }); + } + } + + protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, CompositeMonitors monitors, final Printer printer) { + if (monitors.getMonitor() == null || monitors.getAppStats() == null) { + return false; + } + final AppStats appStats = monitors.getAppStats(); + // - Dump Jiffies + if (sessionDelta.dlt instanceof JiffiesSnapshot) { + //noinspection unchecked + Delta delta = (Delta) sessionDelta; + // header + long minute = Math.max(1, delta.during / ONE_MIN); + long avgJiffies = delta.dlt.totalJiffies.get() / minute; + printer.append("| ").append("pid=").append(Process.myPid()) + .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()) + .tab().tab().append("avg(jiffies/min)=").append(avgJiffies) + .enter(); + + // jiffies sections + printer.createSection("jiffies(" + delta.dlt.threadEntries.getList().size() + ")"); + 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))) { + 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"); + // } + // } + } + printer.append("|\t\t......\n"); + if (avgJiffies > 1000L || !delta.isValid()) { + printer.append("| ").append(avgJiffies > 1000L ? " #overHeat" : "").append(!delta.isValid() ? " #invalid" : "").append("\n"); + } + return true; + } + + // - Dump Alarm + if (sessionDelta.dlt instanceof AlarmSnapshot) { + //noinspection unchecked + Delta delta = (Delta) sessionDelta; + printer.createSubSection("alarm"); + printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); + printer.writeLine("inc_alarm_count", String.valueOf(delta.dlt.totalCount.get())); + printer.writeLine("inc_trace_count", String.valueOf(delta.dlt.tracingCount.get())); + printer.writeLine("inc_dupli_group", String.valueOf(delta.dlt.duplicatedGroup.get())); + printer.writeLine("inc_dupli_count", String.valueOf(delta.dlt.duplicatedCount.get())); + return true; + } + + // - Dump WakeLock + if (sessionDelta.dlt instanceof WakeLockSnapshot) { + //noinspection unchecked + Delta delta = (Delta) sessionDelta; + printer.createSubSection("wake_lock"); + printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); + printer.writeLine("inc_lock_count", String.valueOf(delta.dlt.totalWakeLockCount)); + printer.writeLine("inc_time_total", String.valueOf(delta.dlt.totalWakeLockTime)); + + List> wakeLockRecordsList = delta.end.totalWakeLockRecords.getList(); + if (!wakeLockRecordsList.isEmpty()) { + printer.createSubSection("locking"); + for (BeanEntry item : wakeLockRecordsList) { + if (!item.get().isFinished()) { + printer.writeLine(item.get().toString()); + } + } + } + return true; + } + + // - Dump BlueTooth + if (sessionDelta.dlt instanceof BlueToothSnapshot) { + //noinspection unchecked + Delta delta = (Delta) sessionDelta; + printer.createSubSection("bluetooh"); + printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); + printer.writeLine("inc_regs_count", String.valueOf(delta.dlt.regsCount.get())); + printer.writeLine("inc_dics_count", String.valueOf(delta.dlt.discCount.get())); + printer.writeLine("inc_scan_count", String.valueOf(delta.dlt.scanCount.get())); + return true; + } + + // - Dump BlueTooth + if (sessionDelta.dlt instanceof WifiSnapshot) { + //noinspection unchecked + Delta delta = (Delta) sessionDelta; + printer.createSubSection("wifi"); + printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); + printer.writeLine("inc_scan_count", String.valueOf(delta.dlt.scanCount.get())); + printer.writeLine("inc_qury_count", String.valueOf(delta.dlt.queryCount.get())); + return true; + } + + // - Dump BlueTooth + if (sessionDelta.dlt instanceof LocationSnapshot) { + //noinspection unchecked + Delta delta = (Delta) sessionDelta; + printer.createSubSection("location"); + printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); + printer.writeLine("inc_scan_count", String.valueOf(delta.dlt.scanCount.get())); + return true; + } + + // - Dump CpuFreq + if (sessionDelta.dlt instanceof CpuFreqSnapshot) { + //noinspection unchecked + Delta delta = (Delta) sessionDelta; + printer.createSubSection("cpufreq"); + printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); + printer.writeLine("inc", Arrays.toString(delta.dlt.cpuFreqs.getList().toArray())); + printer.writeLine("cur", Arrays.toString(delta.end.cpuFreqs.getList().toArray())); + return true; + } + + // - Dump CpuStats + if (sessionDelta.dlt instanceof CpuStateSnapshot) { + //noinspection unchecked + final Delta delta = (Delta) sessionDelta; + // Cpu Usage + printer.createSubSection("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) + "%"); + } + }); + } + 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 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("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 procSipEnd = delta.end.configureProcSip(powerProfile, jiffiesDelta.end.totalJiffies.get()); + printer.writeLine("inc_prc_sip", String.format(Locale.US, "%.2f(mAh)", procSipDelta)); + 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)); + } + } + }); + } + return true; + } + + // - Dump Battery Temperature + if (sessionDelta.dlt instanceof BatteryTmpSnapshot) { + //noinspection unchecked + Delta delta = (Delta) sessionDelta; + printer.createSubSection("batt_temp"); + printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); + printer.writeLine("inc", String.valueOf(delta.dlt.temp.get())); + printer.writeLine("cur", String.valueOf(delta.end.temp.get())); + return true; + } + + return false; + } + + protected void onWritingAppStatSection(CompositeMonitors monitors, final Printer printer) { + if (monitors.getMonitor() == null || monitors.getAppStats() == null) { + return; + } + + AppStats appStats = monitors.getAppStats(); + printer.createSection("app_stats"); + printer.createSubSection("stat_time"); + printer.writeLine("time", appStats.getMinute() + "(min)"); + printer.writeLine("fg", String.valueOf(appStats.appFgRatio)); + printer.writeLine("bg", String.valueOf(appStats.appBgRatio)); + printer.writeLine("fgSrv", String.valueOf(appStats.appFgSrvRatio)); + printer.writeLine("devCharging", String.valueOf(appStats.devChargingRatio)); + printer.writeLine("devScreenOff", String.valueOf(appStats.devSceneOffRatio)); + if (!TextUtils.isEmpty(appStats.sceneTop1)) { + printer.writeLine("sceneTop1", appStats.sceneTop1 + "/" + appStats.sceneTop1Ratio); + } + if (!TextUtils.isEmpty(appStats.sceneTop2)) { + printer.writeLine("sceneTop2", appStats.sceneTop2 + "/" + appStats.sceneTop2Ratio); + } + monitors.getFeature(AppStatMonitorFeature.class, new Consumer() { + @Override + public void accept(AppStatMonitorFeature feature) { + AppStatMonitorFeature.AppStatSnapshot currSnapshot = feature.currentAppStatSnapshot(); + printer.createSubSection("run_time"); + printer.writeLine("time", currSnapshot.uptime.get() / ONE_MIN + "(min)"); + printer.writeLine("fg", String.valueOf(currSnapshot.fgRatio.get())); + printer.writeLine("bg", String.valueOf(currSnapshot.bgRatio.get())); + printer.writeLine("fgSrv", String.valueOf(currSnapshot.fgSrvRatio.get())); + } + }); + } + + } + /** * Log Printer */ 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 a1a9e9a95..475c8a48d 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,11 +1,16 @@ package com.tencent.matrix.batterycanary.monitor.feature; +import android.os.SystemClock; + +import com.tencent.matrix.batterycanary.monitor.AppStats; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; import com.tencent.matrix.batterycanary.utils.Consumer; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import androidx.annotation.CallSuper; @@ -16,12 +21,17 @@ * @since 2021/9/18 */ public class CompositeMonitors { + protected final List>> mMetrics = new ArrayList<>(); protected final Map>, Snapshot> mBgnSnapshots = new HashMap<>(); protected final Map>, Delta> mDeltas = new HashMap<>(); - protected final BatteryMonitorCore mMonitor; + @Nullable + protected BatteryMonitorCore mMonitor; + @Nullable + protected AppStats mAppStats; + private long mBgnMillis = SystemClock.uptimeMillis(); - public CompositeMonitors(BatteryMonitorCore core) { + public CompositeMonitors(@Nullable BatteryMonitorCore core) { mMonitor = core; } @@ -30,8 +40,16 @@ public void clear() { mDeltas.clear(); } + @Nullable + public BatteryMonitorCore getMonitor() { + return mMonitor; + } + @Nullable public T getFeature(Class clazz) { + if (mMonitor == null) { + return null; + } for (MonitorFeature plugin : mMonitor.getConfig().features) { if (clazz.isAssignableFrom(plugin.getClass())) { //noinspection unchecked @@ -61,18 +79,50 @@ public > void getDelta(Class snapshotClass, Consumer block) { + AppStats appStats = getAppStats(); + if (appStats != null) { + block.accept(appStats); + } + } + @CallSuper - public void configureAllSnapshot() { - statCurrSnapshot(AlarmMonitorFeature.AlarmSnapshot.class); - statCurrSnapshot(BlueToothMonitorFeature.BlueToothSnapshot.class); - statCurrSnapshot(DeviceStatMonitorFeature.CpuFreqSnapshot.class); - statCurrSnapshot(DeviceStatMonitorFeature.BatteryTmpSnapshot.class); - statCurrSnapshot(JiffiesMonitorFeature.JiffiesSnapshot.class); - statCurrSnapshot(LocationMonitorFeature.LocationSnapshot.class); - statCurrSnapshot(TrafficMonitorFeature.RadioStatSnapshot.class); - statCurrSnapshot(WakeLockMonitorFeature.WakeLockSnapshot.class); - statCurrSnapshot(WifiMonitorFeature.WifiSnapshot.class); - statCurrSnapshot(CpuStatFeature.CpuStateSnapshot.class); + public CompositeMonitors metricAll() { + metric(JiffiesMonitorFeature.JiffiesSnapshot.class); + metric(AlarmMonitorFeature.AlarmSnapshot.class); + metric(WakeLockMonitorFeature.WakeLockSnapshot.class); + metric(CpuStatFeature.CpuStateSnapshot.class); + + metric(AppStatMonitorFeature.AppStatSnapshot.class); + metric(DeviceStatMonitorFeature.CpuFreqSnapshot.class); + metric(DeviceStatMonitorFeature.BatteryTmpSnapshot.class); + + metric(TrafficMonitorFeature.RadioStatSnapshot.class); + metric(BlueToothMonitorFeature.BlueToothSnapshot.class); + metric(WifiMonitorFeature.WifiSnapshot.class); + metric(LocationMonitorFeature.LocationSnapshot.class); + return this; + } + + public CompositeMonitors metric(Class> snapshotClass) { + if (!mMetrics.contains(snapshotClass)) { + mMetrics.add(snapshotClass); + } + return this; + } + + public void configureSnapshots() { + mAppStats = null; + mBgnMillis = SystemClock.uptimeMillis(); + for (Class> item : mMetrics) { + statCurrSnapshot(item); + } } @SuppressWarnings({"unchecked", "rawtypes"}) @@ -87,13 +137,14 @@ public void configureDeltas() { } } } + mAppStats = AppStats.current(SystemClock.uptimeMillis() - mBgnMillis); } @CallSuper protected Snapshot statCurrSnapshot(Class> snapshotClass) { Snapshot snapshot = null; if (snapshotClass == AlarmMonitorFeature.AlarmSnapshot.class) { - AlarmMonitorFeature feature = mMonitor.getMonitorFeature(AlarmMonitorFeature.class); + AlarmMonitorFeature feature = getFeature(AlarmMonitorFeature.class); if (feature != null) { snapshot = feature.currentAlarms(); mBgnSnapshots.put(snapshotClass, snapshot); @@ -101,7 +152,7 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas return snapshot; } if (snapshotClass == BlueToothMonitorFeature.BlueToothSnapshot.class) { - BlueToothMonitorFeature feature = mMonitor.getMonitorFeature(BlueToothMonitorFeature.class); + BlueToothMonitorFeature feature = getFeature(BlueToothMonitorFeature.class); if (feature != null) { snapshot = feature.currentSnapshot(); mBgnSnapshots.put(snapshotClass, snapshot); @@ -109,7 +160,7 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas return snapshot; } if (snapshotClass == DeviceStatMonitorFeature.CpuFreqSnapshot.class) { - DeviceStatMonitorFeature feature = mMonitor.getMonitorFeature(DeviceStatMonitorFeature.class); + DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null) { snapshot = feature.currentCpuFreq(); mBgnSnapshots.put(snapshotClass, snapshot); @@ -117,15 +168,15 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas return snapshot; } if (snapshotClass == DeviceStatMonitorFeature.BatteryTmpSnapshot.class) { - DeviceStatMonitorFeature feature = mMonitor.getMonitorFeature(DeviceStatMonitorFeature.class); - if (feature != null) { + DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); + if (feature != null && mMonitor != null) { snapshot = feature.currentBatteryTemperature(mMonitor.getContext()); mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } if (snapshotClass == JiffiesMonitorFeature.JiffiesSnapshot.class) { - JiffiesMonitorFeature feature = mMonitor.getMonitorFeature(JiffiesMonitorFeature.class); + JiffiesMonitorFeature feature = getFeature(JiffiesMonitorFeature.class); if (feature != null) { snapshot = feature.currentJiffiesSnapshot(); mBgnSnapshots.put(snapshotClass, snapshot); @@ -133,7 +184,7 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas return snapshot; } if (snapshotClass == LocationMonitorFeature.LocationSnapshot.class) { - LocationMonitorFeature feature = mMonitor.getMonitorFeature(LocationMonitorFeature.class); + LocationMonitorFeature feature = getFeature(LocationMonitorFeature.class); if (feature != null) { snapshot = feature.currentSnapshot(); mBgnSnapshots.put(snapshotClass, snapshot); @@ -141,15 +192,15 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas return snapshot; } if (snapshotClass == TrafficMonitorFeature.RadioStatSnapshot.class) { - TrafficMonitorFeature feature = mMonitor.getMonitorFeature(TrafficMonitorFeature.class); - if (feature != null) { + TrafficMonitorFeature feature = getFeature(TrafficMonitorFeature.class); + if (feature != null && mMonitor != null) { snapshot = feature.currentRadioSnapshot(mMonitor.getContext()); mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } if (snapshotClass == WakeLockMonitorFeature.WakeLockSnapshot.class) { - WakeLockMonitorFeature feature = mMonitor.getMonitorFeature(WakeLockMonitorFeature.class); + WakeLockMonitorFeature feature = getFeature(WakeLockMonitorFeature.class); if (feature != null) { snapshot = feature.currentWakeLocks(); mBgnSnapshots.put(snapshotClass, snapshot); @@ -157,7 +208,7 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas return snapshot; } if (snapshotClass == WifiMonitorFeature.WifiSnapshot.class) { - WifiMonitorFeature feature = mMonitor.getMonitorFeature(WifiMonitorFeature.class); + WifiMonitorFeature feature = getFeature(WifiMonitorFeature.class); if (feature != null) { snapshot = feature.currentSnapshot(); mBgnSnapshots.put(snapshotClass, snapshot); @@ -165,13 +216,30 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas return snapshot; } if (snapshotClass == CpuStatFeature.CpuStateSnapshot.class) { - CpuStatFeature feature = mMonitor.getMonitorFeature(CpuStatFeature.class); + CpuStatFeature feature = getFeature(CpuStatFeature.class); if (feature != null && feature.isSupported()) { snapshot = feature.currentCpuStateSnapshot(); mBgnSnapshots.put(snapshotClass, snapshot); } return snapshot; } + if (snapshotClass == AppStatMonitorFeature.AppStatSnapshot.class) { + AppStatMonitorFeature feature = getFeature(AppStatMonitorFeature.class); + if (feature != null) { + snapshot = feature.currentAppStatSnapshot(); + mBgnSnapshots.put(snapshotClass, snapshot); + } + return snapshot; + } return null; } + + @Override + public String toString() { + return "CompositeMonitors{" + + "Metrics=" + mBgnSnapshots + + ", BgnSnapshots=" + mMetrics + + ", Deltas=" + mDeltas + + '}'; + } } From 19a40a2ec233dce74bb620ab3e9ecd65c5700459 Mon Sep 17 00:00:00 2001 From: Kaede Date: Thu, 28 Oct 2021 13:03:49 +0800 Subject: [PATCH 003/163] Revert apis modify --- .../monitor/feature/MonitorCompositeTest.java | 9 +++------ .../batterycanary/monitor/BatteryMonitorCallback.java | 2 +- .../batterycanary/monitor/feature/CompositeMonitors.java | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java index 25417e521..096465c9f 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java @@ -18,13 +18,10 @@ import android.app.Application; import android.content.Context; -import android.os.Handler; -import android.os.Looper; import com.tencent.matrix.Matrix; import com.tencent.matrix.batterycanary.BatteryEventDelegate; import com.tencent.matrix.batterycanary.BatteryMonitorPlugin; -import com.tencent.matrix.batterycanary.TestUtils; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; @@ -94,7 +91,7 @@ public void testMetric() { Assert.assertNull(compositeMonitor.mBgnSnapshots.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNull(compositeMonitor.mBgnSnapshots.get(CpuStatFeature.CpuStateSnapshot.class)); compositeMonitor.metric(JiffiesMonitorFeature.JiffiesSnapshot.class); - compositeMonitor.configureSnapshots(); + compositeMonitor.configureAllSnapshot(); Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNull(compositeMonitor.mBgnSnapshots.get(CpuStatFeature.CpuStateSnapshot.class)); Assert.assertNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); @@ -107,7 +104,7 @@ public void testMetric() { compositeMonitor .metric(JiffiesMonitorFeature.JiffiesSnapshot.class) .metric(CpuStatFeature.CpuStateSnapshot.class); - compositeMonitor.configureSnapshots(); + compositeMonitor.configureAllSnapshot(); Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(CpuStatFeature.CpuStateSnapshot.class)); Assert.assertNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); @@ -132,7 +129,7 @@ public void testMetricAll() { Assert.assertNull(compositeMonitor.mBgnSnapshots.get(item)); } - compositeMonitor.configureSnapshots(); + compositeMonitor.configureAllSnapshot(); for (Class> item : compositeMonitor.mMetrics) { Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(item)); 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 022844520..b1ff5802e 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 @@ -156,7 +156,7 @@ protected AppStats getAppStats() { public void onTraceBegin() { mTraceBgnMillis = SystemClock.uptimeMillis(); mCompositeMonitors.clear(); - mCompositeMonitors.configureSnapshots(); + mCompositeMonitors.configureAllSnapshot(); // TODO: Remove deprecated statements // Configure begin snapshots 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 475c8a48d..2a8f909d0 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 @@ -117,7 +117,7 @@ public CompositeMonitors metric(Class> snapshotClass) { return this; } - public void configureSnapshots() { + public void configureAllSnapshot() { mAppStats = null; mBgnMillis = SystemClock.uptimeMillis(); for (Class> item : mMetrics) { From e148d7e11e5c18e46460a0a8041f669f63b3779f Mon Sep 17 00:00:00 2001 From: yvesluo Date: Thu, 28 Oct 2021 20:35:58 +0800 Subject: [PATCH 004/163] ActivityLeakFixer: reset clickable and longClickable state after clearing views --- .../java/com/tencent/matrix/resource/ActivityLeakFixer.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/ActivityLeakFixer.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/ActivityLeakFixer.java index 9d82510ec..46b93ce8e 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 @@ -208,6 +208,9 @@ private static void recycleView(View view) { return; } + boolean isClickable = view.isClickable(); + boolean isLongClickable = view.isLongClickable(); + try { view.setOnClickListener(null); } catch (Throwable ignored) { @@ -274,6 +277,9 @@ public void onViewDetachedFromWindow(View v) { } }); } + + view.setClickable(isClickable); + view.setLongClickable(isLongClickable); } private static void recycleImageView(ImageView iv) { From 64ff0e8280f7f568864fd84a6580dfadc74dcd12 Mon Sep 17 00:00:00 2001 From: Kaede Date: Fri, 29 Oct 2021 20:37:33 +0800 Subject: [PATCH 005/163] Update battery with composite monitors --- .../batterycanary/monitor/feature/CompositeMonitors.java | 6 +++++- 1 file changed, 5 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 2a8f909d0..206dff254 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 @@ -79,6 +79,10 @@ public > void getDelta(Class snapshotClass, Consumer> snapshotClass, Delta> delta) { + mDeltas.put(snapshotClass, delta); + } + @Nullable public AppStats getAppStats() { return mAppStats; @@ -133,7 +137,7 @@ public void configureDeltas() { Class> snapshotClass = item.getKey(); Snapshot currSnapshot = statCurrSnapshot(snapshotClass); if (currSnapshot != null && currSnapshot.getClass() == lastSnapshot.getClass()) { - mDeltas.put(snapshotClass, currSnapshot.diff(lastSnapshot)); + putDelta(snapshotClass, currSnapshot.diff(lastSnapshot)); } } } From a354ed03ebda1d76bdfe439efcd9db4d81b5c852 Mon Sep 17 00:00:00 2001 From: Kaede Date: Mon, 1 Nov 2021 20:20:08 +0800 Subject: [PATCH 006/163] Add battery internal monitor --- .../monitor/MonitorCoreTest.java | 25 +++-- .../matrix/batterycanary/BatteryCanary.java | 19 +++- .../monitor/BatteryMonitorCallback.java | 6 ++ .../monitor/BatteryMonitorCore.java | 65 ++--------- .../feature/AbsTaskMonitorFeature.java | 2 +- .../monitor/feature/CompositeMonitors.java | 4 + .../feature/InternalMonitorFeature.java | 102 ++++++++++++++++++ 7 files changed, 154 insertions(+), 69 deletions(-) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/InternalMonitorFeature.java diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/MonitorCoreTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/MonitorCoreTest.java index 8b8aa4e12..2bb2534c5 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/MonitorCoreTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/MonitorCoreTest.java @@ -20,14 +20,13 @@ import android.content.Context; import android.os.Handler; import android.os.Looper; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; import com.tencent.matrix.Matrix; import com.tencent.matrix.batterycanary.BatteryEventDelegate; import com.tencent.matrix.batterycanary.monitor.feature.AbsTaskMonitorFeature.TaskJiffiesSnapshot; import com.tencent.matrix.batterycanary.monitor.feature.AlarmMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.DeviceStatMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.InternalMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.LooperTaskMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; @@ -42,6 +41,9 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + @RunWith(AndroidJUnit4.class) public class MonitorCoreTest { @@ -274,7 +276,7 @@ public void testBgLoopTask() throws InterruptedException { public void testConfigureMonitorConsuming() throws InterruptedException { final AtomicReference> ref = new AtomicReference<>(); BatteryMonitorConfig config = new BatteryMonitorConfig.Builder() - .enable(JiffiesMonitorFeature.class) + .enable(InternalMonitorFeature.class) .setCallback(new BatteryMonitorCallback.BatteryPrinter() { @Override public void onReportInternalJiffies(Delta delta) { @@ -288,21 +290,24 @@ public void onReportInternalJiffies(Delta delta) { core.getHandler().post(new Runnable() { @Override public void run() { - for (;;) { - new Handler(Looper.myLooper()); - } + core.getHandler().post(this); } }); - Thread.sleep(100L); - TaskJiffiesSnapshot bgn = core.configureMonitorConsuming(); + + InternalMonitorFeature feat = core.getMonitorFeature(InternalMonitorFeature.class); + Assert.assertNotNull(feat); + + while (feat.mWorkerTid == -1) {} + + TaskJiffiesSnapshot bgn = feat.configureMonitorConsuming(); Assert.assertNotNull(bgn); Assert.assertNull(ref.get()); Thread.sleep(500L); - TaskJiffiesSnapshot end = core.configureMonitorConsuming(); + TaskJiffiesSnapshot end = feat.configureMonitorConsuming(); Assert.assertNotNull(end); Assert.assertNotNull(ref.get()); - Assert.assertEquals(500L, ref.get().during, 10); + Assert.assertTrue(ref.get().during >= 500L); Assert.assertEquals(ref.get().during, end.diff(bgn).during); Assert.assertEquals(ref.get().dlt.jiffies, end.diff(bgn).dlt.jiffies); Assert.assertTrue(ref.get().dlt.jiffies.get() > 0); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryCanary.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryCanary.java index b36dff4c3..a52b1af77 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryCanary.java +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/BatteryCanary.java @@ -1,13 +1,14 @@ package com.tencent.matrix.batterycanary; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - import com.tencent.matrix.Matrix; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore.Callback; 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.utils.Consumer; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * Matrix Battery Canary Plugin Facades. @@ -28,6 +29,18 @@ public static T getMonitorFeature(Class clazz) { return null; } + public static void getMonitorFeature(Class clazz, Consumer block) { + if (Matrix.isInstalled()) { + BatteryMonitorPlugin plugin = Matrix.with().getPluginByClass(BatteryMonitorPlugin.class); + if (plugin != null) { + T feat = plugin.core().getMonitorFeature(clazz); + if (feat != null) { + block.accept(feat); + } + } + } + } + public static void currentJiffies(@NonNull final Callback callback) { if (Matrix.isInstalled()) { BatteryMonitorPlugin plugin = Matrix.with().getPluginByClass(BatteryMonitorPlugin.class); 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 b1ff5802e..f2180cd1e 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 @@ -19,6 +19,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.DeviceStatMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.DeviceStatMonitorFeature.BatteryTmpSnapshot; import com.tencent.matrix.batterycanary.monitor.feature.DeviceStatMonitorFeature.CpuFreqSnapshot; +import com.tencent.matrix.batterycanary.monitor.feature.InternalMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.JiffiesSnapshot; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.JiffiesSnapshot.ThreadJiffiesEntry; @@ -58,6 +59,7 @@ */ public interface BatteryMonitorCallback extends BatteryMonitorCore.JiffiesListener, + InternalMonitorFeature.InternalListener, LooperTaskMonitorFeature.LooperTaskListener, WakeLockMonitorFeature.WakeLockListener, AlarmMonitorFeature.AlarmListener, @@ -223,6 +225,10 @@ public void onTraceEnd(boolean isForeground) { @Override public void onReportInternalJiffies(Delta delta) { + CompositeMonitors monitors = new CompositeMonitors(mMonitor); + monitors.setAppStats(AppStats.current(delta.during)); + monitors.putDelta(InternalMonitorFeature.InternalSnapshot.class, delta); + onCanaryReport(monitors); } @Override 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 2f9f2d218..79593f229 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,13 +4,7 @@ import android.content.ComponentName; import android.content.Context; import android.os.Handler; -import android.os.Looper; import android.os.Message; -import android.os.Process; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; -import androidx.annotation.WorkerThread; import com.tencent.matrix.AppActiveMatrixDelegate; import com.tencent.matrix.Matrix; @@ -18,25 +12,29 @@ import com.tencent.matrix.batterycanary.monitor.feature.AbsTaskMonitorFeature.TaskJiffiesSnapshot; import com.tencent.matrix.batterycanary.monitor.feature.AlarmMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.AppStatMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.InternalMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.JiffiesMonitorFeature.JiffiesSnapshot.ThreadJiffiesEntry; import com.tencent.matrix.batterycanary.monitor.feature.LooperTaskMonitorFeature; 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.Entry.DigitEntry; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.ListEntry; import com.tencent.matrix.batterycanary.monitor.feature.NotificationMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.NotificationMonitorFeature.BadNotification; import com.tencent.matrix.batterycanary.monitor.feature.WakeLockMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.WakeLockMonitorFeature.WakeLockTrace.WakeLockRecord; import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; -import com.tencent.matrix.batterycanary.utils.ProcStatUtil; import com.tencent.matrix.util.MatrixHandlerThread; import com.tencent.matrix.util.MatrixLog; import java.util.List; import java.util.concurrent.Callable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.annotation.WorkerThread; + public class BatteryMonitorCore implements LooperTaskMonitorFeature.LooperTaskListener, WakeLockMonitorFeature.WakeLockListener, @@ -55,7 +53,6 @@ public interface Callback> { public interface JiffiesListener { void onTraceBegin(); void onTraceEnd(boolean isForeground); // TODO: configurable status support - void onReportInternalJiffies(Delta delta); // Watching myself } private class ForegroundLoopCheckTask implements Runnable { @@ -117,7 +114,6 @@ public String call() { private final long mMonitorDelayMillis; private final long mFgLooperMillis; private final long mBgLooperMillis; - private int mWorkerTid = -1; @SuppressLint("VisibleForTests") public BatteryMonitorCore(BatteryMonitorConfig config) { @@ -194,13 +190,6 @@ public void start() { } mTurnOn = true; } - mHandler.post(new Runnable() { - @Override - public void run() { - mWorkerTid = Process.myTid(); - } - }); - if (BatteryEventDelegate.isInit()) { BatteryEventDelegate.getInstance().attach(this).startListening(); } @@ -219,25 +208,13 @@ public void stop() { } } + /** + * Removed to {@link InternalMonitorFeature#configureMonitorConsuming()} + */ @WorkerThread @Nullable + @Deprecated public TaskJiffiesSnapshot configureMonitorConsuming() { - if (Looper.myLooper() == Looper.getMainLooper() || Looper.myLooper() == mHandler.getLooper()) { - throw new IllegalStateException("'#configureMonitorConsuming' should work within worker thread except matrix thread!"); - } - - if (mWorkerTid > 0) { - MatrixLog.i(TAG, "#configureMonitorConsuming, tid = " + mWorkerTid); - TaskJiffiesSnapshot snapshot = createSnapshot(mWorkerTid); - if (snapshot != null) { - if (mLastInternalSnapshot != null) { - Delta delta = snapshot.diff(mLastInternalSnapshot); - getConfig().callback.onReportInternalJiffies(delta); - } - mLastInternalSnapshot = snapshot; - return snapshot; - } - } return null; } @@ -394,26 +371,4 @@ public void onAppSateLeak(boolean isMyself, int appImportance, ComponentName com public void onNotify(BadNotification notification) { getConfig().callback.onNotify(notification); } - - @Nullable - protected TaskJiffiesSnapshot createSnapshot(int tid) { - TaskJiffiesSnapshot snapshot = new TaskJiffiesSnapshot(); - snapshot.tid = tid; - snapshot.appStat = BatteryCanaryUtil.getAppStat(getContext(), isForeground()); - snapshot.devStat = BatteryCanaryUtil.getDeviceStat(getContext()); - try { - Callable supplier = getConfig().onSceneSupplier; - snapshot.scene = supplier == null ? "" : supplier.call(); - } catch (Exception ignored) { - snapshot.scene = ""; - } - - ProcStatUtil.ProcStat stat = ProcStatUtil.of(Process.myPid(), tid); - if (stat == null) { - return null; - } - snapshot.jiffies = DigitEntry.of(stat.getJiffies()); - snapshot.name = stat.comm; - return snapshot; - } } 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 e5280e9ad..5536cada5 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 @@ -461,7 +461,7 @@ protected TaskJiffiesSnapshot createSnapshot(String name, int tid) { return snapshot; } - public static final class TaskJiffiesSnapshot extends Snapshot { + public static class TaskJiffiesSnapshot extends Snapshot { public int tid; public String name; public long timeMillis = System.currentTimeMillis(); 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 206dff254..ddbae28c9 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 @@ -96,6 +96,10 @@ public void getAppStats(Consumer block) { } } + public void setAppStats(@Nullable AppStats appStats) { + mAppStats = appStats; + } + @CallSuper public CompositeMonitors metricAll() { metric(JiffiesMonitorFeature.JiffiesSnapshot.class); diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/InternalMonitorFeature.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/InternalMonitorFeature.java new file mode 100644 index 000000000..12d022d1f --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/InternalMonitorFeature.java @@ -0,0 +1,102 @@ +package com.tencent.matrix.batterycanary.monitor.feature; + +import android.os.Looper; +import android.os.Process; + +import com.tencent.matrix.batterycanary.monitor.feature.AbsTaskMonitorFeature.TaskJiffiesSnapshot; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; +import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; +import com.tencent.matrix.batterycanary.utils.ProcStatUtil; +import com.tencent.matrix.util.MatrixLog; + +import java.util.concurrent.Callable; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.annotation.WorkerThread; + +/** + * Matrix Internal Thread Status Monitoring. + * + * @author Kaede + * @since 2020/11/1 + */ +@SuppressWarnings("NotNullFieldNotInitialized") +public final class InternalMonitorFeature extends AbsMonitorFeature { + private static final String TAG = "Matrix.battery.InternalMonitorFeature"; + + public interface InternalListener { + void onReportInternalJiffies(Delta delta); // Watching myself + } + + @VisibleForTesting public int mWorkerTid = -1; + @Nullable private TaskJiffiesSnapshot mLastInternalSnapshot; + + @Override + public void onTurnOn() { + super.onTurnOn(); + mCore.getHandler().post(new Runnable() { + @Override + public void run() { + mWorkerTid = Process.myTid(); + } + }); + } + + @Override + protected String getTag() { + return TAG; + } + + @Override + public int weight() { + return Integer.MIN_VALUE; + } + + @WorkerThread + @Nullable + public TaskJiffiesSnapshot configureMonitorConsuming() { + if (Looper.myLooper() == Looper.getMainLooper() || Looper.myLooper() == mCore.getHandler().getLooper()) { + throw new IllegalStateException("'#configureMonitorConsuming' should work within worker thread except matrix thread!"); + } + + if (mWorkerTid > 0) { + MatrixLog.i(TAG, "#configureMonitorConsuming, tid = " + mWorkerTid); + TaskJiffiesSnapshot snapshot = createSnapshot(mWorkerTid); + if (snapshot != null) { + if (mLastInternalSnapshot != null) { + Delta delta = snapshot.diff(mLastInternalSnapshot); + mCore.getConfig().callback.onReportInternalJiffies(delta); + } + mLastInternalSnapshot = snapshot; + return snapshot; + } + } + return null; + } + + @Nullable + protected InternalSnapshot createSnapshot(int tid) { + InternalSnapshot snapshot = new InternalSnapshot(); + snapshot.tid = tid; + snapshot.appStat = BatteryCanaryUtil.getAppStat(mCore.getContext(), mCore.isForeground()); + snapshot.devStat = BatteryCanaryUtil.getDeviceStat(mCore.getContext()); + try { + Callable supplier = mCore.getConfig().onSceneSupplier; + snapshot.scene = supplier == null ? "" : supplier.call(); + } catch (Exception ignored) { + snapshot.scene = ""; + } + + ProcStatUtil.ProcStat stat = ProcStatUtil.of(Process.myPid(), tid); + if (stat == null) { + return null; + } + snapshot.jiffies = Snapshot.Entry.DigitEntry.of(stat.getJiffies()); + snapshot.name = stat.comm; + return snapshot; + } + + public static class InternalSnapshot extends TaskJiffiesSnapshot { + } +} From 86b4e1d0f8cfdc273b971997d3c832b43d9149ec Mon Sep 17 00:00:00 2001 From: Kaede Date: Mon, 1 Nov 2021 21:02:11 +0800 Subject: [PATCH 007/163] Append commit --- .../monitor/feature/MonitorCompositeTest.java | 18 ++++++++++++++++++ .../monitor/feature/CompositeMonitors.java | 12 ++++++++++++ 2 files changed, 30 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java index 096465c9f..bb5b69b28 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java @@ -30,7 +30,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; +import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; @@ -43,6 +45,7 @@ public class MonitorCompositeTest { @Before public void setUp() { + System.setProperty("org.mockito.android.target", ApplicationProvider.getApplicationContext().getCacheDir().getPath()); mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); if (!Matrix.isInstalled()) { Matrix.init(new Matrix.Builder(((Application) mContext.getApplicationContext())).build()); @@ -142,4 +145,19 @@ public void testMetricAll() { Assert.assertNotNull(compositeMonitor.mDeltas.get(item)); } } + + @Test + public void testPutDelta() { + final BatteryMonitorCore monitor = mockMonitor(); + BatteryMonitorPlugin plugin = new BatteryMonitorPlugin(monitor.getConfig()); + Matrix.with().getPlugins().add(plugin); + monitor.enableForegroundLoopCheck(true); + monitor.start(); + + CompositeMonitors compositeMonitor = new CompositeMonitors(monitor); + compositeMonitor.putDelta(AbsTaskMonitorFeature.TaskJiffiesSnapshot.class, Mockito.mock(MonitorFeature.Snapshot.Delta.class)); + Assert.assertNotNull(compositeMonitor.getDelta(AbsTaskMonitorFeature.TaskJiffiesSnapshot.class)); + compositeMonitor.putDelta(InternalMonitorFeature.InternalSnapshot.class, Mockito.mock(MonitorFeature.Snapshot.Delta.class)); + Assert.assertNotNull(compositeMonitor.getDeltaRaw(InternalMonitorFeature.InternalSnapshot.class)); + } } 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 ddbae28c9..96102d855 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 @@ -79,6 +79,18 @@ public > void getDelta(Class snapshotClass, Consumer getDeltaRaw(Class> snapshotClass) { + return mDeltas.get(snapshotClass); + } + + public void getDeltaRaw(Class> snapshotClass, Consumer> block) { + Delta delta = getDeltaRaw(snapshotClass); + if (delta != null) { + block.accept(delta); + } + } + public void putDelta(Class> snapshotClass, Delta> delta) { mDeltas.put(snapshotClass, delta); } From 8480fc294628931b356707b3ab0e285ca6e1dc89 Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 3 Nov 2021 13:17:11 +0800 Subject: [PATCH 008/163] Update compositor with cpuload --- .../monitor/feature/MonitorCompositeTest.java | 22 +++++++++++++++ .../monitor/feature/CompositeMonitors.java | 27 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java index bb5b69b28..5626d6d3f 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java @@ -24,6 +24,7 @@ import com.tencent.matrix.batterycanary.BatteryMonitorPlugin; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; +import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import org.junit.After; import org.junit.Assert; @@ -160,4 +161,25 @@ public void testPutDelta() { compositeMonitor.putDelta(InternalMonitorFeature.InternalSnapshot.class, Mockito.mock(MonitorFeature.Snapshot.Delta.class)); Assert.assertNotNull(compositeMonitor.getDeltaRaw(InternalMonitorFeature.InternalSnapshot.class)); } + + @Test + public void testGetCpuLoad() { + final BatteryMonitorCore monitor = mockMonitor(); + BatteryMonitorPlugin plugin = new BatteryMonitorPlugin(monitor.getConfig()); + Matrix.with().getPlugins().add(plugin); + monitor.enableForegroundLoopCheck(true); + monitor.start(); + + CompositeMonitors compositeMonitor = new CompositeMonitors(monitor); + Assert.assertEquals(-1, compositeMonitor.getCpuLoad()); + compositeMonitor.metric(JiffiesMonitorFeature.JiffiesSnapshot.class); + compositeMonitor.configureAllSnapshot(); + compositeMonitor.configureDeltas(); + Assert.assertEquals(-1, compositeMonitor.getCpuLoad()); + + compositeMonitor.metric(CpuStatFeature.CpuStateSnapshot.class); + compositeMonitor.configureAllSnapshot(); + compositeMonitor.configureDeltas(); + Assert.assertTrue(compositeMonitor.getCpuLoad() >= 0 && compositeMonitor.getCpuLoad() <= BatteryCanaryUtil.getCpuCoreNum() * 100); + } } 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 96102d855..32c6fbbc0 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 @@ -6,7 +6,9 @@ import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot; import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Delta; +import com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.Consumer; +import com.tencent.matrix.util.MatrixLog; import java.util.ArrayList; import java.util.HashMap; @@ -21,6 +23,8 @@ * @since 2021/9/18 */ public class CompositeMonitors { + private static final String TAG = "Matrix.battery.CompositeMonitors"; + protected final List>> mMetrics = new ArrayList<>(); protected final Map>, Snapshot> mBgnSnapshots = new HashMap<>(); protected final Map>, Delta> mDeltas = new HashMap<>(); @@ -112,6 +116,29 @@ public void setAppStats(@Nullable AppStats appStats) { mAppStats = appStats; } + public int getCpuLoad() { + if (mAppStats == null) { + MatrixLog.w(TAG, "AppStats should not be null to get CpuLoad"); + return -1; + } + + Delta appJiffies = getDelta(JiffiesMonitorFeature.JiffiesSnapshot.class); + Delta cpuJiffies = getDelta(CpuStatFeature.CpuStateSnapshot.class); + if (appJiffies == null) { + MatrixLog.w(TAG, JiffiesMonitorFeature.JiffiesSnapshot.class + " should be metrics to get CpuLoad"); + return -1; + } + if (cpuJiffies == null) { + MatrixLog.w(TAG, CpuStatFeature.CpuStateSnapshot.class + "should be metrics to get CpuLoad"); + return -1; + } + + final long appJiffiesDelta = appJiffies.dlt.totalJiffies.get(); + final long cpuJiffiesDelta = cpuJiffies.dlt.totalCpuJiffies(); + final float cpuLoad = cpuJiffiesDelta > 0 ? (float) appJiffiesDelta / cpuJiffiesDelta : 0; + return (int) (cpuLoad * BatteryCanaryUtil.getCpuCoreNum() * 100); + } + @CallSuper public CompositeMonitors metricAll() { metric(JiffiesMonitorFeature.JiffiesSnapshot.class); From 06b3253a31875845f3a9494e08f10152edfee7a1 Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 3 Nov 2021 16:02:28 +0800 Subject: [PATCH 009/163] Add battery canary sampler --- .../monitor/feature/SamplerTest.java | 163 ++++++++++++++++++ .../monitor/feature/Sampler.java | 120 +++++++++++++ 2 files changed, 283 insertions(+) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java create mode 100644 matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/Sampler.java 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 new file mode 100644 index 000000000..464b3bce9 --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/SamplerTest.java @@ -0,0 +1,163 @@ +/* + * 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.monitor.feature; + +import android.app.Application; +import android.content.Context; + +import com.tencent.matrix.Matrix; +import com.tencent.matrix.batterycanary.BatteryEventDelegate; +import com.tencent.matrix.batterycanary.BatteryMonitorPlugin; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + + +@RunWith(AndroidJUnit4.class) +public class SamplerTest { + static final String TAG = "Matrix.test.SamplerTest"; + + Context mContext; + + @Before + public void setUp() { + System.setProperty("org.mockito.android.target", ApplicationProvider.getApplicationContext().getCacheDir().getPath()); + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + if (!Matrix.isInstalled()) { + Matrix.init(new Matrix.Builder(((Application) mContext.getApplicationContext())).build()); + } + if (!BatteryEventDelegate.isInit()) { + BatteryEventDelegate.init((Application) mContext.getApplicationContext()); + } + } + + @After + public void shutDown() { + } + + private BatteryMonitorCore mockMonitor() { + BatteryMonitorConfig config = new BatteryMonitorConfig.Builder() + .enable(JiffiesMonitorFeature.class) + .enable(LooperTaskMonitorFeature.class) + .enable(WakeLockMonitorFeature.class) + .enable(DeviceStatMonitorFeature.class) + .enable(AlarmMonitorFeature.class) + .enable(AppStatMonitorFeature.class) + .enable(BlueToothMonitorFeature.class) + .enable(WifiMonitorFeature.class) + .enable(LocationMonitorFeature.class) + .enable(TrafficMonitorFeature.class) + .enable(NotificationMonitorFeature.class) + .enable(CpuStatFeature.class) + .enableBuiltinForegroundNotify(false) + .enableForegroundMode(true) + .wakelockTimeout(1000) + .greyJiffiesTime(100) + .foregroundLoopCheckTime(1000) + .build(); + return new BatteryMonitorCore(config); + } + + @Test + public void testSampling() throws InterruptedException { + final BatteryMonitorCore monitor = mockMonitor(); + BatteryMonitorPlugin plugin = new BatteryMonitorPlugin(monitor.getConfig()); + Matrix.with().getPlugins().add(plugin); + monitor.enableForegroundLoopCheck(true); + monitor.start(); + + final int samplingCount = 10; + + final AtomicInteger counter = new AtomicInteger(0); + final Sampler sampler = new Sampler(monitor.getHandler(), new Callable() { + @Override + public Integer call() throws InterruptedException { + int count = counter.incrementAndGet(); + if (count <= samplingCount) { + return count; + } + synchronized (counter) { + counter.notifyAll(); + } + throw new InterruptedException("stop"); + } + }); + + sampler.setInterval(1L); + sampler.start(); + if (sampler.mCount < samplingCount) { + synchronized (counter) { + counter.wait(); + } + } + sampler.pause(); + Sampler.Result result = sampler.getResult(); + Assert.assertNotNull(result); + Assert.assertEquals(samplingCount, result.count); + Assert.assertEquals(1d, result.sampleFst, 0.1); + Assert.assertEquals(10d, result.sampleLst, 0.1); + Assert.assertEquals(10d, result.sampleMax, 0.1); + Assert.assertEquals(10d, result.sampleMax, 0.1); + Assert.assertEquals(1d, result.sampleMin, 0.1); + Assert.assertEquals(55d / samplingCount, result.sampleAvg, 0.1); + + final AtomicInteger counterDec = new AtomicInteger(0); + final Sampler samplerDec = new Sampler(monitor.getHandler(), new Callable() { + @Override + public Integer call() throws InterruptedException { + int count = counterDec.incrementAndGet(); + if (count <= samplingCount) { + return samplingCount + 1 - count; + } + synchronized (counterDec) { + counterDec.notifyAll(); + } + throw new InterruptedException("stop"); + } + }); + + samplerDec.setInterval(1L); + samplerDec.start(); + if (samplerDec.mCount < samplingCount) { + synchronized (counterDec) { + counterDec.wait(); + } + } + samplerDec.pause(); + result = samplerDec.getResult(); + Assert.assertNotNull(result); + Assert.assertEquals(samplingCount, result.count); + Assert.assertEquals(10d, result.sampleFst, 0.1); + Assert.assertEquals(1d, result.sampleLst, 0.1); + Assert.assertEquals(10d, result.sampleMax, 0.1); + Assert.assertEquals(10d, result.sampleMax, 0.1); + Assert.assertEquals(1d, result.sampleMin, 0.1); + Assert.assertEquals(55d / samplingCount, result.sampleAvg, 0.1); + } +} diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/Sampler.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/Sampler.java new file mode 100644 index 000000000..429ff6eda --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/Sampler.java @@ -0,0 +1,120 @@ +package com.tencent.matrix.batterycanary.monitor.feature; + +import android.os.Handler; +import android.os.SystemClock; + +import com.tencent.matrix.util.MatrixLog; + +import java.util.concurrent.Callable; + +import androidx.annotation.Nullable; + +import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_MIN; + +/** + * @author Kaede + * @since 2021/11/3 + */ +class Sampler { + private static final String TAG = "Matrix.battery.Sampler"; + + final Handler mHandler; + final Callable mSamplingBlock; + + private final Runnable mSamplingTask = new Runnable() { + @Override + public void run() { + try { + Number currSample = mSamplingBlock.call(); + mSampleLst = currSample.doubleValue(); + mCount++; + mSampleAvg = (mSampleAvg * (mCount - 1) + mSampleLst) / mCount; + if (mSampleFst == Double.MIN_VALUE) { + mSampleFst = mSampleLst; + mSampleMax = mSampleLst; + mSampleMin = mSampleLst; + } else { + if (mSampleLst > mSampleMax) { + mSampleMax = mSampleLst; + } + if (mSampleLst < mSampleMin) { + mSampleMin = mSampleLst; + } + } + } catch (Exception e) { + MatrixLog.printErrStackTrace(TAG, e, "onSamplingFailed: " + e); + } finally { + if (!mPaused) { + mHandler.postDelayed(this, mInterval); + } + } + } + }; + + boolean mPaused = true; + long mInterval = ONE_MIN; + int mCount = 0; + long mBgnMillis = 0; + long mEndMillis = 0; + double mSampleFst = Double.MIN_VALUE; + double mSampleLst = Double.MIN_VALUE; + double mSampleMax = Double.MIN_VALUE; + double mSampleMin = Double.MIN_VALUE; + double mSampleAvg = Double.MIN_VALUE; + + Sampler(Handler handler, Callable onSampling) { + mHandler = handler; + mSamplingBlock = onSampling; + } + + public void setInterval(long interval) { + if (interval > 0) { + mInterval = interval; + } + } + + public void start() { + mPaused = false; + mBgnMillis = SystemClock.uptimeMillis(); + mHandler.postDelayed(mSamplingTask, mInterval); + } + + public void pause() { + mPaused = true; + mEndMillis = SystemClock.uptimeMillis(); + mHandler.removeCallbacks(mSamplingTask); + } + + @Nullable + public Result getResult() { + if (mCount <= 0) { + MatrixLog.w(TAG, "Sampling count is invalid: " + mCount); + return null; + } + if (mBgnMillis <= 0 || mEndMillis <= 0 || mBgnMillis > mEndMillis) { + MatrixLog.w(TAG, "Sampling bgn/end millis is invalid: " + mBgnMillis + " - " + mEndMillis); + return null; + } + Result result = new Result(); + result.interval = mInterval; + result.count = mCount; + result.duringMillis = mEndMillis - mBgnMillis; + result.sampleFst = mSampleFst; + result.sampleLst = mSampleLst; + result.sampleMax = mSampleMax; + result.sampleMin = mSampleMin; + result.sampleAvg = mSampleAvg; + return result; + } + + public static final class Result { + public long interval; + public int count; + public long duringMillis; + public double sampleFst; + public double sampleLst; + public double sampleMax; + public double sampleMin; + public double sampleAvg; + } +} From 9cf920eed76cf357e4d0e75ec8516f5c1a581628 Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 3 Nov 2021 17:22:06 +0800 Subject: [PATCH 010/163] Update compositor with samlper --- ...CompositeTest.java => CompositorTest.java} | 53 ++++-- .../monitor/BatteryMonitorCallback.java | 4 +- .../monitor/feature/CompositeMonitors.java | 166 ++++++++++++++---- 3 files changed, 179 insertions(+), 44 deletions(-) rename matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/{MonitorCompositeTest.java => CompositorTest.java} (77%) diff --git a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java similarity index 77% rename from matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java rename to matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java index 5626d6d3f..e9199b6a1 100644 --- a/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/MonitorCompositeTest.java +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/monitor/feature/CompositorTest.java @@ -39,8 +39,8 @@ @RunWith(AndroidJUnit4.class) -public class MonitorCompositeTest { - static final String TAG = "Matrix.test.MonitorFeatureOverAllTest"; +public class CompositorTest { + static final String TAG = "Matrix.test.CompositorTest"; Context mContext; @@ -95,12 +95,12 @@ public void testMetric() { Assert.assertNull(compositeMonitor.mBgnSnapshots.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNull(compositeMonitor.mBgnSnapshots.get(CpuStatFeature.CpuStateSnapshot.class)); compositeMonitor.metric(JiffiesMonitorFeature.JiffiesSnapshot.class); - compositeMonitor.configureAllSnapshot(); + compositeMonitor.start(); Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNull(compositeMonitor.mBgnSnapshots.get(CpuStatFeature.CpuStateSnapshot.class)); Assert.assertNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNull(compositeMonitor.mDeltas.get(CpuStatFeature.CpuStateSnapshot.class)); - compositeMonitor.configureDeltas(); + compositeMonitor.finish(); Assert.assertNotNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNull(compositeMonitor.mDeltas.get(CpuStatFeature.CpuStateSnapshot.class)); @@ -108,12 +108,12 @@ public void testMetric() { compositeMonitor .metric(JiffiesMonitorFeature.JiffiesSnapshot.class) .metric(CpuStatFeature.CpuStateSnapshot.class); - compositeMonitor.configureAllSnapshot(); + compositeMonitor.start(); Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(CpuStatFeature.CpuStateSnapshot.class)); Assert.assertNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNull(compositeMonitor.mDeltas.get(CpuStatFeature.CpuStateSnapshot.class)); - compositeMonitor.configureDeltas(); + compositeMonitor.finish(); Assert.assertNotNull(compositeMonitor.mDeltas.get(JiffiesMonitorFeature.JiffiesSnapshot.class)); Assert.assertNotNull(compositeMonitor.mDeltas.get(CpuStatFeature.CpuStateSnapshot.class)); } @@ -133,14 +133,14 @@ public void testMetricAll() { Assert.assertNull(compositeMonitor.mBgnSnapshots.get(item)); } - compositeMonitor.configureAllSnapshot(); + compositeMonitor.start(); for (Class> item : compositeMonitor.mMetrics) { Assert.assertNotNull(compositeMonitor.mBgnSnapshots.get(item)); Assert.assertNull(compositeMonitor.mDeltas.get(item)); } - compositeMonitor.configureDeltas(); + compositeMonitor.finish(); for (Class> item : compositeMonitor.mMetrics) { Assert.assertNotNull(compositeMonitor.mDeltas.get(item)); @@ -173,13 +173,42 @@ public void testGetCpuLoad() { CompositeMonitors compositeMonitor = new CompositeMonitors(monitor); Assert.assertEquals(-1, compositeMonitor.getCpuLoad()); compositeMonitor.metric(JiffiesMonitorFeature.JiffiesSnapshot.class); - compositeMonitor.configureAllSnapshot(); - compositeMonitor.configureDeltas(); + compositeMonitor.start(); + compositeMonitor.finish(); Assert.assertEquals(-1, compositeMonitor.getCpuLoad()); compositeMonitor.metric(CpuStatFeature.CpuStateSnapshot.class); - compositeMonitor.configureAllSnapshot(); - compositeMonitor.configureDeltas(); + compositeMonitor.start(); + compositeMonitor.finish(); Assert.assertTrue(compositeMonitor.getCpuLoad() >= 0 && compositeMonitor.getCpuLoad() <= BatteryCanaryUtil.getCpuCoreNum() * 100); } + + @Test + public void testSampling() throws InterruptedException { + final BatteryMonitorCore monitor = mockMonitor(); + BatteryMonitorPlugin plugin = new BatteryMonitorPlugin(monitor.getConfig()); + Matrix.with().getPlugins().add(plugin); + monitor.enableForegroundLoopCheck(true); + monitor.start(); + + CompositeMonitors compositeMonitor = new CompositeMonitors(monitor); + Assert.assertNull(compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.BatteryTmpSnapshot.class)); + Assert.assertNull(compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class)); + compositeMonitor.sample(DeviceStatMonitorFeature.BatteryTmpSnapshot.class, 1L); + compositeMonitor.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 10L); + + compositeMonitor.start(); + Thread.sleep(100L); + compositeMonitor.finish(); + + Assert.assertNotNull(compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.BatteryTmpSnapshot.class)); + Assert.assertEquals(1L, compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.BatteryTmpSnapshot.class).interval); + Assert.assertTrue(compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.BatteryTmpSnapshot.class).duringMillis >= 100L); + + Assert.assertNotNull(compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class)); + Assert.assertEquals(10L, compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class).interval); + Assert.assertTrue(compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class).duringMillis >= 100L); + + Assert.assertTrue(compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.BatteryTmpSnapshot.class).count > compositeMonitor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class).count); + } } 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 f2180cd1e..635acb218 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 @@ -158,7 +158,7 @@ protected AppStats getAppStats() { public void onTraceBegin() { mTraceBgnMillis = SystemClock.uptimeMillis(); mCompositeMonitors.clear(); - mCompositeMonitors.configureAllSnapshot(); + mCompositeMonitors.start(); // TODO: Remove deprecated statements // Configure begin snapshots @@ -219,7 +219,7 @@ public void onTraceEnd(boolean isForeground) { MatrixLog.w(TAG, "skip invalid battery tracing, bgn = " + mTraceBgnMillis + ", during = " + duringMillis); return; } - mCompositeMonitors.configureDeltas(); + mCompositeMonitors.finish(); onCanaryDump(mCompositeMonitors); } 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 32c6fbbc0..9a87f6028 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 @@ -6,14 +6,18 @@ import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; 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.utils.BatteryCanaryUtil; import com.tencent.matrix.batterycanary.utils.Consumer; import com.tencent.matrix.util.MatrixLog; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; import androidx.annotation.CallSuper; import androidx.annotation.Nullable; @@ -25,10 +29,16 @@ public class CompositeMonitors { private static final String TAG = "Matrix.battery.CompositeMonitors"; + // Differing protected final List>> mMetrics = new ArrayList<>(); protected final Map>, Snapshot> mBgnSnapshots = new HashMap<>(); protected final Map>, Delta> mDeltas = new HashMap<>(); + // Sampling + protected final Map>, Long> mSampleRegs = new HashMap<>(); + protected final Map>, Sampler> mSamplers = new HashMap<>(); + protected final Map>, Sampler.Result> mSampleResults = new HashMap<>(); + @Nullable protected BatteryMonitorCore mMonitor; @Nullable @@ -42,6 +52,8 @@ public CompositeMonitors(@Nullable BatteryMonitorCore core) { public void clear() { mBgnSnapshots.clear(); mDeltas.clear(); + mSamplers.clear(); + mSampleResults.clear(); } @Nullable @@ -70,35 +82,6 @@ public void getFeature(Class clazz, Consumer bl } } - @Nullable - public > Delta getDelta(Class snapshotClass) { - //noinspection unchecked - return (Delta) mDeltas.get(snapshotClass); - } - - public > void getDelta(Class snapshotClass, Consumer> block) { - Delta delta = getDelta(snapshotClass); - if (delta != null) { - block.accept(delta); - } - } - - @Nullable - public Delta getDeltaRaw(Class> snapshotClass) { - return mDeltas.get(snapshotClass); - } - - public void getDeltaRaw(Class> snapshotClass, Consumer> block) { - Delta delta = getDeltaRaw(snapshotClass); - if (delta != null) { - block.accept(delta); - } - } - - public void putDelta(Class> snapshotClass, Delta> delta) { - mDeltas.put(snapshotClass, delta); - } - @Nullable public AppStats getAppStats() { return mAppStats; @@ -139,6 +122,39 @@ public int getCpuLoad() { return (int) (cpuLoad * BatteryCanaryUtil.getCpuCoreNum() * 100); } + @Nullable + public > Delta getDelta(Class snapshotClass) { + //noinspection unchecked + return (Delta) mDeltas.get(snapshotClass); + } + + public > void getDelta(Class snapshotClass, Consumer> block) { + Delta delta = getDelta(snapshotClass); + if (delta != null) { + block.accept(delta); + } + } + + @Nullable + public Delta getDeltaRaw(Class> snapshotClass) { + return mDeltas.get(snapshotClass); + } + + public void getDeltaRaw(Class> snapshotClass, Consumer> block) { + Delta delta = getDeltaRaw(snapshotClass); + if (delta != null) { + block.accept(delta); + } + } + + public void putDelta(Class> snapshotClass, Delta> delta) { + mDeltas.put(snapshotClass, delta); + } + + public Sampler.Result getSamplingResult(Class> snapshotClass) { + return mSampleResults.get(snapshotClass); + } + @CallSuper public CompositeMonitors metricAll() { metric(JiffiesMonitorFeature.JiffiesSnapshot.class); @@ -164,16 +180,45 @@ public CompositeMonitors metric(Class> snapshotClass) { return this; } + public CompositeMonitors sample(Class> snapshotClass) { + return sample(snapshotClass, BatteryCanaryUtil.ONE_MIN); + } + + public CompositeMonitors sample(Class> snapshotClass, long interval) { + mSampleRegs.put(snapshotClass, interval); + return this; + } + + @Deprecated public void configureAllSnapshot() { + start(); + } + @Deprecated + public void configureDeltas() { + finish(); + } + + public void start() { mAppStats = null; mBgnMillis = SystemClock.uptimeMillis(); + configureBgnSnapshots(); + configureSamplers(); + } + + public void finish() { + configureEndDeltas(); + configureSampleResults(); + mAppStats = AppStats.current(SystemClock.uptimeMillis() - mBgnMillis); + } + + protected void configureBgnSnapshots() { for (Class> item : mMetrics) { statCurrSnapshot(item); } } @SuppressWarnings({"unchecked", "rawtypes"}) - public void configureDeltas() { + protected void configureEndDeltas() { for (Map.Entry>, Snapshot> item : mBgnSnapshots.entrySet()) { Snapshot lastSnapshot = item.getValue(); if (lastSnapshot != null) { @@ -281,6 +326,67 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas return null; } + protected void configureSamplers() { + for (Map.Entry>, Long> item : mSampleRegs.entrySet()) { + Sampler sampler = statSampler(item.getKey()); + if (sampler != null) { + sampler.setInterval(item.getValue()); + sampler.start(); + } + } + } + + protected void configureSampleResults() { + for (Map.Entry>, Sampler> item : mSamplers.entrySet()) { + item.getValue().pause(); + Sampler.Result result = item.getValue().getResult(); + if (result != null) { + mSampleResults.put(item.getKey(), result); + } + } + } + + @CallSuper + protected Sampler statSampler(Class> snapshotClass) { + Sampler sampler = null; + if (snapshotClass == DeviceStatMonitorFeature.CpuFreqSnapshot.class) { + final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); + if (feature != null && mMonitor != null) { + sampler = new Sampler(mMonitor.getHandler(), new Callable() { + @Override + public Number call() { + DeviceStatMonitorFeature.CpuFreqSnapshot snapshot = feature.currentCpuFreq(); + List> list = snapshot.cpuFreqs.getList(); + 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(0).get(); + } + }); + mSamplers.put(snapshotClass, sampler); + } + return sampler; + } + if (snapshotClass == DeviceStatMonitorFeature.BatteryTmpSnapshot.class) { + final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); + if (feature != null && mMonitor != null) { + sampler = new Sampler(mMonitor.getHandler(), new Callable() { + @Override + public Number call() { + DeviceStatMonitorFeature.BatteryTmpSnapshot snapshot = feature.currentBatteryTemperature(mMonitor.getContext()); + return snapshot.temp.get(); + } + }); + mSamplers.put(snapshotClass, sampler); + } + return sampler; + } + return null; + } + @Override public String toString() { return "CompositeMonitors{" + From 9eaaa41b1f86269b2a4afe49bbafd20cb6e6b80f Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 3 Nov 2021 17:27:36 +0800 Subject: [PATCH 011/163] Update battery sampler structure --- .../monitor/feature/SamplerTest.java | 6 +- .../monitor/feature/CompositeMonitors.java | 20 +-- .../monitor/feature/MonitorFeature.java | 116 ++++++++++++++++- .../monitor/feature/Sampler.java | 120 ------------------ 4 files changed, 124 insertions(+), 138 deletions(-) delete mode 100644 matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/Sampler.java 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 464b3bce9..dd6ffd77d 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 Sampler sampler = new Sampler(monitor.getHandler(), new Callable() { + final MonitorFeature.Snapshot.Sampler sampler = new MonitorFeature.Snapshot.Sampler(monitor.getHandler(), new Callable() { @Override public Integer call() throws InterruptedException { int count = counter.incrementAndGet(); @@ -117,7 +117,7 @@ public Integer call() throws InterruptedException { } } sampler.pause(); - Sampler.Result result = sampler.getResult(); + MonitorFeature.Snapshot.Sampler.Result result = sampler.getResult(); Assert.assertNotNull(result); Assert.assertEquals(samplingCount, result.count); Assert.assertEquals(1d, result.sampleFst, 0.1); @@ -128,7 +128,7 @@ public Integer call() throws InterruptedException { Assert.assertEquals(55d / samplingCount, result.sampleAvg, 0.1); final AtomicInteger counterDec = new AtomicInteger(0); - final Sampler samplerDec = new Sampler(monitor.getHandler(), new Callable() { + final MonitorFeature.Snapshot.Sampler samplerDec = new MonitorFeature.Snapshot.Sampler(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 9a87f6028..e58b88f97 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 @@ -36,8 +36,8 @@ public class CompositeMonitors { // Sampling protected final Map>, Long> mSampleRegs = new HashMap<>(); - protected final Map>, Sampler> mSamplers = new HashMap<>(); - protected final Map>, Sampler.Result> mSampleResults = new HashMap<>(); + protected final Map>, Snapshot.Sampler> mSamplers = new HashMap<>(); + protected final Map>, Snapshot.Sampler.Result> mSampleResults = new HashMap<>(); @Nullable protected BatteryMonitorCore mMonitor; @@ -151,7 +151,7 @@ public void putDelta(Class> snapshotClass, Delta> snapshotClass) { + public Snapshot.Sampler.Result getSamplingResult(Class> snapshotClass) { return mSampleResults.get(snapshotClass); } @@ -328,7 +328,7 @@ protected Snapshot statCurrSnapshot(Class> snapshotClas protected void configureSamplers() { for (Map.Entry>, Long> item : mSampleRegs.entrySet()) { - Sampler sampler = statSampler(item.getKey()); + Snapshot.Sampler sampler = statSampler(item.getKey()); if (sampler != null) { sampler.setInterval(item.getValue()); sampler.start(); @@ -337,9 +337,9 @@ protected void configureSamplers() { } protected void configureSampleResults() { - for (Map.Entry>, Sampler> item : mSamplers.entrySet()) { + for (Map.Entry>, Snapshot.Sampler> item : mSamplers.entrySet()) { item.getValue().pause(); - Sampler.Result result = item.getValue().getResult(); + Snapshot.Sampler.Result result = item.getValue().getResult(); if (result != null) { mSampleResults.put(item.getKey(), result); } @@ -347,12 +347,12 @@ protected void configureSampleResults() { } @CallSuper - protected Sampler statSampler(Class> snapshotClass) { - Sampler sampler = null; + protected Snapshot.Sampler statSampler(Class> snapshotClass) { + Snapshot.Sampler sampler = null; if (snapshotClass == DeviceStatMonitorFeature.CpuFreqSnapshot.class) { final DeviceStatMonitorFeature feature = getFeature(DeviceStatMonitorFeature.class); if (feature != null && mMonitor != null) { - sampler = new Sampler(mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler(mMonitor.getHandler(), new Callable() { @Override public Number call() { DeviceStatMonitorFeature.CpuFreqSnapshot snapshot = feature.currentCpuFreq(); @@ -373,7 +373,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 Sampler(mMonitor.getHandler(), new Callable() { + sampler = new Snapshot.Sampler(mMonitor.getHandler(), new Callable() { @Override public Number call() { DeviceStatMonitorFeature.BatteryTmpSnapshot snapshot = feature.currentBatteryTemperature(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 8d309d6a1..e977c4a48 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 @@ -1,29 +1,31 @@ package com.tencent.matrix.batterycanary.monitor.feature; +import android.os.Handler; import android.os.SystemClock; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; +import com.tencent.matrix.util.MatrixLog; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.concurrent.Callable; + +import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_MIN; public interface MonitorFeature { void configure(BatteryMonitorCore monitor); - void onTurnOn(); - void onTurnOff(); - void onForeground(boolean isForeground); - void onBackgroundCheck(long duringMillis); - int weight(); + @SuppressWarnings("rawtypes") abstract class Snapshot { public final long time; @@ -413,5 +415,109 @@ public Entry.ListEntry diff(@NonNull Entry.ListEntry bgn, @NonNull } } } + + public static class Sampler { + private static final String TAG = "Matrix.battery.Sampler"; + + final Handler mHandler; + final Callable mSamplingBlock; + + private final Runnable mSamplingTask = new Runnable() { + @Override + public void run() { + try { + Number currSample = mSamplingBlock.call(); + mSampleLst = currSample.doubleValue(); + mCount++; + mSampleAvg = (mSampleAvg * (mCount - 1) + mSampleLst) / mCount; + if (mSampleFst == Double.MIN_VALUE) { + mSampleFst = mSampleLst; + mSampleMax = mSampleLst; + mSampleMin = mSampleLst; + } else { + if (mSampleLst > mSampleMax) { + mSampleMax = mSampleLst; + } + if (mSampleLst < mSampleMin) { + mSampleMin = mSampleLst; + } + } + } catch (Exception e) { + MatrixLog.printErrStackTrace(TAG, e, "onSamplingFailed: " + e); + } finally { + if (!mPaused) { + mHandler.postDelayed(this, mInterval); + } + } + } + }; + + boolean mPaused = true; + long mInterval = ONE_MIN; + int mCount = 0; + long mBgnMillis = 0; + long mEndMillis = 0; + double mSampleFst = Double.MIN_VALUE; + double mSampleLst = Double.MIN_VALUE; + double mSampleMax = Double.MIN_VALUE; + double mSampleMin = Double.MIN_VALUE; + double mSampleAvg = Double.MIN_VALUE; + + public Sampler(Handler handler, Callable onSampling) { + mHandler = handler; + mSamplingBlock = onSampling; + } + + public void setInterval(long interval) { + if (interval > 0) { + mInterval = interval; + } + } + + public void start() { + mPaused = false; + mBgnMillis = SystemClock.uptimeMillis(); + mHandler.postDelayed(mSamplingTask, mInterval); + } + + public void pause() { + mPaused = true; + mEndMillis = SystemClock.uptimeMillis(); + mHandler.removeCallbacks(mSamplingTask); + } + + @Nullable + public Result getResult() { + if (mCount <= 0) { + MatrixLog.w(TAG, "Sampling count is invalid: " + mCount); + return null; + } + if (mBgnMillis <= 0 || mEndMillis <= 0 || mBgnMillis > mEndMillis) { + MatrixLog.w(TAG, "Sampling bgn/end millis is invalid: " + mBgnMillis + " - " + mEndMillis); + return null; + } + Result result = new Result(); + result.interval = mInterval; + result.count = mCount; + result.duringMillis = mEndMillis - mBgnMillis; + result.sampleFst = mSampleFst; + result.sampleLst = mSampleLst; + result.sampleMax = mSampleMax; + result.sampleMin = mSampleMin; + result.sampleAvg = mSampleAvg; + return result; + } + + public static final class Result { + public long interval; + public int count; + public long duringMillis; + public double sampleFst; + public double sampleLst; + public double sampleMax; + public double sampleMin; + public double sampleAvg; + } + } } } diff --git a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/Sampler.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/Sampler.java deleted file mode 100644 index 429ff6eda..000000000 --- a/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/feature/Sampler.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.tencent.matrix.batterycanary.monitor.feature; - -import android.os.Handler; -import android.os.SystemClock; - -import com.tencent.matrix.util.MatrixLog; - -import java.util.concurrent.Callable; - -import androidx.annotation.Nullable; - -import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_MIN; - -/** - * @author Kaede - * @since 2021/11/3 - */ -class Sampler { - private static final String TAG = "Matrix.battery.Sampler"; - - final Handler mHandler; - final Callable mSamplingBlock; - - private final Runnable mSamplingTask = new Runnable() { - @Override - public void run() { - try { - Number currSample = mSamplingBlock.call(); - mSampleLst = currSample.doubleValue(); - mCount++; - mSampleAvg = (mSampleAvg * (mCount - 1) + mSampleLst) / mCount; - if (mSampleFst == Double.MIN_VALUE) { - mSampleFst = mSampleLst; - mSampleMax = mSampleLst; - mSampleMin = mSampleLst; - } else { - if (mSampleLst > mSampleMax) { - mSampleMax = mSampleLst; - } - if (mSampleLst < mSampleMin) { - mSampleMin = mSampleLst; - } - } - } catch (Exception e) { - MatrixLog.printErrStackTrace(TAG, e, "onSamplingFailed: " + e); - } finally { - if (!mPaused) { - mHandler.postDelayed(this, mInterval); - } - } - } - }; - - boolean mPaused = true; - long mInterval = ONE_MIN; - int mCount = 0; - long mBgnMillis = 0; - long mEndMillis = 0; - double mSampleFst = Double.MIN_VALUE; - double mSampleLst = Double.MIN_VALUE; - double mSampleMax = Double.MIN_VALUE; - double mSampleMin = Double.MIN_VALUE; - double mSampleAvg = Double.MIN_VALUE; - - Sampler(Handler handler, Callable onSampling) { - mHandler = handler; - mSamplingBlock = onSampling; - } - - public void setInterval(long interval) { - if (interval > 0) { - mInterval = interval; - } - } - - public void start() { - mPaused = false; - mBgnMillis = SystemClock.uptimeMillis(); - mHandler.postDelayed(mSamplingTask, mInterval); - } - - public void pause() { - mPaused = true; - mEndMillis = SystemClock.uptimeMillis(); - mHandler.removeCallbacks(mSamplingTask); - } - - @Nullable - public Result getResult() { - if (mCount <= 0) { - MatrixLog.w(TAG, "Sampling count is invalid: " + mCount); - return null; - } - if (mBgnMillis <= 0 || mEndMillis <= 0 || mBgnMillis > mEndMillis) { - MatrixLog.w(TAG, "Sampling bgn/end millis is invalid: " + mBgnMillis + " - " + mEndMillis); - return null; - } - Result result = new Result(); - result.interval = mInterval; - result.count = mCount; - result.duringMillis = mEndMillis - mBgnMillis; - result.sampleFst = mSampleFst; - result.sampleLst = mSampleLst; - result.sampleMax = mSampleMax; - result.sampleMin = mSampleMin; - result.sampleAvg = mSampleAvg; - return result; - } - - public static final class Result { - public long interval; - public int count; - public long duringMillis; - public double sampleFst; - public double sampleLst; - public double sampleMax; - public double sampleMin; - public double sampleAvg; - } -} From 09ff3709abb7541fb379b5d5e1bb2c40f26d20f0 Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 3 Nov 2021 17:35:14 +0800 Subject: [PATCH 012/163] Update battery stacks collect --- .../matrix/batterycanary/utils/BatteryCanaryUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 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 d7110058f..a05b8ee9f 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 @@ -211,11 +211,11 @@ public static String stackTraceToString(final StackTraceElement[] arr) { } } } - StringBuilder sb = new StringBuilder(stacks.size()); - for (StackTraceElement stackTraceElement : stacks) { - sb.append(stackTraceElement).append('\n'); + StringBuilder sb = new StringBuilder(); + for (StackTraceElement traceElement : stacks) { + sb.append("\n").append("at ").append(traceElement); } - return sb.toString(); + return sb.length() > 0 ? "Matrix" + sb.toString() : ""; } public static String getThrowableStack(Throwable throwable) { From 29b81c20edfef1960b498873d72749748268c98b Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 3 Nov 2021 19:08:20 +0800 Subject: [PATCH 013/163] Update battery printer with sampler --- .../feature/MonitorFeatureOverAllTest.java | 10 ++++++++ .../monitor/BatteryMonitorCallback.java | 24 +++++++++++++++++++ .../monitor/feature/CompositeMonitors.java | 9 ++++++- .../monitor/feature/MonitorFeature.java | 5 ++-- 4 files changed, 45 insertions(+), 3 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 d3b0b77fe..4fc36c443 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 @@ -27,6 +27,7 @@ import com.tencent.matrix.batterycanary.BatteryEventDelegate; import com.tencent.matrix.batterycanary.BatteryMonitorPlugin; import com.tencent.matrix.batterycanary.TestUtils; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCallback; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; @@ -74,6 +75,15 @@ private BatteryMonitorCore mockMonitor() { .wakelockTimeout(1000) .greyJiffiesTime(100) .foregroundLoopCheckTime(1000) + .setCallback(new BatteryMonitorCallback.BatteryPrinter() { + @Override + public BatteryPrinter attach(BatteryMonitorCore monitorCore) { + BatteryPrinter core = super.attach(monitorCore); + mCompositeMonitors.sample(DeviceStatMonitorFeature.BatteryTmpSnapshot.class, 100L); + mCompositeMonitors.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.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/BatteryMonitorCallback.java b/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/monitor/BatteryMonitorCallback.java index 635acb218..9dacc7fda 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 @@ -30,6 +30,7 @@ import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature.Snapshot.Entry.BeanEntry; 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.MonitorFeature.Snapshot.Sampler; import com.tencent.matrix.batterycanary.monitor.feature.NotificationMonitorFeature; import com.tencent.matrix.batterycanary.monitor.feature.NotificationMonitorFeature.BadNotification; import com.tencent.matrix.batterycanary.monitor.feature.TrafficMonitorFeature; @@ -880,6 +881,17 @@ protected boolean onWritingSectionContent(@NonNull Delta sessionDelta, Compos printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); printer.writeLine("inc", Arrays.toString(delta.dlt.cpuFreqs.getList().toArray())); printer.writeLine("cur", Arrays.toString(delta.end.cpuFreqs.getList().toArray())); + monitors.getSamplingResult(CpuFreqSnapshot.class, new Consumer() { + @Override + public void accept(Sampler.Result result) { + printer.createSubSection("cpufreq_sampling"); + printer.writeLine(result.duringMillis + "(mls)\t" + (result.interval) + "(itv)"); + printer.writeLine("max", String.valueOf(result.sampleMax)); + printer.writeLine("min", String.valueOf(result.sampleMin)); + printer.writeLine("avg", String.valueOf(result.sampleAvg)); + printer.writeLine("cnt", String.valueOf(result.count)); + } + }); return true; } @@ -909,6 +921,7 @@ public void accept(Delta jiffiesDelta) { } // BatterySip if (cpuStatFeature != null) { + 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))); @@ -939,6 +952,17 @@ public void accept(Delta jiffiesDelta) { printer.writeLine(delta.during + "(mls)\t" + (delta.during / ONE_MIN) + "(min)"); printer.writeLine("inc", String.valueOf(delta.dlt.temp.get())); printer.writeLine("cur", String.valueOf(delta.end.temp.get())); + monitors.getSamplingResult(BatteryTmpSnapshot.class, new Consumer() { + @Override + public void accept(Sampler.Result result) { + printer.createSubSection("batt_temp_sampling"); + printer.writeLine(result.duringMillis + "(mls)\t" + (result.interval) + "(itv)"); + printer.writeLine("max", String.valueOf(result.sampleMax)); + printer.writeLine("min", String.valueOf(result.sampleMin)); + printer.writeLine("avg", String.valueOf(result.sampleAvg)); + printer.writeLine("cnt", String.valueOf(result.count)); + } + }); 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 e58b88f97..a42d1aff9 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 @@ -155,6 +155,13 @@ public Snapshot.Sampler.Result getSamplingResult(Class> sn return mSampleResults.get(snapshotClass); } + public void getSamplingResult(Class> snapshotClass, Consumer block) { + Snapshot.Sampler.Result result = getSamplingResult(snapshotClass); + if (result != null) { + block.accept(result); + } + } + @CallSuper public CompositeMonitors metricAll() { metric(JiffiesMonitorFeature.JiffiesSnapshot.class); @@ -363,7 +370,7 @@ public int compare(DigitEntry o1, DigitEntry o2) { return o1.get().compareTo(o2.get()); } }); - return list.isEmpty() ? 0 : list.get(0).get(); + return list.isEmpty() ? 0 : list.get(list.size() - 1).get(); } }); mSamplers.put(snapshotClass, sampler); 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 e977c4a48..d05a18915 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 @@ -3,8 +3,6 @@ import android.os.Handler; import android.os.SystemClock; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; import com.tencent.matrix.util.MatrixLog; @@ -15,6 +13,9 @@ import java.util.Objects; import java.util.concurrent.Callable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import static com.tencent.matrix.batterycanary.utils.BatteryCanaryUtil.ONE_MIN; public interface MonitorFeature { From 73fc5e9e36f17462f906b2010faa88188cbaa879 Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 3 Nov 2021 19:28:31 +0800 Subject: [PATCH 014/163] Add example codes --- .../matrix/batterycanary/Examples.java | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.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 new file mode 100644 index 000000000..57cfb8a79 --- /dev/null +++ b/matrix/matrix-android/matrix-battery-canary/src/androidTest/java/com/tencent/matrix/batterycanary/Examples.java @@ -0,0 +1,185 @@ +/* + * 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; + +import android.app.Application; +import android.content.Context; + +import com.tencent.matrix.Matrix; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorConfig; +import com.tencent.matrix.batterycanary.monitor.BatteryMonitorCore; +import com.tencent.matrix.batterycanary.monitor.feature.AlarmMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.AppStatMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.BlueToothMonitorFeature; +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.LocationMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.LooperTaskMonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.MonitorFeature; +import com.tencent.matrix.batterycanary.monitor.feature.NotificationMonitorFeature; +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 org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + + +@RunWith(AndroidJUnit4.class) +public class Examples { + static final String TAG = "Matrix.test.Examples"; + + Context mContext; + + @Test + public void exampleForCpuLoad() { + 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.metric(CpuStatFeature.CpuStateSnapshot.class); + compositor.start(); + + doSomething(); + + compositor.finish(); + int cpuLoad = compositor.getCpuLoad(); + Assert.assertTrue(cpuLoad > 0); + } + } + } + + @Test + public void exampleForCpuFreqSampling() { + 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.sample(DeviceStatMonitorFeature.CpuFreqSnapshot.class, 10L); + compositor.start(); + + doSomething(); + + compositor.finish(); + MonitorFeature.Snapshot.Sampler.Result result = compositor.getSamplingResult(DeviceStatMonitorFeature.CpuFreqSnapshot.class); + Assert.assertNotNull(result); + Assert.assertTrue(result.sampleAvg > 0); + } + } + } + + @Test + public void exampleForTemperatureSampling() { + 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.sample(DeviceStatMonitorFeature.BatteryTmpSnapshot.class, 10L); + compositor.start(); + + doSomething(); + + compositor.finish(); + MonitorFeature.Snapshot.Sampler.Result result = compositor.getSamplingResult(DeviceStatMonitorFeature.BatteryTmpSnapshot.class); + Assert.assertNotNull(result); + Assert.assertTrue(result.sampleAvg > 0); + } + } + } + + private void doSomething() { + try { + Thread.sleep(1000L); + } catch (InterruptedException ignored) { + } + } + + @Before + public void setUp() { + System.setProperty("org.mockito.android.target", ApplicationProvider.getApplicationContext().getCacheDir().getPath()); + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + if (!Matrix.isInstalled()) { + Matrix.init(new Matrix.Builder(((Application) mContext.getApplicationContext())).build()); + } + if (!BatteryEventDelegate.isInit()) { + BatteryEventDelegate.init((Application) mContext.getApplicationContext()); + } + } + + @After + public void shutDown() { + } + + private void mockSetup() { + final BatteryMonitorCore monitor = mockMonitor(); + BatteryMonitorPlugin plugin = new BatteryMonitorPlugin(monitor.getConfig()); + Matrix.with().getPlugins().add(plugin); + monitor.enableForegroundLoopCheck(true); + monitor.start(); + } + + private BatteryMonitorCore mockMonitor() { + BatteryMonitorConfig config = new BatteryMonitorConfig.Builder() + .enable(JiffiesMonitorFeature.class) + .enable(LooperTaskMonitorFeature.class) + .enable(WakeLockMonitorFeature.class) + .enable(DeviceStatMonitorFeature.class) + .enable(AlarmMonitorFeature.class) + .enable(AppStatMonitorFeature.class) + .enable(BlueToothMonitorFeature.class) + .enable(WifiMonitorFeature.class) + .enable(LocationMonitorFeature.class) + .enable(TrafficMonitorFeature.class) + .enable(NotificationMonitorFeature.class) + .enable(CpuStatFeature.class) + .enableBuiltinForegroundNotify(false) + .enableForegroundMode(true) + .wakelockTimeout(1000) + .greyJiffiesTime(100) + .foregroundLoopCheckTime(1000) + .build(); + return new BatteryMonitorCore(config); + } +} From a7d67ce7cb011704e89a4712cf29819ebfc04197 Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 3 Nov 2021 19:55:43 +0800 Subject: [PATCH 015/163] Append commit --- .../monitor/feature/CompositeMonitors.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 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 a42d1aff9..1851b90f5 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 @@ -396,10 +396,14 @@ public Number call() { @Override public String toString() { - return "CompositeMonitors{" + - "Metrics=" + mBgnSnapshots + - ", BgnSnapshots=" + mMetrics + - ", Deltas=" + mDeltas + + return "CompositeMonitors{" + "\n" + + "Metrics=" + mMetrics + "\n" + + ", BgnSnapshots=" + mBgnSnapshots + "\n" + + ", Deltas=" + mDeltas + "\n" + + ", SampleRegs=" + mSampleRegs + "\n" + + ", Samplers=" + mSamplers + "\n" + + ", SampleResults=" + mSampleResults + "\n" + + ", AppStats=" + mAppStats + "\n" + '}'; } } From 50685a132c4d69adff3fdc77abb30e61e75db88a Mon Sep 17 00:00:00 2001 From: Kaede Date: Thu, 4 Nov 2021 15:58:28 +0800 Subject: [PATCH 016/163] Update battery tmp with caching --- .../batterycanary/utils/CanaryUtilsTest.java | 2 +- .../monitor/BatteryMonitorCore.java | 4 +++- .../batterycanary/utils/BatteryCanaryUtil.java | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 2 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 e5f155cfa..a3c43e5a0 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,7 +169,7 @@ public void testGetCpuFreq() throws InterruptedException { @Test public void testGetBatteryTemps() throws InterruptedException { for (int i = 0; i < 5; i++) { - int temperature = BatteryCanaryUtil.getBatteryTemperature(mContext); + int temperature = BatteryCanaryUtil.getBatteryTemperatureImmediately(mContext); Assert.assertTrue(temperature > 0); Thread.sleep(100L); } 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 79593f229..f357a9099 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 @@ -299,7 +299,9 @@ public boolean isForeground() { public int getCurrentBatteryTemperature(Context context) { try { - return BatteryCanaryUtil.getBatteryTemperature(context); + int tmp = BatteryCanaryUtil.getBatteryTemperature(context); + MatrixLog.i(TAG, "onGetTemperature, battery = " + tmp); + return tmp; } catch (Throwable e) { MatrixLog.printErrStackTrace(TAG, e, "#currentBatteryTemperature error"); return 0; 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 a05b8ee9f..cf51100b2 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 @@ -71,6 +71,7 @@ public final class BatteryCanaryUtil { public interface Proxy { String getProcessName(); String getPackageName(); + int getBatteryTemperature(Context context); @AppStats.AppStatusDef int getAppStat(Context context, boolean isForeground); @AppStats.DevStatusDef int getDevStat(Context context); void updateAppStat(int value); @@ -96,6 +97,7 @@ boolean isExpired() { static Proxy sCacheStub = new Proxy() { private String mProcessName; private String mPackageName; + private ExpireRef mBatteryTemp; private ExpireRef mLastAppStat; private ExpireRef mLastDevStat; @@ -125,6 +127,16 @@ public String getPackageName() { return mPackageName; } + @Override + public int getBatteryTemperature(Context context) { + if (mBatteryTemp != null && !mBatteryTemp.isExpired()) { + return mBatteryTemp.value; + } + int tmp = getBatteryTemperatureImmediately(context); + mBatteryTemp = new ExpireRef(tmp, DEFAULT_AMS_CACHE_MILLIS); + return mBatteryTemp.value; + } + @Override public int getAppStat(Context context, boolean isForeground) { if (isForeground) return APP_STAT_FOREGROUND; // 前台 @@ -302,6 +314,10 @@ public static String cat(String path) { } public static int getBatteryTemperature(Context context) { + return sCacheStub.getBatteryTemperature(context); + } + + public static int getBatteryTemperatureImmediately(Context context) { try { Intent batIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); if (batIntent == null) return 0; From f23b2462522be4737b1d35d4e6e2917166186d47 Mon Sep 17 00:00:00 2001 From: carlguo Date: Tue, 9 Nov 2021 21:45:10 +0800 Subject: [PATCH 017/163] [TracePlugin] Add method trace file check. --- .../src/main/java/com/tencent/matrix/trace/MethodTracer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/trace/MethodTracer.java b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/trace/MethodTracer.java index 8c43c72bd..407c70154 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/trace/MethodTracer.java +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/java/com/tencent/matrix/trace/MethodTracer.java @@ -134,6 +134,11 @@ private void innerTraceMethodFromSrc(File input, File output, ClassLoader classL try { final String changedFileInputFullPath = classFile.getAbsolutePath(); final File changedFileOutput = new File(changedFileInputFullPath.replace(input.getAbsolutePath(), output.getAbsolutePath())); + + if (changedFileOutput.getCanonicalPath().equals(classFile.getCanonicalPath())) { + throw new RuntimeException("Input file(" + classFile.getCanonicalPath() + ") should not be same with output!"); + } + if (!changedFileOutput.exists()) { changedFileOutput.getParentFile().mkdirs(); } From 1fa52799cfc95595898e977ed26cd208d3a6a51c Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 10 Nov 2021 11:12:43 +0800 Subject: [PATCH 018/163] Update battery compositor with fork configs --- .../monitor/feature/CompositeMonitors.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 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 1851b90f5..9d282a6f0 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 @@ -43,7 +43,7 @@ public class CompositeMonitors { protected BatteryMonitorCore mMonitor; @Nullable protected AppStats mAppStats; - private long mBgnMillis = SystemClock.uptimeMillis(); + protected long mBgnMillis = SystemClock.uptimeMillis(); public CompositeMonitors(@Nullable BatteryMonitorCore core) { mMonitor = core; @@ -56,6 +56,21 @@ public void clear() { mSampleResults.clear(); } + public CompositeMonitors fork() { + CompositeMonitors that = new CompositeMonitors(mMonitor); + that.mBgnMillis = this.mBgnMillis; + that.mAppStats = this.mAppStats; + + that.mMetrics.addAll(mMetrics); + that.mBgnSnapshots.putAll(mBgnSnapshots); + that.mDeltas.putAll(mDeltas); + + that.mSampleRegs.putAll(mSampleRegs); + that.mSamplers.putAll(mSamplers); + that.mSampleResults.putAll(mSampleResults); + return that; + } + @Nullable public BatteryMonitorCore getMonitor() { return mMonitor; @@ -236,7 +251,6 @@ protected void configureEndDeltas() { } } } - mAppStats = AppStats.current(SystemClock.uptimeMillis() - mBgnMillis); } @CallSuper From c6a7c289c02acd542c01bd40193a197d7db36571 Mon Sep 17 00:00:00 2001 From: aurorani Date: Thu, 21 Oct 2021 20:16:35 +0800 Subject: [PATCH 019/163] feat: Complete memory fork-dump. --- .../matrix-memory-dump/CMakeLists.txt | 31 ++ .../matrix-memory-dump/build.gradle | 57 +++ .../matrix-memory-dump/consumer-rules.pro | 0 .../matrix-memory-dump/gradle.properties | 1 + .../matrix-memory-dump/proguard-rules.pro | 21 ++ .../memorydump/ExampleInstrumentedTest.kt | 24 ++ .../src/main/AndroidManifest.xml | 5 + .../src/main/cpp/bionic/tls.h | 43 +++ .../src/main/cpp/bionic/tls_defines.h | 119 ++++++ .../main/cpp/dlfcn/enhance/EnhanceDlsym.cpp | 347 +++++++++++++++++ .../src/main/cpp/dlfcn/enhance/EnhanceDlsym.h | 57 +++ .../src/main/cpp/dlfcn/self_dlfcn.cpp | 32 ++ .../src/main/cpp/dlfcn/self_dlfcn.h | 20 + .../src/main/cpp/internal/log.h | 26 ++ .../src/main/cpp/mem_dump.cpp | 354 ++++++++++++++++++ .../src/main/cpp/runtime/collector_type.h | 62 +++ .../src/main/cpp/runtime/gc_cause.h | 67 ++++ .../tencent/matrix/memorydump/MemoryDump.kt | 337 +++++++++++++++++ .../matrix/memorydump/ExampleUnitTest.kt | 17 + .../build.gradle | 1 + .../processor/ForkAnalyseProcessor.java | 101 +++++ .../resource/processor/ForkDumpProcessor.java | 53 +++ .../resource/watcher/ActivityRefWatcher.java | 22 +- matrix/matrix-android/settings.gradle | 1 + 24 files changed, 1790 insertions(+), 8 deletions(-) create mode 100644 matrix/matrix-android/matrix-memory-dump/CMakeLists.txt create mode 100644 matrix/matrix-android/matrix-memory-dump/build.gradle create mode 100644 matrix/matrix-android/matrix-memory-dump/consumer-rules.pro create mode 100644 matrix/matrix-android/matrix-memory-dump/gradle.properties create mode 100644 matrix/matrix-android/matrix-memory-dump/proguard-rules.pro create mode 100644 matrix/matrix-android/matrix-memory-dump/src/androidTest/java/com/tencent/matrix/memorydump/ExampleInstrumentedTest.kt create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/AndroidManifest.xml create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/bionic/tls.h create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/bionic/tls_defines.h create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.h create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.cpp create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.h create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/internal/log.h create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/mem_dump.cpp create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/runtime/collector_type.h create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/runtime/gc_cause.h create mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt create mode 100644 matrix/matrix-android/matrix-memory-dump/src/test/java/com/tencent/matrix/memorydump/ExampleUnitTest.kt create mode 100644 matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java create mode 100644 matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java diff --git a/matrix/matrix-android/matrix-memory-dump/CMakeLists.txt b/matrix/matrix-android/matrix-memory-dump/CMakeLists.txt new file mode 100644 index 000000000..8db8788e4 --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.10.2) + +project("matrix-memorydump") + +add_library( + matrix-memorydump + SHARED + src/main/cpp/mem_dump.cpp + src/main/cpp/dlfcn/self_dlfcn.cpp + src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp) + +find_library( + log-lib + log) + +target_include_directories( + matrix-memorydump + PRIVATE ${EXT_DEP}/include + PRIVATE ${EXT_DEP}/include/backtrace/common) + +target_link_libraries( + matrix-memorydump + ${log-lib} + ${EXT_DEP}/lib/${ANDROID_ABI}/libsemi_dlfcn.a) + +if(${ANDROID_ABI} MATCHES "armeabi-v7a" OR ${ANDROID_ABI} MATCHES "arm64-v8a") + target_link_libraries( + matrix-memorydump + ${EXT_DEP}/lib/${ANDROID_ABI}/libwechatbacktrace.so + ) +endif() \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/build.gradle b/matrix/matrix-android/matrix-memory-dump/build.gradle new file mode 100644 index 000000000..d5428139a --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/build.gradle @@ -0,0 +1,57 @@ +plugins { + id 'com.android.library' + id 'kotlin-android' +} + +apply from: rootProject.file('gradle/WeChatNativeDepend.gradle') + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + + defaultConfig { + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName rootProject.ext.VERSION_NAME + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$gradle.KOTLIN_VERSION" + implementation project(':matrix-android-lib') + implementation project(':matrix-android-commons') + implementation project(':matrix-backtrace') + + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' +} + +version rootProject.ext.VERSION_NAME +group rootProject.ext.GROUP + +if ("External" == rootProject.ext.PUBLISH_CHANNEL) { + apply from: rootProject.file('gradle/android-publish.gradle') +} else { + apply from: rootProject.file('gradle/WeChatPublish.gradle') + wechatPublish { + artifactId = POM_ARTIFACT_ID + } +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/consumer-rules.pro b/matrix/matrix-android/matrix-memory-dump/consumer-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/matrix/matrix-android/matrix-memory-dump/gradle.properties b/matrix/matrix-android/matrix-memory-dump/gradle.properties new file mode 100644 index 000000000..9ec625401 --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/gradle.properties @@ -0,0 +1 @@ +POM_ARTIFACT_ID=matrix-memory-dump \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/proguard-rules.pro b/matrix/matrix-android/matrix-memory-dump/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/androidTest/java/com/tencent/matrix/memorydump/ExampleInstrumentedTest.kt b/matrix/matrix-android/matrix-memory-dump/src/androidTest/java/com/tencent/matrix/memorydump/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..26bd9ede1 --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/androidTest/java/com/tencent/matrix/memorydump/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.tencent.matrix.memorydump + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.tencent.matrix.memorydump.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/AndroidManifest.xml b/matrix/matrix-android/matrix-memory-dump/src/main/AndroidManifest.xml new file mode 100644 index 000000000..fd63856aa --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/bionic/tls.h b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/bionic/tls.h new file mode 100644 index 000000000..c6404039e --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/bionic/tls.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#if defined(__aarch64__) +# define __get_tls() ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; }) +#elif defined(__arm__) +# define __get_tls() ({ void** __val; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__val)); __val; }) +#elif defined(__i386__) +# define __get_tls() ({ void** __val; __asm__("movl %%gs:0, %0" : "=r"(__val)); __val; }) +#elif defined(__x86_64__) +# define __get_tls() ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; }) +#else +#error unsupported architecture +#endif + +#include "tls_defines.h" \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/bionic/tls_defines.h b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/bionic/tls_defines.h new file mode 100644 index 000000000..fbe0ed5cb --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/bionic/tls_defines.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +/** WARNING WARNING WARNING + ** + ** This header file is *NOT* part of the public Bionic ABI/API and should not + ** be used/included by user-serviceable parts of the system (e.g. + ** applications). + ** + ** It is only provided here for the benefit of Android components that need a + ** pre-allocated slot for performance reasons (including ART, the OpenGL + ** subsystem, and sanitizers). + **/ + +// Bionic TCB / TLS slots: +// +// - TLS_SLOT_SELF: On x86-{32,64}, the kernel makes TLS memory available via +// the gs/fs segments. To get the address of a TLS variable, the first slot +// of TLS memory (accessed using %gs:0 / %fs:0) holds the address of the +// gs/fs segment. This slot is used by: +// - OpenGL and compiler-rt +// - Accesses of x86 ELF TLS variables +// +// - TLS_SLOT_OPENGL and TLS_SLOT_OPENGL_API: These two aren't used by bionic +// itself, but allow the graphics code to access TLS directly rather than +// using the pthread API. +// +// - TLS_SLOT_STACK_GUARD: Used for -fstack-protector by: +// - Clang targeting Android/arm64 +// - gcc targeting Linux/x86-{32,64} +// +// - TLS_SLOT_SANITIZER: Lets sanitizers avoid using pthread_getspecific for +// finding the current thread state. +// +// - TLS_SLOT_DTV: Pointer to ELF TLS dynamic thread vector. +// +// - TLS_SLOT_ART_THREAD_SELF: Fast storage for Thread::Current() in ART. +// +// - TLS_SLOT_BIONIC_TLS: Optimizes accesses to bionic_tls by one load versus +// finding it using __get_thread(). +// +// - TLS_SLOT_APP: Available for use by apps in Android Q and later. (This slot +// was used for errno in P and earlier.) + +#if defined(__arm__) || defined(__aarch64__) + +// The ARM ELF TLS ABI specifies[1] that the thread pointer points at a 2-word +// TCB followed by the executable's TLS segment. Both the TCB and the +// executable's segment are aligned according to the segment, so Bionic requires +// a minimum segment alignment, which effectively reserves an 8-word TCB. The +// ARM spec allocates the first TCB word to the DTV. +// +// [1] "Addenda to, and Errata in, the ABI for the ARM Architecture". Section 3. +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf + +#define MIN_TLS_SLOT (-1) // update this value when reserving a slot +#define TLS_SLOT_BIONIC_TLS (-1) +#define TLS_SLOT_DTV 0 +#define TLS_SLOT_THREAD_ID 1 +#define TLS_SLOT_APP 2 // was historically used for errno +#define TLS_SLOT_OPENGL 3 +#define TLS_SLOT_OPENGL_API 4 +#define TLS_SLOT_STACK_GUARD 5 +#define TLS_SLOT_SANITIZER 6 // was historically used for dlerror +#define TLS_SLOT_ART_THREAD_SELF 7 + +// The maximum slot is fixed by the minimum TLS alignment in Bionic executables. +#define MAX_TLS_SLOT 7 + +#elif defined(__i386__) || defined(__x86_64__) + +// x86 uses variant 2 ELF TLS layout, which places the executable's TLS segment +// immediately before the thread pointer. New slots are allocated at positive +// offsets from the thread pointer. + +#define MIN_TLS_SLOT 0 + +#define TLS_SLOT_SELF 0 +#define TLS_SLOT_THREAD_ID 1 +#define TLS_SLOT_APP 2 // was historically used for errno +#define TLS_SLOT_OPENGL 3 +#define TLS_SLOT_OPENGL_API 4 +#define TLS_SLOT_STACK_GUARD 5 +#define TLS_SLOT_SANITIZER 6 // was historically used for dlerror +#define TLS_SLOT_ART_THREAD_SELF 7 +#define TLS_SLOT_DTV 8 +#define TLS_SLOT_BIONIC_TLS 9 +#define MAX_TLS_SLOT 9 // update this value when reserving a slot + +#endif + +#define BIONIC_TLS_SLOTS (MAX_TLS_SLOT - MIN_TLS_SLOT + 1) \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp new file mode 100644 index 000000000..2666bfee4 --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp @@ -0,0 +1,347 @@ +/* + * 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 "EnhanceDlsym.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../internal/log.h" + +#define TAG "Matrix.EnhanceDl" + +namespace enhance { + + static std::set m_opened_info; + static std::mutex m_dl_mutex; + static std::map m_founded_symtab; + + 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 inline bool start_with(std::string const &value, std::string const &starting) { + if (starting.size() > value.size()) { + return false; + } + return std::equal(starting.begin(), starting.end(), value.begin()); + } + + static std::string prepare_filename(const char *__filename) { + assert(__filename != nullptr); + std::stringstream ss; + + if (!start_with(__filename, "/")) { + ss << "/"; + if (!start_with(__filename, "lib")) { + ss << "lib"; + } + } + + ss << __filename; + + if (!end_with(__filename, ".so")) { + ss << ".so"; + } + + return ss.str(); + } + + static ElfW(Phdr) *get_first_segment_by_type_offset(DlInfo &__info, ElfW(Word) __type, + ElfW(Off) __offset) { + ElfW(Phdr) *phdr; + + for (phdr = __info.phdr; phdr < __info.phdr + __info.ehdr->e_phnum; phdr++) { + if (phdr->p_type == __type && phdr->p_offset == __offset) { + return phdr; + } + } + return nullptr; + } + + static int check_loaded_so(void *addr) { + Dl_info stack_info; + return dladdr(addr, &stack_info); + } + + static bool parse_maps(const std::string &__file_name, DlInfo &__info) { + bool found = false; + uintptr_t map_base_addr = 0; + char map_perm[5]; + unsigned long map_offset = 0; + char map_file_name[512]; + + std::ifstream input("/proc/self/maps"); + std::string aline; + + while (getline(input, aline)) { + if (sscanf(aline.c_str(), + "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%s", + &map_base_addr, + map_perm, + &map_offset, + map_file_name) != 4) { + continue; + } + +// _debug_log(TAG, "%s", aline.c_str()); + + if (end_with(map_file_name, __file_name) + && 0 != check_loaded_so((void *) map_base_addr)) { + found = true; + _debug_log(TAG, "found entry [%s]", aline.c_str()); + break; + } + } + + if (!found || map_perm[0] != 'r' || map_perm[3] != 'p') { + _error_log(TAG, "maps entry not found, %d, %c, %c", found, map_perm[0], map_perm[3]); + return false; + } + + __info.pathname = map_file_name; + __info.base_addr = map_base_addr; + __info.ehdr = reinterpret_cast(map_base_addr); + __info.phdr = reinterpret_cast(map_base_addr + __info.ehdr->e_phoff); + + //find the first load-segment with offset 0 + ElfW(Phdr) *phdr0 = get_first_segment_by_type_offset(__info, PT_LOAD, 0); + if (!phdr0) { + _error_log(TAG, "Can NOT found the first load segment. %s", map_file_name); + return false; + } + + //save load bias addr + if (__info.base_addr < phdr0->p_vaddr) { + _error_log(TAG, "base_addr < phdr0->p_vaddr"); + return false; + } + __info.bias_addr = __info.base_addr - phdr0->p_vaddr; + _debug_log(TAG, "bias_addr = %p, bias = %p", (void *)__info.bias_addr, (void *)phdr0->p_vaddr); + + return true; + } + + static bool parse_section_header(DlInfo &__info) { + + int fd = open(__info.pathname.c_str(), O_RDONLY | O_CLOEXEC); + if (-1 == fd) { + _error_log(TAG, "open file failed: %s", strerror(errno)); + return false; + } + + off_t elf_size = lseek(fd, 0, SEEK_END); + if (-1 == elf_size) { + close(fd); + return false; + } + ElfW(Ehdr) *elf = static_cast(mmap(nullptr, elf_size, PROT_READ, MAP_SHARED, fd, + 0)); + // TODO check elf header ? + + ElfW(Shdr) *shdr = reinterpret_cast(((uintptr_t) elf) + elf->e_shoff); + + ElfW(Shdr) *shdr_end = reinterpret_cast(((uintptr_t) shdr) + + elf->e_shentsize * elf->e_shnum); + + ElfW(Shdr) *shdr_shstrtab = reinterpret_cast((uintptr_t) shdr + + elf->e_shstrndx * + elf->e_shentsize); + + auto shstr = reinterpret_cast(((uintptr_t) elf) + + shdr_shstrtab->sh_offset); + + // SHT_SYMTAB 和 SHT_STRTAB 通常在 section header table 的末尾, 所以倒序遍历 + short flag = 0b11; + size_t count = 0; + __info.symtab_num = 0; + __info.strtab_size = 0; + do { + shdr_end--; + + switch (shdr_end->sh_type) { + + case SHT_SYMTAB: + _debug_log(TAG, "SHT_SYMTAB[%zu]", count++); + __info.symtab = static_cast(malloc(shdr_end->sh_size)); + memcpy(__info.symtab, + reinterpret_cast(((uintptr_t) elf) + shdr_end->sh_offset), + shdr_end->sh_size); + __info.symtab_num = shdr_end->sh_size / sizeof(ElfW(Sym)); + + flag &= 0b01; + break; + + case SHT_STRTAB: + _debug_log(TAG, "SHT_STRTAB[%zu]", count++); + + if (0 == strcmp(shstr + shdr_end->sh_name, ".strtab")) { + __info.strtab = static_cast(malloc(shdr_end->sh_size)); + __info.strtab_size = shdr_end->sh_size; + memcpy(__info.strtab, + reinterpret_cast(((uintptr_t) elf) + + shdr_end->sh_offset), + shdr_end->sh_size); + + flag &= 0b10; + } + + break; + } + + _debug_log(TAG, "flag = %d", flag); + + } while (flag && shdr_end != shdr); +// for (; shdr < shdr_end; shdr++) { +// +// switch (shdr->sh_type) { +// +// case SHT_SYMTAB: +// meta__.symtab = static_cast(malloc(shdr->sh_size)); +// memcpy(meta__.symtab, +// reinterpret_cast(((uintptr_t) elf) + shdr->sh_offset), shdr->sh_size); +// meta__.symtab_num = shdr_end->sh_size / sizeof(ElfW(Sym)); +// break; +// +// case SHT_STRTAB: +// +// if (0 == strcmp(shstr + shdr->sh_name,".strtab")) { +// meta__.strtab = static_cast(malloc(shdr->sh_size)); +// memcpy(meta__.strtab, +// reinterpret_cast(((uintptr_t) elf) + shdr->sh_offset), shdr->sh_size); +// } +// +// break; +// } +// } + _debug_log(TAG, "got symtab size = %d", __info.symtab_num); + + munmap(elf, elf_size); + close(fd); + + return true; + } + + static bool load(const std::string &__file_name, DlInfo &__info) { + return parse_maps(__file_name, __info) && parse_section_header(__info); + } + + void *dlopen(const char *__file_name, int __flag) { + std::lock_guard lock(m_dl_mutex); + + if (!__file_name) { + return nullptr; + } + + std::string &&suffix_name = prepare_filename(__file_name); + _debug_log(TAG, "final filename = %s", suffix_name.c_str()); + + auto info = new DlInfo; + + if (!load(suffix_name, *info)) { + delete info; + return nullptr; + } + + m_opened_info.emplace(info); + + return info; + } + + int dlclose(void *__handle) { + std::lock_guard lock(m_dl_mutex); + + if (__handle) { + auto info = static_cast(__handle); + m_opened_info.erase(info); + free(info->strtab); + free(info); + + std::map empty; + empty.swap(m_founded_symtab); + empty.clear(); + } + return 0; + } + + // TODO dlsym object and func + void *dlsym(void *__handle, const char *__symbol) { + std::lock_guard lock(m_dl_mutex); + + if (!__handle) { + return nullptr; + } + auto info = static_cast(__handle); + if (!m_opened_info.count(info)) { + return nullptr; + } + + + + ElfW(Sym) *symtab_end = info->symtab + info->symtab_num; + ElfW(Sym) *symtab_idx = info->symtab; + + for (; symtab_idx < symtab_end; symtab_idx++) { + + if (info->strtab_size <= symtab_idx->st_name) { + _debug_log(TAG, "context.strtabsz = %d, symtab_idx->st_name = %d", + info->strtab_size, symtab_idx->st_name); + } + assert (info->strtab_size > symtab_idx->st_name); + + std::string sym_name(info->strtab + symtab_idx->st_name); + if (sym_name == __symbol) { + _debug_log(TAG, "st_value=%x", symtab_idx->st_value); + uintptr_t found_sym_addr = symtab_idx->st_value + info->bias_addr; + if (check_loaded_so((void *)found_sym_addr) != 0) { + auto res = reinterpret_cast(found_sym_addr); + m_founded_symtab[res] = symtab_idx; + return res; + } + } + } + + return nullptr; + } + + size_t dlsizeof(void *__addr) { + + if (m_founded_symtab.count(__addr)) { + return m_founded_symtab[__addr]->st_size; + } + + return -1; + } +} + diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.h b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.h new file mode 100644 index 000000000..8a6d8fd8b --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.h @@ -0,0 +1,57 @@ +/* + * 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. +// + +#ifndef LIBMATRIX_JNI_ENHANCEDLSYM_H +#define LIBMATRIX_JNI_ENHANCEDLSYM_H + +#include +#include +#include +#include + +namespace enhance { + void* dlopen(const char* __file_name, int __flag); + int dlclose(void* __handle); + void* dlsym(void* __handle, const char* __symbol); + size_t dlsizeof(void *__addr); + + struct DlInfo { + + DlInfo() {} + ~DlInfo() {} + + std::string pathname; + + ElfW(Addr) base_addr; + ElfW(Addr) bias_addr; + + ElfW(Ehdr) *ehdr; // pointing to loaded mem + ElfW(Phdr) *phdr; // pointing to loaded mem + + char *strtab; // strtab + ElfW(Word) strtab_size; // size in bytes + + ElfW(Sym) *symtab; + ElfW(Word) symtab_num; + + }; +} + +#endif //LIBMATRIX_JNI_ENHANCEDLSYM_H diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.cpp b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.cpp new file mode 100644 index 000000000..94faf0cac --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.cpp @@ -0,0 +1,32 @@ +// +// Created by M.D. on 2021/10/29. +// + +#include "self_dlfcn.h" +#include "enhance/EnhanceDlsym.h" +#include + +extern "C" { + +static bool use_origin_ = false; + +void self_dlfcn_mode(int api) { + use_origin_ = api < __ANDROID_API_N__; +} + +void self_dlclose(void *handle) { + if (use_origin_) dlclose(handle); + else enhance::dlclose(handle); +} + +void *self_dlopen(const char *filename) { + if (use_origin_) return dlopen(filename, RTLD_NOW); + else return enhance::dlopen(filename, RTLD_NOW); +} + +void *self_dlsym(void *handle, const char *name) { + if (use_origin_) return dlsym(handle, name); + else return enhance::dlsym(handle, name); +} + +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.h b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.h new file mode 100644 index 000000000..f3e62264b --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.h @@ -0,0 +1,20 @@ +// +// Created by M.D. on 2021/10/29. +// + +#ifndef MATRIX_ANDROID_SELF_DLFCN_H +#define MATRIX_ANDROID_SELF_DLFCN_H + +extern "C" { + +void self_dlfcn_mode(int api); + +void self_dlclose(void *handle); + +void *self_dlopen(const char *filename); + +void *self_dlsym(void *handle, const char *name); + +} + +#endif //MATRIX_ANDROID_SELF_DLFCN_H diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/internal/log.h b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/internal/log.h new file mode 100644 index 000000000..fe7c33fca --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/internal/log.h @@ -0,0 +1,26 @@ +// +// Created by M.D. on 2021/10/26. +// + +#ifndef MATRIX_ANDROID_LOG_H +#define MATRIX_ANDROID_LOG_H + +#if defined(__aarch64__) || defined(__arm__) + +#include + +#define _info_log(tag, fmt, args...) LOGI(tag, FMT, ##args) +#define _debug_log(tag, fmt, args...) LOGD(tag, FMT, ##args) +#define _error_log(tag, fmt, args...) LOGE(tag, FMT, ##args) + +#else + +#include + +#define _info_log(tag, fmt, args...) __android_log_print(ANDROID_LOG_INFO, tag, fmt, ##args) +#define _debug_log(tag, fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, tag, fmt, ##args) +#define _error_log(tag, fmt, args...) __android_log_print(ANDROID_LOG_ERROR, tag, fmt, ##args) + +#endif + +#endif diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/mem_dump.cpp b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/mem_dump.cpp new file mode 100644 index 000000000..548077445 --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/mem_dump.cpp @@ -0,0 +1,354 @@ +#include +#include +#include +#include +#include +#include + +#include "bionic/tls.h" +#include "internal/log.h" +#include "runtime/collector_type.h" +#include "runtime/gc_cause.h" +#include "dlfcn/self_dlfcn.h" + +#define LOG_TAG "Matrix.MemoryDump" + +#define READ 0 +#define WRITE 1 + +struct fork_pair { + int pid; + int fd; +}; + +using namespace art::gc; + +namespace mirror { + + static void *suspend_all_ptr_ = nullptr; + + static void *resume_all_ptr_ = nullptr; + + class Thread { + }; + + class ScopedSuspend { + }; + + static void (*sgc_constructor)(void *, Thread *, GcCause, CollectorType) = nullptr; + + static void (*sgc_destructor)(void *) = nullptr; + + class ScopedGCCriticalSection { + private: + uint64_t buf[8] = {0}; + public: + ScopedGCCriticalSection(Thread *thread, GcCause cause, CollectorType collectorType) { + if (sgc_constructor != nullptr) { + sgc_constructor(this, thread, cause, collectorType); + } + } + + ~ScopedGCCriticalSection() { + if (sgc_destructor != nullptr) { + sgc_destructor(this); + } + } + }; + + static void (*exclusive_lock)(void *, Thread *) = nullptr; + + static void (*exclusive_unlock)(void *, Thread *) = nullptr; + + class ReadWriteMutex { + public: + void ExclusiveLock(Thread *self) { + if (exclusive_lock != nullptr) { + reinterpret_cast(exclusive_lock)(this, self); + } + } + + void ExclusiveUnlock(Thread *self) { + if (exclusive_unlock != nullptr) { + reinterpret_cast(exclusive_unlock)(this, self); + } + } + }; +} + +static int android_version_; + +static mirror::ScopedSuspend suspend_; + +static mirror::ReadWriteMutex *mutator_lock_ = nullptr; + +static void (*dump_heap_)(const char *, int, bool) = nullptr; + +static void suspend_runtime(mirror::Thread *thread) { + if (android_version_ > __ANDROID_API_Q__) { + mirror::ScopedGCCriticalSection sgc(thread, kGcCauseHprof, kCollectorTypeHprof); + + if (mirror::suspend_all_ptr_ != nullptr) { + reinterpret_cast + (mirror::suspend_all_ptr_)(&suspend_, "matrix_dump_hprof", true); + } else { + _error_log(LOG_TAG, + "Cannot suspend runtime because suspend function symbol cannot be found."); + } + + mutator_lock_->ExclusiveUnlock(thread); + } else { + if (mirror::suspend_all_ptr_ != nullptr) { + reinterpret_cast(mirror::suspend_all_ptr_)(); + } else { + _error_log(LOG_TAG, + "Cannot suspend runtime because suspend function symbol cannot be found."); + } + } +} + +static void resume_runtime(mirror::Thread *thread) { + if (android_version_ > __ANDROID_API_Q__) { + mutator_lock_->ExclusiveLock(thread); + + if (mirror::resume_all_ptr_ != nullptr) { + reinterpret_cast(mirror::resume_all_ptr_)(&suspend_); + } else { + _error_log(LOG_TAG, + "Cannot suspend runtime because suspend function symbol cannot be found."); + } + } else { + if (mirror::resume_all_ptr_ != nullptr) { + reinterpret_cast(mirror::resume_all_ptr_)(); + } else { + _error_log(LOG_TAG, + "Cannot resume runtime because resume function symbol cannot be found."); + } + } +} + +static bool initialize_functions( + void *(*_dl_open)(const char *), + void *(*_dl_sym)(void *, const char *), + void (*_dl_close)(void *), + const char *impl_tag +) { + auto *art_lib = _dl_open("libart.so"); + + if (art_lib == nullptr) { + _error_log(LOG_TAG, "Cannot dynamic open library libart.so with %s.", impl_tag); + return false; + } + + auto *lock_sym = reinterpret_cast( + _dl_sym(art_lib, "_ZN3art5Locks13mutator_lock_E")); + if (lock_sym == nullptr) { + _error_log(LOG_TAG, "Cannot find symbol art::Locks::mutator_lock_."); + goto on_error; + } else { + mutator_lock_ = *lock_sym; + } + +#define _load_symbol_unsafe(ptr, type, sym, err) \ + ptr = reinterpret_cast(_dl_sym(art_lib, sym)); \ + if (ptr == nullptr) { \ + _info_log(LOG_TAG, err); \ + } + +#define _load_symbol(ptr, type, sym, err) \ + ptr = reinterpret_cast(_dl_sym(art_lib, sym)); \ + if (ptr == nullptr) { \ + _error_log(LOG_TAG, err); \ + goto on_error; \ + } + + _load_symbol_unsafe(dump_heap_, + void(*)(const char *, int, bool ), + "_ZN3art5hprof8DumpHeapEPKcib", + "Cannot find symbol art::hprof::DumpHeap") + + if (android_version_ > __ANDROID_API_Q__) { + _load_symbol(mirror::suspend_all_ptr_, + void*, + "_ZN3art16ScopedSuspendAllC1EPKcb", + "Cannot find symbol art::ScopedSuspendAll().") + _load_symbol(mirror::resume_all_ptr_, + void*, + "_ZN3art16ScopedSuspendAllD1Ev", + "Cannot find symbol art::~ScopedSuspendAll().") + + _load_symbol(mirror::sgc_constructor, + void(*)(void * , mirror::Thread *, GcCause, CollectorType), + "_ZN3art2gc23ScopedGCCriticalSectionC1EPNS_6ThreadENS0_7GcCauseENS0_13CollectorTypeE", + "Cannot find symbol art::gc::ScopedGCCriticalSection().") + _load_symbol(mirror::sgc_destructor, + void(*)(void * ), + "_ZN3art2gc23ScopedGCCriticalSectionD1Ev", + "Cannot find symbol art::gc::~ScopedGCCriticalSection().") + + _load_symbol(mirror::exclusive_lock, + void(*)(void * , mirror::Thread *), + "_ZN3art17ReaderWriterMutex13ExclusiveLockEPNS_6ThreadE", + "Cannot find symbol art::ReaderWriterMutex::ExclusiveLock().") + _load_symbol(mirror::exclusive_unlock, + void(*)(void * , mirror::Thread *), + "_ZN3art17ReaderWriterMutex15ExclusiveUnlockEPNS_6ThreadE", + "Cannot find symbol art::ReaderWriterMutex::ExclusiveUnlock().") + } else { + _load_symbol(mirror::suspend_all_ptr_, + void*, + "_ZN3art3Dbg9SuspendVMEv", + "Cannot find symbol art::Dbg::SuspendVM.") + + _load_symbol(mirror::resume_all_ptr_, + void*, + "_ZN3art3Dbg8ResumeVMEv", + "Cannot find symbol art::Dbg::ResumeVM.") + } + + return true; + + on_error: + _dl_close(art_lib); + return false; +} + +static bool initialize_functions_with_self() { + return initialize_functions(self_dlopen, self_dlsym, self_dlclose, "self_dlfcn"); +} + +static bool initialize_functions_with_semi() { + return initialize_functions( + semi_dlopen, + reinterpret_cast(semi_dlsym), + semi_dlclose, + "semi_dlfcn" + ); +} + +static void fork_process_crash_handler(int signal_num) { + // Do nothing, just tell parent process to handle the error. + exit(-3); +} + +extern "C" JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_memorydump_MemoryDumpKt_initializeNative(JNIEnv *, jclass) { + + { + char api_level[5]; + if (__system_property_get("ro.build.version.sdk", api_level) < 1) { + _error_log(LOG_TAG, "Unable to get system property ro.build.version.sdk."); + } + android_version_ = static_cast(strtol(api_level, nullptr, 10)); + } + + // Set Android API version first to decide whether to use native "dlfcn" implementation or not. + self_dlfcn_mode(android_version_); + bool ret = initialize_functions_with_self(); + if (!ret) { + ret = initialize_functions_with_semi(); + } + return ret; +} + +extern "C" JNIEXPORT jint JNICALL +Java_com_tencent_matrix_memorydump_MemoryDumpKt_dumpHprof(JNIEnv *, jclass, jint fd) { + if (dump_heap_ != nullptr) { + dump_heap_("[fd]", fd, false); + return 0; + } else { + _error_log(LOG_TAG, "Failed to load art::hprof::DumpHeap()."); + return -1; + } +} + +extern "C" JNIEXPORT jint JNICALL +Java_com_tencent_matrix_memorydump_MemoryDumpKt_fork(JNIEnv *, jclass, jlong child_timeout) { + auto *thread = reinterpret_cast(__get_tls()[TLS_SLOT_ART_THREAD_SELF]); + suspend_runtime(thread); + int pid = fork(); + if (pid == 0) { + signal(SIGSEGV, fork_process_crash_handler); + alarm(child_timeout); + prctl(PR_SET_NAME, "matrix_dump_process"); + } else { + resume_runtime(thread); + } + return pid; +} + +extern "C" JNIEXPORT jlong JNICALL +Java_com_tencent_matrix_memorydump_MemoryDumpKt_forkPipe(JNIEnv *, jclass, jlong child_timeout) { + int fd[2]; + if (pipe(fd)) { + return -2; + } + + auto *ret = reinterpret_cast(malloc(sizeof(fork_pair))); + if (ret == nullptr) { + close(fd[READ]); + close(fd[WRITE]); + return -2; + } + + auto *thread = reinterpret_cast(__get_tls()[TLS_SLOT_ART_THREAD_SELF]); + suspend_runtime(thread); + + int pid = fork(); + ret->pid = pid; + if (pid == 0) { + close(fd[READ]); + ret->fd = fd[WRITE]; + signal(SIGSEGV, fork_process_crash_handler); + alarm(child_timeout); + prctl(PR_SET_NAME, "matrix_dump_process"); + return reinterpret_cast(ret); + } else { + resume_runtime(thread); + close(fd[WRITE]); + if (pid == -1) { + close(fd[READ]); + free(ret); + return -1; + } else { + ret->fd = fd[READ]; + return reinterpret_cast(ret); + } + } +} + +extern "C" JNIEXPORT jint JNICALL +Java_com_tencent_matrix_memorydump_MemoryDumpKt_wait(JNIEnv *, jclass, jint pid) { + int status; + if (waitpid(pid, &status, 0) == -1) { + _error_log(LOG_TAG, "Failed to invoke waitpid()."); + return -2; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } else { + _error_log(LOG_TAG, "Fork process exited unexpectedly."); + return -2; + } +} + +extern "C" JNIEXPORT void JNICALL +Java_com_tencent_matrix_memorydump_MemoryDumpKt_exit(JNIEnv *, jclass, jint code) { + _exit(code); +} + +extern "C" JNIEXPORT jint JNICALL +Java_com_tencent_matrix_memorydump_MemoryDumpKt_pidFromForkPair(JNIEnv *, jclass, jlong pointer) { + return reinterpret_cast(pointer)->pid; +} + +extern "C" JNIEXPORT jint JNICALL +Java_com_tencent_matrix_memorydump_MemoryDumpKt_fdFromForkPair(JNIEnv *, jclass, jlong pointer) { + return reinterpret_cast(pointer)->fd; +} + +extern "C" JNIEXPORT void JNICALL +Java_com_tencent_matrix_memorydump_MemoryDumpKt_free(JNIEnv *, jclass, jlong pointer) { + free(reinterpret_cast(pointer)); +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/runtime/collector_type.h b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/runtime/collector_type.h new file mode 100644 index 000000000..4aeed0dda --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/runtime/collector_type.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ +#ifndef ART_RUNTIME_GC_COLLECTOR_TYPE_H_ +#define ART_RUNTIME_GC_COLLECTOR_TYPE_H_ + +namespace art { +namespace gc { +// Which types of collections are able to be performed. +enum CollectorType { + // No collector selected. + kCollectorTypeNone, + // Non concurrent mark-sweep. + kCollectorTypeMS, + // Concurrent mark-sweep. + kCollectorTypeCMS, + // Semi-space / mark-sweep hybrid, enables compaction. + kCollectorTypeSS, + // Heap trimming collector, doesn't do any actual collecting. + kCollectorTypeHeapTrim, + // A (mostly) concurrent copying collector. + kCollectorTypeCC, + // The background compaction of the concurrent copying collector. + kCollectorTypeCCBackground, + // Instrumentation critical section fake collector. + kCollectorTypeInstrumentation, + // Fake collector for adding or removing application image spaces. + kCollectorTypeAddRemoveAppImageSpace, + // Fake collector used to implement exclusion between GC and debugger. + kCollectorTypeDebugger, + // A homogeneous space compaction collector used in background transition + // when both foreground and background collector are CMS. + kCollectorTypeHomogeneousSpaceCompact, + // Class linker fake collector. + kCollectorTypeClassLinker, + // JIT Code cache fake collector. + kCollectorTypeJitCodeCache, + // Hprof fake collector. + kCollectorTypeHprof, + // Fake collector for installing/removing a system-weak holder. + kCollectorTypeAddRemoveSystemWeakHolder, + // Fake collector type for GetObjectsAllocated + kCollectorTypeGetObjectsAllocated, + // Fake collector type for ScopedGCCriticalSection + kCollectorTypeCriticalSection, +}; + +} // namespace gc +} // namespace art +#endif // ART_RUNTIME_GC_COLLECTOR_TYPE_H_ \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/runtime/gc_cause.h b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/runtime/gc_cause.h new file mode 100644 index 000000000..05985a020 --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/runtime/gc_cause.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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. + */ +#ifndef ART_RUNTIME_GC_GC_CAUSE_H_ +#define ART_RUNTIME_GC_GC_CAUSE_H_ + +namespace art { +namespace gc { +// What caused the GC? +enum GcCause { + // Invalid GC cause used as a placeholder. + kGcCauseNone, + // GC triggered by a failed allocation. Thread doing allocation is blocked waiting for GC before + // retrying allocation. + kGcCauseForAlloc, + // A background GC trying to ensure there is free memory ahead of allocations. + kGcCauseBackground, + // An explicit System.gc() call. + kGcCauseExplicit, + // GC triggered for a native allocation when NativeAllocationGcWatermark is exceeded. + // (This may be a blocking GC depending on whether we run a non-concurrent collector). + kGcCauseForNativeAlloc, + // GC triggered for a collector transition. + kGcCauseCollectorTransition, + // Not a real GC cause, used when we disable moving GC (currently for GetPrimitiveArrayCritical). + kGcCauseDisableMovingGc, + // Not a real GC cause, used when we trim the heap. + kGcCauseTrim, + // Not a real GC cause, used to implement exclusion between GC and instrumentation. + kGcCauseInstrumentation, + // Not a real GC cause, used to add or remove app image spaces. + kGcCauseAddRemoveAppImageSpace, + // Not a real GC cause, used to implement exclusion between GC and debugger. + kGcCauseDebugger, + // GC triggered for background transition when both foreground and background collector are CMS. + kGcCauseHomogeneousSpaceCompact, + // Class linker cause, used to guard filling art methods with special values. + kGcCauseClassLinker, + // Not a real GC cause, used to implement exclusion between code cache metadata and GC. + kGcCauseJitCodeCache, + // Not a real GC cause, used to add or remove system-weak holders. + kGcCauseAddRemoveSystemWeakHolder, + // Not a real GC cause, used to prevent hprof running in the middle of GC. + kGcCauseHprof, + // Not a real GC cause, used to prevent GetObjectsAllocated running in the middle of GC. + kGcCauseGetObjectsAllocated, + // GC cause for the profile saver. + kGcCauseProfileSaver, + // GC cause for running an empty checkpoint. + kGcCauseRunEmptyCheckpoint, +}; + +} // namespace gc +} // namespace art +#endif // ART_RUNTIME_GC_GC_CAUSE_H_ \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt b/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt new file mode 100644 index 000000000..583032da9 --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt @@ -0,0 +1,337 @@ +package com.tencent.matrix.memorydump + +import android.os.Build +import android.os.Debug +import android.os.Process +import java.util.concurrent.Future +import java.util.concurrent.FutureTask +import com.tencent.matrix.util.MatrixLog +import java.io.BufferedInputStream +import java.io.FileInputStream +import java.io.InputStream +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executors + +private const val TAG = "Matrix.MemoryDump" + +/** + * Memory dump manager. + * + * The manager is used to dump heap memory into a HPROF file, like [Debug.dumpHprofData]. However, + * there are several API of manager can dump memory without suspend runtime. The manager will fork + * a new process for dumping (See [Copy-on-Write](https://en.wikipedia.org/wiki/Copy-on-write)). + * + * The idea is from [KOOM](https://github.com/KwaiAppTeam/KOOM). + * + * @author aurorani + * @since 2021/10/20 + */ +object MemoryDumpManager { + + private val initialized: Boolean = initialize() + + private const val DEFAULT_DUMP_TIMEOUT = 60L + + private val dumpExecutor = Executors.newSingleThreadExecutor { + Thread(it, "matrix_memory_dump_executor") + } + + /** + * Callback when dump process completes dumping memory. + * + * TODO: Convert to SAM interface after upgrading Kotlin version to 1.4. + * + * @author aurorani + * @since 2021/10/25 + */ + interface DumpCallback { + fun onDumpComplete(result: Boolean) + } + + /** + * Dump HPROF to specific file on [path]. It will suspend the whole runtime. + * + * The function may cause jank and garbage collection, and will not throw exceptions but return + * false and print stack trace if error happened. + */ + @JvmStatic + fun dumpSuspend(path: String): Boolean { + if (!initialized) { + MatrixLog.e(TAG, "Memory dump manager is not successfully initialized. Skip dump.") + return false + } + return try { + Debug.dumpHprofData(path) + true + } catch (exception: Exception) { + MatrixLog.printErrStackTrace(TAG, exception, "") + false + } + } + + /** + * Dump HPROF to specific file on [path]. Compared to [dumpSuspend], it will only suspend current + * thread. + * + * The function may cause jank and garbage collection, and will not throw exceptions but return + * false and print stack trace if error happened. + */ + @JvmStatic + @JvmOverloads + fun dumpBlock(path: String, timeout: Long = DEFAULT_DUMP_TIMEOUT): Boolean { + if (!initialized) { + MatrixLog.e(TAG, "Memory dump manager is not successfully initialized. Skip dump.") + return false + } + MatrixLog.i(TAG, "[dump block, pid: ${Process.myPid()}] Fork dump process.") + return when (val pid = fork(timeout)) { + -1 -> run { + MatrixLog.e(TAG, "Cannot fork child dump process.") + false + } + 0 -> run { + try { + if (dumpSuspend(path)) exit(0) else exit(-1) + } catch (exception: Exception) { + // The catch block may be unnecessary, because the runtime is broken and cannot + // create any exception to throw. But keep the code, whatever. + MatrixLog.printErrStackTrace(TAG, exception, "") + exit(-2) + } + true + } + else -> run { + MatrixLog.i( + TAG, + "[dump block, pid: ${Process.myPid()}] Wait dump complete (dump process pid: ${pid})." + ) + val result = wait(pid) + MatrixLog.i( + TAG, + "[dump block, pid: ${Process.myPid()}] Dump complete, status code: $result." + ) + result == 0 + } + } + } + + /** + * Dump HPROF to specific file on [path]. It will dump memory as an asynchronous computation. + * + * The function may cause jank and garbage collection, and will not throw exceptions but return + * false and print stack trace if error happened. + */ + @JvmStatic + fun dumpAsync(path: String): Future { + if (!initialized) { + MatrixLog.e(TAG, "Memory dump manager is not successfully initialized. Skip dump.") + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + CompletableFuture.completedFuture(false) + } else { + dumpExecutor.submit { false } + } + } + return dumpExecutor.submit { + dumpBlock(path) + } + } + + /** + * Dump HPROF to specific file on [path]. It will dump memory as an asynchronous computation. + * + * The function may cause jank and garbage collection, and will not throw exceptions but return + * false and print stack trace if error happened. + */ + @JvmStatic + fun dumpAsync(path: String, callback: DumpCallback) { + if (!initialized) { + MatrixLog.e(TAG, "Memory dump manager is not successfully initialized. Skip dump.") + callback.onDumpComplete(false) + } + dumpExecutor.execute { + callback.onDumpComplete(dumpBlock(path)) + } + } + + /** + * Dump HPROF as a buffered input stream. It will dump memory as an asynchronous computation. + * + * The function returns a dump handler including HPROF file input stream instance and a [Future] + * object for listening dump process status, see [DumpHandler]. + * + * The buffer size of buffered input stream will be set as default value of [BufferedInputStream] + * if [bufferSize] is not positive. + * + * TODO: Extract function for two [dumpStream] using inline. DO NOT ALLOCATE ANY OBJECT, INCLUDING LAMBDA. + * + * The function may cause jank and garbage collection, and will not throw exceptions but return + * false and print stack trace if error happened. + */ + @JvmStatic + @JvmOverloads + fun dumpStream( + bufferSize: Int = 0, + timeout: Long = DEFAULT_DUMP_TIMEOUT + ): DumpHandler? { + if (!initialized) { + MatrixLog.e(TAG, "Memory dump manager is not successfully initialized. Skip dump.") + return null + } + val pointer = forkPipe(timeout) + if (pointer == -1L) { + MatrixLog.e(TAG, "Cannot fork child dump process.") + return null + } + if (pointer == -2L) { + MatrixLog.e(TAG, "Failed to allocate native resource in parent process.") + return null + } + MatrixLog.i(TAG, "[dump stream, pid: ${Process.myPid()}] Fork dump process.") + val pid = pidFromForkPair(pointer) + val fd = fdFromForkPair(pointer) + return when (pid) { + 0 -> run { + try { + exit(dumpHprof(fd)) + } catch (exception: Exception) { + // The catch block may be unnecessary, because the runtime is broken and cannot + // create any exception to throw. But keep the code, whatever. + MatrixLog.printErrStackTrace(TAG, exception, "") + exit(-1) + } + throw RuntimeException("Unreachable code.") + } + else -> { + free(pointer) + val stream = FileInputStream("/proc/self/fd/${fd}").let { + if (bufferSize > 0) BufferedInputStream(it, bufferSize) + else BufferedInputStream(it) + } + val future = FutureTask { + MatrixLog.i( + TAG, + "[dump stream, pid: ${Process.myPid()}] Wait dump complete (dump process pid: ${pid})." + ) + val result = wait(pid) + MatrixLog.i( + TAG, + "[dump stream, pid: ${Process.myPid()}] Dump complete, status code: $result." + ) + result == 0 + } + DumpHandler(stream, future) + } + } + } +} + +/** + * Instance for handling remote memory dump. + * + * **Developer should invokes [InputStream.close] manually after dump process completes execution.** + * + * @property stream HPROF file input stream. + * @property result [Future] instance to check dump execution is done or not and dump result. + */ +class DumpHandler internal constructor( + val stream: InputStream, + val result: Future +) + +/* + Native Function Handlers. + */ + +private fun initialize(): Boolean { + System.loadLibrary("matrix-memorydump") + val success = initializeNative() + if (!success) { + MatrixLog.printErrStackTrace( + TAG, + RuntimeException("Failed to initialize native resources."), + "" + ) + } + return success +} + +/** + * Initialize native resources. + */ +private external fun initializeNative(): Boolean + +/** + * Dump HPROF file to specific file which file descriptor [fd] points to. The function returns 0 if + * dump successfully, or -1 if error happened. + * + * The function is implemented with art::hprof::DumpHeap() in libart.so. + */ +private external fun dumpHprof(fd: Int): Int + +/** + * Fork dump process. To solve the deadlock, this function will suspend the runtime and resume it in + * parent process. + * + * The function is implemented with native standard fork(). + * See [man fork](https://man7.org/linux/man-pages/man2/fork.2.html). + */ +private external fun fork(timeout: Long): Int + +/** + * Fork dump process with a pipe for transferring data. To solve the deadlock, this function will + * suspend the runtime and resume it in parent process. + * + * The code this function may returns: + * -1: Cannot fork child dump process. + * -2: Failed to allocate native resource in parent process. + * others: The return value is a pointer of integer pair in native. The integer pair is "forked dump + * process id - hprof-reading file descriptor". + * + * Reason for designing the return value: + * The runtime cannot allocate any object after invoking fork() in forked process. + * + * The function is implemented with native standard fork() and pipe(). + * See [man fork](https://man7.org/linux/man-pages/man2/fork.2.html) + * and [man pipe](https://man7.org/linux/man-pages/man2/pipe.2.html). + */ +private external fun forkPipe(timeout: Long): Long + +/** + * Wait dump process exits and return exit status of child process. + * + * The function is implemented with native standard waitpid(). + * See [man wait](https://man7.org/linux/man-pages/man2/wait.2.html). + */ +private external fun wait(pid: Int): Int + +/** + * Exit current process. + * + * The function is implemented with native standard _exit(). + * See [man _exit](https://man7.org/linux/man-pages/man2/exit.2.html). + */ +private external fun exit(code: Int) + +/** + * Get process id member value of native fork_pair instance by [pointer]. + * + * Reason for designing structure in native: + * The runtime cannot allocate any object after invoking fork() in forked process. + */ +private external fun pidFromForkPair(pointer: Long): Int + +/** + * Get file descriptor member value of native fork_pair instance by [pointer]. + * + * Reason for designing structure in native: + * The runtime cannot allocate any object after invoking fork() in forked process. + */ +private external fun fdFromForkPair(pointer: Long): Int + +/** + * Free the native memory space pointed to by [pointer]. + * + * The function is implemented with native standard free(). + * See [man free](https://man7.org/linux/man-pages/man3/free.3.html). + */ +private external fun free(pointer: Long) \ No newline at end of file diff --git a/matrix/matrix-android/matrix-memory-dump/src/test/java/com/tencent/matrix/memorydump/ExampleUnitTest.kt b/matrix/matrix-android/matrix-memory-dump/src/test/java/com/tencent/matrix/memorydump/ExampleUnitTest.kt new file mode 100644 index 000000000..c5ee6b369 --- /dev/null +++ b/matrix/matrix-android/matrix-memory-dump/src/test/java/com/tencent/matrix/memorydump/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.tencent.matrix.memorydump + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/build.gradle b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/build.gradle index 1e05894e2..ee46999a2 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/build.gradle +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/build.gradle @@ -27,6 +27,7 @@ dependencies { implementation "com.tencent.tinker:tinker-ziputils:1.9.2" implementation project(':matrix-android-lib') implementation project(':matrix-resource-canary:matrix-resource-canary-analyzer') + implementation project(':matrix-memory-dump') } version = rootProject.ext.VERSION_NAME 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 new file mode 100644 index 000000000..85f6e5c6e --- /dev/null +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkAnalyseProcessor.java @@ -0,0 +1,101 @@ +package com.tencent.matrix.resource.processor; + +import com.tencent.matrix.memorydump.MemoryDumpManager; +import com.tencent.matrix.resource.analyzer.model.ActivityLeakResult; +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.watcher.ActivityRefWatcher; +import com.tencent.matrix.util.MatrixLog; + +import java.io.File; + +/** + * HPROF file analysis processor using fork dump. + * + * @author aurorani + * @since 2021/10/25 + */ +public class ForkAnalyseProcessor extends BaseLeakProcessor { + + private static final String TAG = "Matrix.LeakProcessor.ForkAnalyse"; + + public ForkAnalyseProcessor(ActivityRefWatcher watcher) { + super(watcher); + } + + @Override + public boolean process(DestroyedActivityInfo destroyedActivityInfo) { + getWatcher().triggerGc(); + + if (dumpAndAnalyse( + destroyedActivityInfo.mActivityName, + destroyedActivityInfo.mKey + )) { + getWatcher().markPublished(destroyedActivityInfo.mActivityName, false); + return true; + } + + return false; + } + + private boolean dumpAndAnalyse(String activity, String key) { + + /* Dump */ + + final long dumpStart = System.currentTimeMillis(); + + final File hprof = getDumpStorageManager().newHprofFile(); + + if (hprof == null) { + MatrixLog.e(TAG, "cannot create hprof file"); + return false; + } + + if (!MemoryDumpManager.dumpBlock(hprof.getPath())) { + MatrixLog.e(TAG, String.format("heap dump for further analyzing activity with key [%s] was failed, just ignore.", + key)); + return false; + } + + MatrixLog.i(TAG, String.format("dump cost=%sms refString=%s path=%s", + System.currentTimeMillis() - dumpStart, key, hprof.getPath())); + + /* Analyse */ + + try { + final long analyseStart = System.currentTimeMillis(); + + final ActivityLeakResult leaks = analyze(hprof, key); + MatrixLog.i(TAG, String.format("analyze cost=%sms refString=%s", + System.currentTimeMillis() - analyseStart, key)); + + if (leaks.mLeakFound) { + final String leakChain = leaks.toString(); + publishIssue( + SharePluginInfo.IssueType.LEAK_FOUND, + ResourceConfig.DumpMode.FORK_ANALYSE, + activity, key, leakChain, + String.valueOf(System.currentTimeMillis() - dumpStart)); + MatrixLog.i(TAG, leakChain); + } else { + MatrixLog.i(TAG, "leak not found"); + } + + } catch (OutOfMemoryError error) { + publishIssue( + SharePluginInfo.IssueType.ERR_ANALYSE_OOM, + ResourceConfig.DumpMode.FORK_ANALYSE, + activity, key, "OutOfMemoryError", + "0"); + MatrixLog.printErrStackTrace(TAG, error.getCause(), ""); + } finally { + //noinspection ResultOfMethodCallIgnored + hprof.delete(); + } + + /* Done */ + + return true; + } +} 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 new file mode 100644 index 000000000..1d2f1a929 --- /dev/null +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ForkDumpProcessor.java @@ -0,0 +1,53 @@ +package com.tencent.matrix.resource.processor; + +import com.tencent.matrix.memorydump.MemoryDumpManager; +import com.tencent.matrix.resource.analyzer.model.DestroyedActivityInfo; +import com.tencent.matrix.resource.analyzer.model.HeapDump; +import com.tencent.matrix.resource.watcher.ActivityRefWatcher; +import com.tencent.matrix.util.MatrixLog; + +import java.io.File; + +/** + * HPROF file dump processor using fork dump. + * + * @author aurorani + * @since 2021/10/25 + */ +public class ForkDumpProcessor extends BaseLeakProcessor { + + private static final String TAG = "Matrix.LeakProcessor.ForkDump"; + + public ForkDumpProcessor(ActivityRefWatcher watcher) { + super(watcher); + } + + @Override + public boolean process(DestroyedActivityInfo destroyedActivityInfo) { + final long dumpStart = System.currentTimeMillis(); + + final File hprof = getDumpStorageManager().newHprofFile(); + + if (hprof == null) { + MatrixLog.e(TAG, "cannot create hprof file, just ignore"); + return true; + } + + if (!MemoryDumpManager.dumpBlock(hprof.getPath())) { + MatrixLog.e(TAG, String.format("heap dump for further analyzing activity with key [%s] was failed, just ignore.", + destroyedActivityInfo.mKey)); + return true; + } + + MatrixLog.i(TAG, String.format("dump cost=%sms refString=%s path=%s", + System.currentTimeMillis() - dumpStart, destroyedActivityInfo.mKey, hprof.getPath())); + + getWatcher().markPublished(destroyedActivityInfo.mActivityName); + getWatcher().triggerGc(); + + getHeapDumpHandler().process( + new HeapDump(hprof, destroyedActivityInfo.mKey, destroyedActivityInfo.mActivityName)); + + return true; + } +} 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 0d844361b..570ebf5cf 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 @@ -27,6 +27,8 @@ import com.tencent.matrix.resource.config.ResourceConfig; import com.tencent.matrix.resource.processor.AutoDumpProcessor; import com.tencent.matrix.resource.processor.BaseLeakProcessor; +import com.tencent.matrix.resource.processor.ForkAnalyseProcessor; +import com.tencent.matrix.resource.processor.ForkDumpProcessor; import com.tencent.matrix.resource.processor.ManualDumpProcessor; import com.tencent.matrix.resource.processor.NoDumpProcessor; import com.tencent.matrix.resource.processor.SilenceAnalyseProcessor; @@ -49,20 +51,20 @@ public class ActivityRefWatcher extends FilePublisher implements Watcher { private static final String TAG = "Matrix.ActivityRefWatcher"; - private static final int CREATED_ACTIVITY_COUNT_THRESHOLD = 1; - private static final long FILE_CONFIG_EXPIRED_TIME_MILLIS = TimeUnit.DAYS.toMillis(1); + private static final int CREATED_ACTIVITY_COUNT_THRESHOLD = 1; + private static final long FILE_CONFIG_EXPIRED_TIME_MILLIS = TimeUnit.DAYS.toMillis(1); private static final String ACTIVITY_REFKEY_PREFIX = "MATRIX_RESCANARY_REFKEY_"; private final ResourcePlugin mResourcePlugin; - private final RetryableTaskExecutor mDetectExecutor; - private final int mMaxRedetectTimes; - private final long mBgScanTimes; - private final long mFgScanTimes; + private final RetryableTaskExecutor mDetectExecutor; + private final int mMaxRedetectTimes; + private final long mBgScanTimes; + private final long mFgScanTimes; - private final HandlerThread mHandlerThread; - private final Handler mHandler; + private final HandlerThread mHandlerThread; + private final Handler mHandler; private final ConcurrentLinkedQueue mDestroyedActivityInfos; @@ -93,6 +95,10 @@ private BaseLeakProcessor createLeakProcess(ResourceConfig.DumpMode dumpMode, Ac return new ManualDumpProcessor(watcher, watcher.getResourcePlugin().getConfig().getTargetActivity()); case SILENCE_ANALYSE: return new SilenceAnalyseProcessor(watcher); + case FORK_DUMP: + return new ForkDumpProcessor(watcher); + case FORK_ANALYSE: + return new ForkAnalyseProcessor(watcher); case NO_DUMP: default: return new NoDumpProcessor(watcher); diff --git a/matrix/matrix-android/settings.gradle b/matrix/matrix-android/settings.gradle index a909259dd..72347c834 100644 --- a/matrix/matrix-android/settings.gradle +++ b/matrix/matrix-android/settings.gradle @@ -18,6 +18,7 @@ include ':matrix-sqlite-lint:matrix-sqlite-lint-android-sdk' include ':matrix-battery-canary' include ':matrix-arscutil' include ':matrix-opengl-leak' +include ':matrix-memory-dump' // Components for memory hook include ':matrix-backtrace' From e64416b42ed87640f20d1150c85b68697b2271f3 Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 12 Nov 2021 14:50:35 +0800 Subject: [PATCH 020/163] The Birth of Matrix Traffic --- .../matrix-traffic/CMakeLists.txt | 31 +++ .../matrix-traffic/build.gradle | 87 ++++++++ .../matrix-traffic/consumer-rules.pro | 0 .../matrix-traffic/gradle.properties | 2 + .../matrix-traffic/proguard-rules.pro | 21 ++ .../src/main/AndroidManifest.xml | 5 + .../src/main/cpp/MatrixTraffic.cc | 195 +++++++++++++++++ .../src/main/cpp/MatrixTraffic.h | 24 ++ .../src/main/cpp/TrafficCollector.cc | 205 ++++++++++++++++++ .../src/main/cpp/TrafficCollector.h | 86 ++++++++ .../src/main/cpp/util/Logging.h | 80 +++++++ .../src/main/cpp/util/blocking_queue.h | 70 ++++++ .../src/main/cpp/util/managed_jnienv.cc | 62 ++++++ .../src/main/cpp/util/managed_jnienv.h | 35 +++ .../tencent/matrix/traffic/TrafficConfig.java | 28 +++ .../tencent/matrix/traffic/TrafficPlugin.java | 66 ++++++ matrix/matrix-android/settings.gradle | 1 + 17 files changed, 998 insertions(+) create mode 100644 matrix/matrix-android/matrix-traffic/CMakeLists.txt create mode 100644 matrix/matrix-android/matrix-traffic/build.gradle create mode 100644 matrix/matrix-android/matrix-traffic/consumer-rules.pro create mode 100644 matrix/matrix-android/matrix-traffic/gradle.properties create mode 100644 matrix/matrix-android/matrix-traffic/proguard-rules.pro create mode 100644 matrix/matrix-android/matrix-traffic/src/main/AndroidManifest.xml create mode 100644 matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc create mode 100644 matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h create mode 100644 matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc create mode 100644 matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h create mode 100644 matrix/matrix-android/matrix-traffic/src/main/cpp/util/Logging.h create mode 100644 matrix/matrix-android/matrix-traffic/src/main/cpp/util/blocking_queue.h create mode 100644 matrix/matrix-android/matrix-traffic/src/main/cpp/util/managed_jnienv.cc create mode 100644 matrix/matrix-android/matrix-traffic/src/main/cpp/util/managed_jnienv.h create mode 100644 matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java create mode 100644 matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java diff --git a/matrix/matrix-android/matrix-traffic/CMakeLists.txt b/matrix/matrix-android/matrix-traffic/CMakeLists.txt new file mode 100644 index 000000000..c26b4ca79 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.4.1) + +project(MatrixTraffic) + +include_directories(src/main/cpp) + +add_library(matrix-traffic + SHARED + src/main/cpp/MatrixTraffic.cc + src/main/cpp/TrafficCollector.cc + src/main/cpp/util/blocking_queue.h + src/main/cpp/util/managed_jnienv.cc + ) + +TARGET_INCLUDE_DIRECTORIES(matrix-traffic PRIVATE ${EXT_DEP}/include) + + +find_library( log-lib + log ) + + +target_link_libraries(matrix-traffic + PRIVATE ${log-lib} + PRIVATE ${EXT_DEP}/lib/${ANDROID_ABI}/libxhook.a + ) + +set_target_properties(matrix-traffic PROPERTIES + CXX_STANDARD_REQUIRED ON + CXX_STANDARD 17 + CXX_EXTENSIONS OFF + ) \ No newline at end of file diff --git a/matrix/matrix-android/matrix-traffic/build.gradle b/matrix/matrix-android/matrix-traffic/build.gradle new file mode 100644 index 000000000..d7bc40620 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/build.gradle @@ -0,0 +1,87 @@ +apply plugin: 'com.android.library' + +apply from: rootProject.file('gradle/WeChatNativeDepend.gradle') + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion +// publishNonDefault true + defaultConfig { + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName rootProject.ext.VERSION_NAME + + externalNativeBuild { + cmake { + cppFlags "-std=gnu++11 -frtti -fexceptions" + } + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } + } + + } +// buildTypes { +// release { +// minifyEnabled false +// consumerProguardFiles 'proguard-rules.pro' +// } +// } +// +// externalNativeBuild { +// cmake { +// path "CMakeLists.txt" +// } +// } +// + + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + java { + srcDir "src/main/java" + } + } + } + + buildTypes { + release { + minifyEnabled false + consumerProguardFiles 'proguard-rules.pro' + } + } + + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + androidTestImplementation 'androidx.annotation:annotation:1.0.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + + testImplementation 'junit:junit:4.12' + implementation project(':matrix-android-lib') + implementation project(':matrix-android-commons') +} + +version = rootProject.ext.VERSION_NAME +group = rootProject.ext.GROUP + +if (rootProject.file('gradle/WeChatPublish.gradle').exists()) { + if("External" == rootProject.ext.PUBLISH_CHANNEL) { + apply from: rootProject.file('gradle/android-publish.gradle') + } + else { + apply from: rootProject.file('gradle/WeChatPublish.gradle') + wechatPublish { + artifactId = POM_ARTIFACT_ID + } + } +} diff --git a/matrix/matrix-android/matrix-traffic/consumer-rules.pro b/matrix/matrix-android/matrix-traffic/consumer-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/matrix/matrix-android/matrix-traffic/gradle.properties b/matrix/matrix-android/matrix-traffic/gradle.properties new file mode 100644 index 000000000..2e2d56881 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/gradle.properties @@ -0,0 +1,2 @@ +POM_NAME=Matrix Traffic Detector for Android +POM_ARTIFACT_ID=matrix-traffic \ No newline at end of file diff --git a/matrix/matrix-android/matrix-traffic/proguard-rules.pro b/matrix/matrix-android/matrix-traffic/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/matrix/matrix-android/matrix-traffic/src/main/AndroidManifest.xml b/matrix/matrix-android/matrix-traffic/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a71349401 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc new file mode 100644 index 000000000..760a5ee52 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -0,0 +1,195 @@ +/* + * 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. + */ + +// Author: leafjia@tencent.com +// +// MatrixTraffic.cc + +#include "MatrixTraffic.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define HOOK_REQUEST_GROUPID_TRAFFIC 0x06 + +using namespace MatrixTraffic; +static bool HOOKED = false; + +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) { + TrafficCollector::enQueueRx(MSG_TYPE_READ, fd, count); + return original_read(fd, buf, count); +} + + +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) { + TrafficCollector::enQueueRx(MSG_TYPE_RECV, sockfd, len); + return original_recv(sockfd, buf, len, flags); +} + +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, + struct sockaddr *src_addr, socklen_t *addrlen) { + TrafficCollector::enQueueRx(MSG_TYPE_RECVFROM, sockfd, len); + return original_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); +} + + +ssize_t (*original_recvmsg)(int sockfd, struct msghdr *msg, int flags); +ssize_t my_recvmsg(int sockfd, struct msghdr *msg, int flags) { + TrafficCollector::enQueueRx(MSG_TYPE_RECVMSG, sockfd, msg->msg_iovlen); + return original_recvmsg(sockfd, msg, flags); +} + + +ssize_t (*original_write)(int fd, const void *buf, size_t count); +ssize_t my_write(int fd, const void *buf, size_t count) { + TrafficCollector::enQueueTx(MSG_TYPE_WRITE, fd, count); + return original_write(fd, buf, count); +} + +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) { + TrafficCollector::enQueueTx(MSG_TYPE_SEND, sockfd, len); + return original_send(sockfd, buf, len, flags); +} + +ssize_t (*original_sendto)(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); +ssize_t my_sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) { + TrafficCollector::enQueueTx(MSG_TYPE_SENDTO, sockfd, len); + return original_sendto(sockfd, buf, len, flags, dest_addr, addrlen); +} + +ssize_t (*original_sendmsg)(int sockfd, const struct msghdr *msg, int flags); +ssize_t my_sendmsg(int sockfd, const struct msghdr *msg, int flags) { + TrafficCollector::enQueueTx(MSG_TYPE_SENDMSG, sockfd, msg->msg_iovlen); + return original_sendmsg(sockfd, msg, flags); +} + +static jobject nativeGetTrafficInfoMap(JNIEnv *env, jclass, jint type) { + return TrafficCollector::getTrafficInfoMap(type); +} + + +static void nativeReleaseMatrixTraffic(JNIEnv *env, jclass) { + TrafficCollector::stopLoop(); + TrafficCollector::clearTrafficInfo(); +} + + +static void nativeClearTrafficInfo(JNIEnv *env, jclass) { + TrafficCollector::clearTrafficInfo(); +} + +static void hookSocket(bool rxHook, bool txHook) { + if (HOOKED) { + return; + } + + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "connect", + (void *) my_connect, (void **) (&original_connect)); + + if (rxHook) { + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.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", + (void *) my_recvfrom, (void **) (&original_recvfrom)); + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "recvmsg", + (void *) my_recvmsg, (void **) (&original_recvmsg)); + } + + if (txHook) { + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.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", + (void *) my_sendto, (void **) (&original_sendto)); + xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "sendmsg", + (void *) my_sendmsg, (void **) (&original_sendmsg)); + } + + 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, ".*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); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libnetd_client\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libhardcoder\\.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, ".*libtraffic-collector\\.so$", nullptr); + + xhook_refresh(true); + HOOKED = true; +} + +static void nativeInitMatrixTraffic(JNIEnv *env, jclass, jboolean rxEnable, jboolean txEnable) { + TrafficCollector::startLoop(); + hookSocket(rxEnable == JNI_TRUE, txEnable == JNI_TRUE); +} + +template +static inline constexpr std::size_t NELEM(const T(&)[sz]) { return sz; } + +static const JNINativeMethod TRAFFIC_METHODS[] = { + {"nativeInitMatrixTraffic", "(ZZ)V", (void *) nativeInitMatrixTraffic}, + {"nativeGetTrafficInfoMap", "(I)Ljava/util/HashMap;", (void *) nativeGetTrafficInfoMap}, + {"nativeClearTrafficInfo", "()V", (void *) nativeClearTrafficInfo}, + {"nativeReleaseMatrixTraffic", "()V", (void *) nativeReleaseMatrixTraffic}, +}; + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + JniInvocation::init(vm); + JNIEnv *env; + + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) + return -1; + + jclass trafficCollectorCls = env->FindClass("com/tencent/matrix/traffic/TrafficPlugin"); + if (!trafficCollectorCls) + return -1; + + if (env->RegisterNatives( + trafficCollectorCls, TRAFFIC_METHODS, static_cast(NELEM(TRAFFIC_METHODS))) != 0) + return -1; + + env->DeleteLocalRef(trafficCollectorCls); + return JNI_VERSION_1_6; +} // namespace MatrixTraffic diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h new file mode 100644 index 000000000..71634bda2 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h @@ -0,0 +1,24 @@ +/* + * 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. + */ + +// Author: leafjia@tencent.com +// +// MatrixTraffic.h + +#ifndef MATRIX_ANDROID_MATRIXTRAFFIC_H +#define MATRIX_ANDROID_MATRIXTRAFFIC_H + +#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 new file mode 100644 index 000000000..e3e506a83 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc @@ -0,0 +1,205 @@ +/* + * 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. + */ + +// Author: leafjia@tencent.com +// +// TrafficCollector.cc + +#include "TrafficCollector.h" + +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; + +namespace MatrixTraffic { + +static mutex queueMutex; +static lock_guard lock(queueMutex); +static bool loopRunning = false; +static map fdFamilyMap; +static blocking_queue> msgQueue; +static map rxTrafficInfoMap; +static map txTrafficInfoMap; +static mutex rxTrafficInfoMapLock; +static mutex txTrafficInfoMapLock; + +static map fdThreadNameMap; +static mutex fdThreadNameMapLock; + +string getThreadName(int fd) { + fdThreadNameMapLock.lock(); + if (fdThreadNameMap.count(fd) == 0) { + auto threadName = new char[15]; + prctl(PR_GET_NAME, threadName); + fdThreadNameMap[fd] = threadName; + fdThreadNameMapLock.unlock(); + return threadName; + } else { + auto threadName = fdThreadNameMap[fd]; + fdThreadNameMapLock.unlock(); + return threadName; + } +} + +void TrafficCollector::enQueueConnect(int fd, sockaddr *addr, socklen_t addr_length) { + if (!loopRunning) { + return; + } + shared_ptr msg = make_shared(MSG_TYPE_CONNECT, fd, addr->sa_family, getThreadName(fd), 0); + msgQueue.push(msg); + queueMutex.unlock(); +} + +void enQueueMsg(int type, int fd, size_t len) { + if (!loopRunning) { + return; + } + shared_ptr msg = make_shared(type, fd, 0, getThreadName(fd), len); + msgQueue.push(msg); + queueMutex.unlock(); +} + +void TrafficCollector::enQueueTx(int type, int fd, size_t len) { + if (!loopRunning) { + return; + } + enQueueMsg(type, fd, len); +} + +void TrafficCollector::enQueueRx(int type, int fd, size_t len) { + if (!loopRunning) { + return; + } + enQueueMsg(type, fd, len); +} + +void appendRxTraffic(const string& threadName, long len) { + rxTrafficInfoMapLock.lock(); + rxTrafficInfoMap[threadName] += len; + rxTrafficInfoMapLock.unlock(); +} + +void appendTxTraffic(const string& threadName, long len) { + txTrafficInfoMapLock.lock(); + txTrafficInfoMap[threadName] += 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); + } + } else if (msg->type >= MSG_TYPE_RECV && msg->type <= MSG_TYPE_RECVMSG) { + if (fdFamilyMap[msg->fd] != AF_LOCAL) { + appendRxTraffic(msg->threadName, msg->len); + } + } else if (msg->type == MSG_TYPE_WRITE) { + if (fdFamilyMap.count(msg->fd) > 0) { + appendTxTraffic(msg->threadName, 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); + } + } + msgQueue.pop(); + } + } +} + + +void TrafficCollector::startLoop() { + loopRunning = true; + thread loopThread(loop); + loopThread.detach(); +} + +void TrafficCollector::stopLoop() { + loopRunning = false; +} + +jobject TrafficCollector::getTrafficInfoMap(int type) { + JNIEnv *env = JniInvocation::getEnv(); + jclass mapClass = env->FindClass("java/util/HashMap"); + if(mapClass == nullptr) { + return nullptr; + } + jmethodID mapInit = env->GetMethodID(mapClass, "", "()V"); + jobject jHashMap = env->NewObject(mapClass, mapInit); + jmethodID mapPut = env->GetMethodID(mapClass, "put", + "(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()); + jstring traffic = env->NewStringUTF(to_string(it.second).c_str()); + env->CallObjectMethod(jHashMap, mapPut, threadName, traffic); + env->DeleteLocalRef(threadName); + env->DeleteLocalRef(traffic); + } + rxTrafficInfoMapLock.unlock(); + } else if (type == TYPE_GET_TRAFFIC_TX) { + txTrafficInfoMapLock.lock(); + for (auto & it : txTrafficInfoMap) { + jstring threadName = env->NewStringUTF(it.first.c_str()); + jstring traffic = env->NewStringUTF(to_string(it.second).c_str()); + env->CallObjectMethod(jHashMap, mapPut, threadName, traffic); + env->DeleteLocalRef(threadName); + env->DeleteLocalRef(traffic); + } + txTrafficInfoMapLock.unlock(); + } + env->DeleteLocalRef(mapClass); + return jHashMap; +} + +void TrafficCollector::clearTrafficInfo() { + rxTrafficInfoMapLock.lock(); + rxTrafficInfoMap.clear(); + rxTrafficInfoMapLock.unlock(); + + txTrafficInfoMapLock.lock(); + txTrafficInfoMap.clear(); + txTrafficInfoMapLock.unlock(); + + fdThreadNameMapLock.lock(); + fdThreadNameMap.clear(); + fdThreadNameMapLock.unlock(); +} + +TrafficCollector::~TrafficCollector() { + stopLoop(); + clearTrafficInfo(); +} + +}// namespace MatrixTraffic + diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h new file mode 100644 index 000000000..e46e98e2c --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h @@ -0,0 +1,86 @@ +/* + * 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. + */ + +// Author: leafjia@tencent.com +// +// TrafficCollector.h + + +#ifndef MATRIX_ANDROID_TRAFFICCOLLECTOR_H +#define MATRIX_ANDROID_TRAFFICCOLLECTOR_H + +#include +#include "util/Logging.h" +#include + +#include +#include +#include +#include + +#define MSG_TYPE_CONNECT 1 + +#define MSG_TYPE_READ 10 +#define MSG_TYPE_RECV 11 +#define MSG_TYPE_RECVFROM 12 +#define MSG_TYPE_RECVMSG 13 + +#define MSG_TYPE_WRITE 20 +#define MSG_TYPE_SEND 21 +#define MSG_TYPE_SENDTO 22 +#define MSG_TYPE_SENDMSG 23 + + +#define TYPE_GET_TRAFFIC_RX 0 +#define TYPE_GET_TRAFFIC_TX 1 + +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) { + } + int type; + int fd; + sa_family_t sa_family; + string threadName; + long len; +}; + +class TrafficCollector { + +public : + static void startLoop(); + + static void stopLoop(); + + static void enQueueConnect(int fd, sockaddr *addr, socklen_t __addr_length); + + static void enQueueTx(int type, int fd, size_t len); + + static void enQueueRx(int type, int fd, size_t len); + + static void clearTrafficInfo(); + + static jobject getTrafficInfoMap(int type); + + virtual ~TrafficCollector(); +}; +}// namespace MatrixTraffic + +#endif //MATRIX_ANDROID_TRAFFICCOLLECTOR_H diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/util/Logging.h b/matrix/matrix-android/matrix-traffic/src/main/cpp/util/Logging.h new file mode 100644 index 000000000..17e04aa7f --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/util/Logging.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +// Author: leafjia@tencent.com +// +// logging.h + +#ifndef LAGDETECTOR_LAG_DETECTOR_MAIN_CPP_LOGGING_H_ +#define LAGDETECTOR_LAG_DETECTOR_MAIN_CPP_LOGGING_H_ + +#ifdef __ANDROID__ +#include +#endif + +#ifdef ALOGV +#undef ALOGV +#endif + +namespace MatrixTraffic { +namespace Logging { + +static constexpr const char *kLogTag = "MatrixTraffic"; + +#if defined(__GNUC__) +__attribute__((__format__(printf, 1, 2))) +#endif +static inline void ALOGV(const char *fmt, ...) { +#ifdef __ANDROID__ + va_list ap; + va_start(ap, fmt); + __android_log_vprint(ANDROID_LOG_VERBOSE, kLogTag, fmt, ap); + va_end(ap); +#endif +} + +#if defined(__GNUC__) +__attribute__((__format__(printf, 1, 2))) +#endif +static inline void ALOGI(const char *fmt, ...) { +#ifdef __ANDROID__ + va_list ap; + va_start(ap, fmt); + __android_log_vprint(ANDROID_LOG_INFO, kLogTag, fmt, ap); + va_end(ap); +#endif +} + +#if defined(__GNUC__) +__attribute__((__format__(printf, 1, 2))) +#endif +static inline void ALOGE(const char *fmt, ...) { +#ifdef __ANDROID__ + va_list ap; + va_start(ap, fmt); + __android_log_vprint(ANDROID_LOG_ERROR, kLogTag, fmt, ap); + va_end(ap); +#endif +} + +} // namespace Logging +} // namespace MatrixTraffic + +using ::MatrixTraffic::Logging::ALOGV; +using ::MatrixTraffic::Logging::ALOGI; +using ::MatrixTraffic::Logging::ALOGE; + +#endif // MATRIX_TRAFFIC_MAIN_CPP_LOGGING_H_ diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/util/blocking_queue.h b/matrix/matrix-android/matrix-traffic/src/main/cpp/util/blocking_queue.h new file mode 100644 index 000000000..10480b904 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/util/blocking_queue.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +// Author: leafjia@tencent.com +// +// blocking_queue.h + +#ifndef MATRIX_ANDROID_BLOCKING_QUEUE_H +#define MATRIX_ANDROID_BLOCKING_QUEUE_H +#include +#include + +using namespace std; + +template +class blocking_queue { +private: + deque coreQueue; + mutex queueGuard; + +public: + void push(T msg) { + queueGuard.lock(); + coreQueue.push_back(msg); + queueGuard.unlock(); + } + void pop() { + queueGuard.lock(); + this->coreQueue.pop_front(); + queueGuard.unlock(); + } + T front() { + queueGuard.lock(); + T msg = coreQueue.front(); + queueGuard.unlock(); + return msg; + } + bool empty() { + return coreQueue.empty(); + } + int size() { + return coreQueue.size(); + } + void shrink_to_fit() { + queueGuard.lock(); + coreQueue.shrink_to_fit(); + queueGuard.unlock(); + } + void clear() { + queueGuard.lock(); + coreQueue.clear(); + queueGuard.unlock(); + } +}; + + +#endif //MATRIX_ANDROID_BLOCKING_QUEUE_H diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/util/managed_jnienv.cc b/matrix/matrix-android/matrix-traffic/src/main/cpp/util/managed_jnienv.cc new file mode 100644 index 000000000..0d838a700 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/util/managed_jnienv.cc @@ -0,0 +1,62 @@ +/* + * 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. + */ + +// Author: leafjia@tencent.com +// +// managed_jnienv.cc + +#include "managed_jnienv.h" + +#include + +#include + +namespace JniInvocation { + + static JavaVM *g_VM = nullptr; + static pthread_once_t g_onceInitTls = PTHREAD_ONCE_INIT; + static pthread_key_t g_tlsJavaEnv; + + void init(JavaVM *vm) { + if (g_VM) return; + g_VM = vm; + } + + JavaVM *getJavaVM() { + return g_VM; + } + + JNIEnv *getEnv() { + JNIEnv *env; + int ret = g_VM->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + if (ret != JNI_OK) { + pthread_once(&g_onceInitTls, []() { + pthread_key_create(&g_tlsJavaEnv, [](void *d) { + if (d && g_VM) + g_VM->DetachCurrentThread(); + }); + }); + + if (g_VM->AttachCurrentThread(&env, nullptr) == JNI_OK) { + pthread_setspecific(g_tlsJavaEnv, reinterpret_cast(1)); + } else { + env = nullptr; + } + } + return env; + } + +} // namespace JniInvocation diff --git a/matrix/matrix-android/matrix-traffic/src/main/cpp/util/managed_jnienv.h b/matrix/matrix-android/matrix-traffic/src/main/cpp/util/managed_jnienv.h new file mode 100644 index 000000000..a9266af9c --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/util/managed_jnienv.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +// Author: leafjia@tencent.com +// +// managed_jnienv.h + +#ifndef LAGDETECTOR_LAG_DETECTOR_MAIN_CPP_NATIVEHELPER_MANAGED_JNIENV_H_ +#define LAGDETECTOR_LAG_DETECTOR_MAIN_CPP_NATIVEHELPER_MANAGED_JNIENV_H_ + +#include + +namespace JniInvocation { + + void init(JavaVM *vm); + JavaVM *getJavaVM(); + JNIEnv *getEnv(); + +} + +#endif // LAGDETECTOR_LAG_DETECTOR_MAIN_CPP_NATIVEHELPER_MANAGED_JNIENV_H_ + 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 new file mode 100644 index 000000000..68b012ba2 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficConfig.java @@ -0,0 +1,28 @@ +package com.tencent.matrix.traffic; + +public class TrafficConfig { + private boolean rxCollectorEnable; + private boolean txCollectorEnable; + + public TrafficConfig() { + + } + public TrafficConfig(boolean rxCollectorEnable, boolean txCollectorEnable) { + this.rxCollectorEnable = rxCollectorEnable; + this.txCollectorEnable = txCollectorEnable; + } + + public boolean isRxCollectorEnable() { + return rxCollectorEnable; + } + public void setRxCollectorEnable(boolean rxCollectorEnable) { + this.rxCollectorEnable = rxCollectorEnable; + } + + public boolean isTxCollectorEnable() { + return txCollectorEnable; + } + public void setTxCollectorEnable(boolean txCollectorEnable) { + this.txCollectorEnable = txCollectorEnable; + } +} 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 new file mode 100644 index 000000000..bbfb7d939 --- /dev/null +++ b/matrix/matrix-android/matrix-traffic/src/main/java/com/tencent/matrix/traffic/TrafficPlugin.java @@ -0,0 +1,66 @@ +package com.tencent.matrix.traffic; + +import com.tencent.matrix.plugin.Plugin; + +import java.util.HashMap; + +public class TrafficPlugin extends Plugin { + + final private TrafficConfig trafficConfig; + public static final int TYPE_GET_TRAFFIC_RX = 0; + public static final int TYPE_GET_TRAFFIC_TX = 1; + + //TODO will be done in next upgrade + //public static final int TYPE_GET_TRAFFIC_ALL = 2; + + static { + System.loadLibrary("matrix-traffic"); + } + + public TrafficPlugin(TrafficConfig trafficConfig) { + this.trafficConfig = trafficConfig; + } + + @Override + public void start() { + if (isPluginStarted()) { + return; + } + super.start(); + nativeInitMatrixTraffic(trafficConfig.isRxCollectorEnable(), trafficConfig.isTxCollectorEnable()); + } + + + @Override + public void stop() { + if (isPluginStopped()) { + return; + } + super.stop(); + nativeReleaseMatrixTraffic(); + } + + + public HashMap getTrafficInfoMap(int type) { + return nativeGetTrafficInfoMap(type); + } + public void clearTrafficInfo() { + nativeClearTrafficInfo(); + } + + private static native void nativeInitMatrixTraffic(boolean rxEnable, boolean txEnable); + private static native String nativeGetTrafficInfo(); + private static native String nativeGetAllStackTraceTrafficInfo(); + private static native void nativeReleaseMatrixTraffic(); + private static native void nativeEnableDumpJavaStackTrace(boolean enable); + private static native void nativeClearTrafficInfo(); + private static native HashMap nativeGetTrafficInfoMap(int type); + + public static String getJavaStackTrace() { + StringBuilder stackTrace = new StringBuilder(); + for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) { + stackTrace.append(stackTraceElement.toString()).append("\n"); + } + return stackTrace.toString(); + } +} diff --git a/matrix/matrix-android/settings.gradle b/matrix/matrix-android/settings.gradle index 72347c834..538106684 100644 --- a/matrix/matrix-android/settings.gradle +++ b/matrix/matrix-android/settings.gradle @@ -19,6 +19,7 @@ include ':matrix-battery-canary' include ':matrix-arscutil' include ':matrix-opengl-leak' include ':matrix-memory-dump' +include ':matrix-traffic' // Components for memory hook include ':matrix-backtrace' From 6c648b24ff8d0922f9f799652209368bd05112ca Mon Sep 17 00:00:00 2001 From: yvesluo Date: Fri, 12 Nov 2021 15:10:05 +0800 Subject: [PATCH 021/163] refactor: move enhanceDlsym from jectl to android-common --- .../matrix-android-commons/CMakeLists.txt | 1 + .../matrix-android-commons/build.gradle | 5 ++++- .../main/cpp/libenhance_dlsym/CMakeLists.txt | 19 +++++++++++++++++++ .../cpp/libenhance_dlsym}/EnhanceDlsym.cpp | 2 +- .../main/cpp/libenhance_dlsym}/EnhanceDlsym.h | 0 .../matrix-jectl/CMakeLists.txt | 11 +++++++++-- .../matrix-android/matrix-jectl/build.gradle | 4 +++- 7 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/CMakeLists.txt rename matrix/matrix-android/{matrix-jectl/src/main/cpp/jectl => matrix-android-commons/src/main/cpp/libenhance_dlsym}/EnhanceDlsym.cpp (99%) rename matrix/matrix-android/{matrix-jectl/src/main/cpp/jectl => matrix-android-commons/src/main/cpp/libenhance_dlsym}/EnhanceDlsym.h (100%) diff --git a/matrix/matrix-android/matrix-android-commons/CMakeLists.txt b/matrix/matrix-android/matrix-android-commons/CMakeLists.txt index 2096bfb6b..a9b8c0b65 100644 --- a/matrix/matrix-android/matrix-android-commons/CMakeLists.txt +++ b/matrix/matrix-android/matrix-android-commons/CMakeLists.txt @@ -2,4 +2,5 @@ cmake_minimum_required(VERSION 3.4.1) project(android-commons C) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/libsemi_dlfcn) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/libenhance_dlsym) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/libxhook) \ No newline at end of file diff --git a/matrix/matrix-android/matrix-android-commons/build.gradle b/matrix/matrix-android/matrix-android-commons/build.gradle index 52be820aa..62aef0853 100644 --- a/matrix/matrix-android/matrix-android-commons/build.gradle +++ b/matrix/matrix-android/matrix-android-commons/build.gradle @@ -18,7 +18,7 @@ android { externalNativeBuild { cmake { - targets = ['xhook', 'semi_dlfcn'] + targets = ['xhook', 'semi_dlfcn', 'enhance_dlsym'] } exportHeaders { from('src/main/cpp/libxhook') { @@ -27,6 +27,9 @@ android { from('src/main/cpp/libsemi_dlfcn') { include '**/*.h' } + from('src/main/cpp/libenhance_dlsym') { + include '**/*.h' + } } } } diff --git a/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/CMakeLists.txt b/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/CMakeLists.txt new file mode 100644 index 000000000..52b7c5b46 --- /dev/null +++ b/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.4.1) +project(libenhance_dlsym CXX) + +set(enhance_dlsym_source_dir ${CMAKE_CURRENT_SOURCE_DIR}) + +set(enhance_dlsym_source + ${enhance_dlsym_source_dir}/EnhanceDlsym.cpp) + +add_library(enhance_dlsym STATIC ${enhance_dlsym_source}) + +target_include_directories( + enhance_dlsym + PUBLIC ${enhance_dlsym_source_dir} +) + +target_link_libraries( + enhance_dlsym + PUBLIC ${log-lib} +) \ No newline at end of file diff --git a/matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/EnhanceDlsym.cpp b/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/EnhanceDlsym.cpp similarity index 99% rename from matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/EnhanceDlsym.cpp rename to matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/EnhanceDlsym.cpp index 912995f02..6be54536d 100644 --- a/matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/EnhanceDlsym.cpp +++ b/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/EnhanceDlsym.cpp @@ -32,7 +32,7 @@ #include #include #include "EnhanceDlsym.h" -#include "JeLog.h" +#include "../../../../../matrix-jectl/src/main/cpp/jectl/JeLog.h" #define TAG "Matrix.EnhanceDl" diff --git a/matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/EnhanceDlsym.h b/matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/EnhanceDlsym.h similarity index 100% rename from matrix/matrix-android/matrix-jectl/src/main/cpp/jectl/EnhanceDlsym.h rename to matrix/matrix-android/matrix-android-commons/src/main/cpp/libenhance_dlsym/EnhanceDlsym.h diff --git a/matrix/matrix-android/matrix-jectl/CMakeLists.txt b/matrix/matrix-android/matrix-jectl/CMakeLists.txt index 44560092b..931537f6f 100644 --- a/matrix/matrix-android/matrix-jectl/CMakeLists.txt +++ b/matrix/matrix-android/matrix-jectl/CMakeLists.txt @@ -17,7 +17,6 @@ set(SOURCE_DIR src/main/cpp) set( SOURCE_FILES ${SOURCE_DIR}/jectl/JeCtl.cpp - ${SOURCE_DIR}/jectl/EnhanceDlsym.cpp ${SOURCE_DIR}/jectl/JeHooks.cpp ) @@ -53,7 +52,15 @@ target_link_libraries( # Specifies the target library. ${TARGET} # Links the target library to the log library # included in the NDK. - ${log-lib}) + PUBLIC ${log-lib} + PRIVATE -Wl,--whole-archive ${EXT_DEP}/lib/${ANDROID_ABI}/libenhance_dlsym.a -Wl,--no-whole-archive + ) + +target_include_directories( + ${TARGET} + PUBLIC ${SOURCE_DIR} + PUBLIC ${EXT_DEP}/include +) TARGET_COMPILE_OPTIONS( ${TARGET} diff --git a/matrix/matrix-android/matrix-jectl/build.gradle b/matrix/matrix-android/matrix-jectl/build.gradle index c2c8d444c..8b49d40dc 100644 --- a/matrix/matrix-android/matrix-jectl/build.gradle +++ b/matrix/matrix-android/matrix-jectl/build.gradle @@ -1,5 +1,7 @@ apply plugin: 'com.android.library' +apply from: rootProject.file('gradle/WeChatNativeDepend.gradle') + android { compileSdkVersion rootProject.compileSdkVersion @@ -41,6 +43,7 @@ dependencies { androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' // implementation "com.tencent.stubs:logger:${rootProject.LOGGER_VERSION}" implementation project(':matrix-android-lib') + implementation project(':matrix-android-commons') } group = rootProject.GROUP @@ -50,7 +53,6 @@ if("External" == rootProject.ext.PUBLISH_CHANNEL) { apply from: rootProject.file('gradle/android-publish.gradle') } else { apply from: rootProject.file('gradle/WeChatPublish.gradle') - apply from: rootProject.file('gradle/WeChatNativeDepend.gradle') wechatPublish { artifactId = POM_ARTIFACT_ID } From 270aec7041f6a98d9ed6cfede311dc0c03b7d060 Mon Sep 17 00:00:00 2001 From: aurorani Date: Fri, 12 Nov 2021 15:23:25 +0800 Subject: [PATCH 022/163] refactor: Remove enhance-dlsym in matrix-android-common instead of origin. --- .../matrix-memory-dump/CMakeLists.txt | 4 +- .../main/cpp/dlfcn/enhance/EnhanceDlsym.cpp | 347 ------------------ .../src/main/cpp/dlfcn/enhance/EnhanceDlsym.h | 57 --- .../src/main/cpp/dlfcn/self_dlfcn.cpp | 2 +- 4 files changed, 3 insertions(+), 407 deletions(-) delete mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp delete mode 100644 matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.h diff --git a/matrix/matrix-android/matrix-memory-dump/CMakeLists.txt b/matrix/matrix-android/matrix-memory-dump/CMakeLists.txt index 8db8788e4..cda06177a 100644 --- a/matrix/matrix-android/matrix-memory-dump/CMakeLists.txt +++ b/matrix/matrix-android/matrix-memory-dump/CMakeLists.txt @@ -6,8 +6,7 @@ add_library( matrix-memorydump SHARED src/main/cpp/mem_dump.cpp - src/main/cpp/dlfcn/self_dlfcn.cpp - src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp) + src/main/cpp/dlfcn/self_dlfcn.cpp) find_library( log-lib @@ -21,6 +20,7 @@ target_include_directories( target_link_libraries( matrix-memorydump ${log-lib} + ${EXT_DEP}/lib/${ANDROID_ABI}/libenhance_dlsym.a ${EXT_DEP}/lib/${ANDROID_ABI}/libsemi_dlfcn.a) if(${ANDROID_ABI} MATCHES "armeabi-v7a" OR ${ANDROID_ABI} MATCHES "arm64-v8a") diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp deleted file mode 100644 index 2666bfee4..000000000 --- a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.cpp +++ /dev/null @@ -1,347 +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 "EnhanceDlsym.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../internal/log.h" - -#define TAG "Matrix.EnhanceDl" - -namespace enhance { - - static std::set m_opened_info; - static std::mutex m_dl_mutex; - static std::map m_founded_symtab; - - 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 inline bool start_with(std::string const &value, std::string const &starting) { - if (starting.size() > value.size()) { - return false; - } - return std::equal(starting.begin(), starting.end(), value.begin()); - } - - static std::string prepare_filename(const char *__filename) { - assert(__filename != nullptr); - std::stringstream ss; - - if (!start_with(__filename, "/")) { - ss << "/"; - if (!start_with(__filename, "lib")) { - ss << "lib"; - } - } - - ss << __filename; - - if (!end_with(__filename, ".so")) { - ss << ".so"; - } - - return ss.str(); - } - - static ElfW(Phdr) *get_first_segment_by_type_offset(DlInfo &__info, ElfW(Word) __type, - ElfW(Off) __offset) { - ElfW(Phdr) *phdr; - - for (phdr = __info.phdr; phdr < __info.phdr + __info.ehdr->e_phnum; phdr++) { - if (phdr->p_type == __type && phdr->p_offset == __offset) { - return phdr; - } - } - return nullptr; - } - - static int check_loaded_so(void *addr) { - Dl_info stack_info; - return dladdr(addr, &stack_info); - } - - static bool parse_maps(const std::string &__file_name, DlInfo &__info) { - bool found = false; - uintptr_t map_base_addr = 0; - char map_perm[5]; - unsigned long map_offset = 0; - char map_file_name[512]; - - std::ifstream input("/proc/self/maps"); - std::string aline; - - while (getline(input, aline)) { - if (sscanf(aline.c_str(), - "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%s", - &map_base_addr, - map_perm, - &map_offset, - map_file_name) != 4) { - continue; - } - -// _debug_log(TAG, "%s", aline.c_str()); - - if (end_with(map_file_name, __file_name) - && 0 != check_loaded_so((void *) map_base_addr)) { - found = true; - _debug_log(TAG, "found entry [%s]", aline.c_str()); - break; - } - } - - if (!found || map_perm[0] != 'r' || map_perm[3] != 'p') { - _error_log(TAG, "maps entry not found, %d, %c, %c", found, map_perm[0], map_perm[3]); - return false; - } - - __info.pathname = map_file_name; - __info.base_addr = map_base_addr; - __info.ehdr = reinterpret_cast(map_base_addr); - __info.phdr = reinterpret_cast(map_base_addr + __info.ehdr->e_phoff); - - //find the first load-segment with offset 0 - ElfW(Phdr) *phdr0 = get_first_segment_by_type_offset(__info, PT_LOAD, 0); - if (!phdr0) { - _error_log(TAG, "Can NOT found the first load segment. %s", map_file_name); - return false; - } - - //save load bias addr - if (__info.base_addr < phdr0->p_vaddr) { - _error_log(TAG, "base_addr < phdr0->p_vaddr"); - return false; - } - __info.bias_addr = __info.base_addr - phdr0->p_vaddr; - _debug_log(TAG, "bias_addr = %p, bias = %p", (void *)__info.bias_addr, (void *)phdr0->p_vaddr); - - return true; - } - - static bool parse_section_header(DlInfo &__info) { - - int fd = open(__info.pathname.c_str(), O_RDONLY | O_CLOEXEC); - if (-1 == fd) { - _error_log(TAG, "open file failed: %s", strerror(errno)); - return false; - } - - off_t elf_size = lseek(fd, 0, SEEK_END); - if (-1 == elf_size) { - close(fd); - return false; - } - ElfW(Ehdr) *elf = static_cast(mmap(nullptr, elf_size, PROT_READ, MAP_SHARED, fd, - 0)); - // TODO check elf header ? - - ElfW(Shdr) *shdr = reinterpret_cast(((uintptr_t) elf) + elf->e_shoff); - - ElfW(Shdr) *shdr_end = reinterpret_cast(((uintptr_t) shdr) + - elf->e_shentsize * elf->e_shnum); - - ElfW(Shdr) *shdr_shstrtab = reinterpret_cast((uintptr_t) shdr + - elf->e_shstrndx * - elf->e_shentsize); - - auto shstr = reinterpret_cast(((uintptr_t) elf) + - shdr_shstrtab->sh_offset); - - // SHT_SYMTAB 和 SHT_STRTAB 通常在 section header table 的末尾, 所以倒序遍历 - short flag = 0b11; - size_t count = 0; - __info.symtab_num = 0; - __info.strtab_size = 0; - do { - shdr_end--; - - switch (shdr_end->sh_type) { - - case SHT_SYMTAB: - _debug_log(TAG, "SHT_SYMTAB[%zu]", count++); - __info.symtab = static_cast(malloc(shdr_end->sh_size)); - memcpy(__info.symtab, - reinterpret_cast(((uintptr_t) elf) + shdr_end->sh_offset), - shdr_end->sh_size); - __info.symtab_num = shdr_end->sh_size / sizeof(ElfW(Sym)); - - flag &= 0b01; - break; - - case SHT_STRTAB: - _debug_log(TAG, "SHT_STRTAB[%zu]", count++); - - if (0 == strcmp(shstr + shdr_end->sh_name, ".strtab")) { - __info.strtab = static_cast(malloc(shdr_end->sh_size)); - __info.strtab_size = shdr_end->sh_size; - memcpy(__info.strtab, - reinterpret_cast(((uintptr_t) elf) + - shdr_end->sh_offset), - shdr_end->sh_size); - - flag &= 0b10; - } - - break; - } - - _debug_log(TAG, "flag = %d", flag); - - } while (flag && shdr_end != shdr); -// for (; shdr < shdr_end; shdr++) { -// -// switch (shdr->sh_type) { -// -// case SHT_SYMTAB: -// meta__.symtab = static_cast(malloc(shdr->sh_size)); -// memcpy(meta__.symtab, -// reinterpret_cast(((uintptr_t) elf) + shdr->sh_offset), shdr->sh_size); -// meta__.symtab_num = shdr_end->sh_size / sizeof(ElfW(Sym)); -// break; -// -// case SHT_STRTAB: -// -// if (0 == strcmp(shstr + shdr->sh_name,".strtab")) { -// meta__.strtab = static_cast(malloc(shdr->sh_size)); -// memcpy(meta__.strtab, -// reinterpret_cast(((uintptr_t) elf) + shdr->sh_offset), shdr->sh_size); -// } -// -// break; -// } -// } - _debug_log(TAG, "got symtab size = %d", __info.symtab_num); - - munmap(elf, elf_size); - close(fd); - - return true; - } - - static bool load(const std::string &__file_name, DlInfo &__info) { - return parse_maps(__file_name, __info) && parse_section_header(__info); - } - - void *dlopen(const char *__file_name, int __flag) { - std::lock_guard lock(m_dl_mutex); - - if (!__file_name) { - return nullptr; - } - - std::string &&suffix_name = prepare_filename(__file_name); - _debug_log(TAG, "final filename = %s", suffix_name.c_str()); - - auto info = new DlInfo; - - if (!load(suffix_name, *info)) { - delete info; - return nullptr; - } - - m_opened_info.emplace(info); - - return info; - } - - int dlclose(void *__handle) { - std::lock_guard lock(m_dl_mutex); - - if (__handle) { - auto info = static_cast(__handle); - m_opened_info.erase(info); - free(info->strtab); - free(info); - - std::map empty; - empty.swap(m_founded_symtab); - empty.clear(); - } - return 0; - } - - // TODO dlsym object and func - void *dlsym(void *__handle, const char *__symbol) { - std::lock_guard lock(m_dl_mutex); - - if (!__handle) { - return nullptr; - } - auto info = static_cast(__handle); - if (!m_opened_info.count(info)) { - return nullptr; - } - - - - ElfW(Sym) *symtab_end = info->symtab + info->symtab_num; - ElfW(Sym) *symtab_idx = info->symtab; - - for (; symtab_idx < symtab_end; symtab_idx++) { - - if (info->strtab_size <= symtab_idx->st_name) { - _debug_log(TAG, "context.strtabsz = %d, symtab_idx->st_name = %d", - info->strtab_size, symtab_idx->st_name); - } - assert (info->strtab_size > symtab_idx->st_name); - - std::string sym_name(info->strtab + symtab_idx->st_name); - if (sym_name == __symbol) { - _debug_log(TAG, "st_value=%x", symtab_idx->st_value); - uintptr_t found_sym_addr = symtab_idx->st_value + info->bias_addr; - if (check_loaded_so((void *)found_sym_addr) != 0) { - auto res = reinterpret_cast(found_sym_addr); - m_founded_symtab[res] = symtab_idx; - return res; - } - } - } - - return nullptr; - } - - size_t dlsizeof(void *__addr) { - - if (m_founded_symtab.count(__addr)) { - return m_founded_symtab[__addr]->st_size; - } - - return -1; - } -} - diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.h b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.h deleted file mode 100644 index 8a6d8fd8b..000000000 --- a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/enhance/EnhanceDlsym.h +++ /dev/null @@ -1,57 +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. -// - -#ifndef LIBMATRIX_JNI_ENHANCEDLSYM_H -#define LIBMATRIX_JNI_ENHANCEDLSYM_H - -#include -#include -#include -#include - -namespace enhance { - void* dlopen(const char* __file_name, int __flag); - int dlclose(void* __handle); - void* dlsym(void* __handle, const char* __symbol); - size_t dlsizeof(void *__addr); - - struct DlInfo { - - DlInfo() {} - ~DlInfo() {} - - std::string pathname; - - ElfW(Addr) base_addr; - ElfW(Addr) bias_addr; - - ElfW(Ehdr) *ehdr; // pointing to loaded mem - ElfW(Phdr) *phdr; // pointing to loaded mem - - char *strtab; // strtab - ElfW(Word) strtab_size; // size in bytes - - ElfW(Sym) *symtab; - ElfW(Word) symtab_num; - - }; -} - -#endif //LIBMATRIX_JNI_ENHANCEDLSYM_H diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.cpp b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.cpp index 94faf0cac..f2efd26d8 100644 --- a/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.cpp +++ b/matrix/matrix-android/matrix-memory-dump/src/main/cpp/dlfcn/self_dlfcn.cpp @@ -3,7 +3,7 @@ // #include "self_dlfcn.h" -#include "enhance/EnhanceDlsym.h" +#include #include extern "C" { From 13a1db1690271a1dc7af777f7927691e2f6c604b Mon Sep 17 00:00:00 2001 From: aurorani Date: Wed, 17 Nov 2021 20:22:12 +0800 Subject: [PATCH 023/163] feat: Migrate dump implementation of manual dump processor to fork-dump. --- .../resource/config/SharePluginInfo.java | 1 + .../processor/ManualDumpProcessor.java | 258 +++++++----------- 2 files changed, 96 insertions(+), 163 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 74ee1e53b..38047e822 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 @@ -31,6 +31,7 @@ public class SharePluginInfo { public static final String ISSUE_LEAK_DETAIL = "leak_detail"; public static final String ISSUE_COST_MILLIS = "cost_millis"; public static final String ISSUE_LEAK_PROCESS = "leak_process"; + public static final String ISSUE_DUMP_DATA = "dump_data"; 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/ManualDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java index b249ae9f8..dcde6d372 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 @@ -4,12 +4,13 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import com.tencent.matrix.memorydump.MemoryDumpManager; import com.tencent.matrix.resource.R; import com.tencent.matrix.resource.analyzer.model.ActivityLeakResult; import com.tencent.matrix.resource.analyzer.model.DestroyedActivityInfo; @@ -28,6 +29,8 @@ 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 @@ -50,13 +53,10 @@ public ManualDumpProcessor(ActivityRefWatcher watcher, String targetActivity) { super(watcher); mTargetActivity = targetActivity; mNotificationManager = (NotificationManager) watcher.getContext().getSystemService(Context.NOTIFICATION_SERVICE); - - ManualDumpProcessorHelper.install(watcher.getContext(), this); } @Override - public boolean process(DestroyedActivityInfo destroyedActivityInfo) { - final Context context = getWatcher().getContext(); + public boolean process(final DestroyedActivityInfo destroyedActivityInfo) { getWatcher().triggerGc(); if (destroyedActivityInfo.mActivityRef.get() == null) { @@ -73,12 +73,28 @@ public boolean process(DestroyedActivityInfo destroyedActivityInfo) { return true; } + dumpAndAnalyzeAsync(destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey, new ManualDumpCallback() { + @Override + public void onDumpComplete(@Nullable ManualDumpData data) { + if (data != null) { + MatrixLog.i(TAG, "shown notification!!!3"); + publishResult(destroyedActivityInfo, data); + } + } + }); + + return true; + } + + private void publishResult(DestroyedActivityInfo activityInfo, ManualDumpData data) { + final Context context = getWatcher().getContext(); + Intent targetIntent = new Intent(); targetIntent.setClassName(getWatcher().getContext(), mTargetActivity); - targetIntent.putExtra(SharePluginInfo.ISSUE_ACTIVITY_NAME, destroyedActivityInfo.mActivityName); - targetIntent.putExtra(SharePluginInfo.ISSUE_REF_KEY, destroyedActivityInfo.mKey); + targetIntent.putExtra(SharePluginInfo.ISSUE_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); PendingIntent pIntent = PendingIntent.getActivity(context, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT); @@ -86,32 +102,28 @@ public boolean process(DestroyedActivityInfo destroyedActivityInfo) { ResourceConfig config = getWatcher().getResourcePlugin().getConfig(); String dumpingHeapContent = String.format(Locale.getDefault(), "[%s] has leaked for [%s]min!!!", - destroyedActivityInfo.mActivityName, + activityInfo.mActivityName, TimeUnit.MILLISECONDS.toMinutes( config.getScanIntervalMillis() * config.getMaxRedetectTimes())); - Notification.Builder builder = null; + Notification.Builder builder; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { builder = new Notification.Builder(context, getNotificationChannelIdCompat(context)); } else { builder = new Notification.Builder(context); } + builder.setContentTitle(dumpingHeapTitle) .setPriority(Notification.PRIORITY_DEFAULT) .setStyle(new Notification.BigTextStyle().bigText(dumpingHeapContent)) - .setContentIntent(pIntent) .setAutoCancel(true) + .setContentIntent(pIntent) .setSmallIcon(R.drawable.ic_launcher) .setWhen(System.currentTimeMillis()); Notification notification = builder.build(); - mNotificationManager.notify( - NOTIFICATION_ID + destroyedActivityInfo.mKey.hashCode(), notification); - - publishIssue(destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey); - MatrixLog.i(TAG, "shown notification!!!3"); - return true; + mNotificationManager.notify(NOTIFICATION_ID + activityInfo.mKey.hashCode(), notification); } private String getNotificationChannelIdCompat(Context context) { @@ -133,190 +145,110 @@ 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 * * @param activity - * @param refString + * @param key * @return */ - private ManualDumpData dumpAndAnalyse(String activity, String refString) { - long dumpBegin = System.currentTimeMillis(); + private ManualDumpData dumpAndAnalyse(String activity, String key) { + long dumpStart = System.currentTimeMillis(); getWatcher().triggerGc(); - File file = getHeapDumper().dumpHeap(false); + File file = getDumpStorageManager().newHprofFile(); + if (file != null) { + MemoryDumpManager.dumpBlock(file.getPath()); + } if (file == null || file.length() <= 0) { -// publishIssue(SharePluginInfo.IssueType.ERR_FILE_NOT_FOUND, activity, refString, "file is null", "0"); + publishIssue( + SharePluginInfo.IssueType.ERR_FILE_NOT_FOUND, + ResourceConfig.DumpMode.MANUAL_DUMP, + activity, key, "FileNull", "0"); MatrixLog.e(TAG, "file is null!"); return null; } MatrixLog.i(TAG, String.format("dump cost=%sms refString=%s path=%s", - System.currentTimeMillis() - dumpBegin, refString, file.getAbsolutePath())); + System.currentTimeMillis() - dumpStart, key, file.getAbsolutePath())); long analyseBegin = System.currentTimeMillis(); try { - final ActivityLeakResult result = analyze(file, refString); + final ActivityLeakResult result = analyze(file, key); MatrixLog.i(TAG, String.format("analyze cost=%sms refString=%s", - System.currentTimeMillis() - analyseBegin, refString)); - - String refChain = result.toString(); + System.currentTimeMillis() - analyseBegin, key)); + String leakChain = result.toString(); if (result.mLeakFound) { -// publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, activity, refString, refChain, String.valueOf(System.currentTimeMillis() - dumpBegin)); - MatrixLog.i(TAG, "leakFound,refcChain = %s", refChain); - return new ManualDumpData(file.getAbsolutePath(), refChain); + MatrixLog.i(TAG, "leakFound,refcChain = %s", leakChain); + publishIssue( + SharePluginInfo.IssueType.LEAK_FOUND, + ResourceConfig.DumpMode.MANUAL_DUMP, + activity, key, leakChain, + String.valueOf(System.currentTimeMillis() - dumpStart)); + return new ManualDumpData(file.getAbsolutePath(), leakChain); } else { MatrixLog.i(TAG, "leak not found"); return new ManualDumpData(file.getAbsolutePath(), null); } } catch (OutOfMemoryError error) { -// publishIssue(SharePluginInfo.IssueType.ERR_ANALYSE_OOM, activity, refString, "OutOfMemoryError", "0"); + publishIssue( + SharePluginInfo.IssueType.ERR_ANALYSE_OOM, + ResourceConfig.DumpMode.MANUAL_DUMP, + activity, key, "OutOfMemoryError", "0"); MatrixLog.printErrStackTrace(TAG, error.getCause(), ""); } return null; } - private void publishIssue(String activity, String refKey) { - publishIssue(SharePluginInfo.IssueType.LEAK_FOUND, ResourceConfig.DumpMode.MANUAL_DUMP, activity, refKey, "manual_dump", "0"); - } - - /** - * multi process dump helper. - */ - public static class ManualDumpProcessorHelper extends BroadcastReceiver { - - private static final String DUMP_PERMISSION_SUFFIX = ".manual.dump"; - - private static final String ACTION_DUMP = "com.tencent.matrix.manual.dump"; - private static final String ACTION_RESULT = "com.tencent.matrix.manual.result"; - - private static final String KEY_RESULT_PROCESS = "result_process"; - private static final String KEY_LEAK_ACTIVITY = "leak_activity"; - private static final String KEY_LEAK_PROCESS = "leak_process"; - private static final String KEY_LEAK_REFKEY = "leak_refkey"; - private static final String KEY_HPROF_PATH = "hprof_path"; - private static final String KEY_REF_CHAIN = "ref_chain"; + public static class ManualDumpData implements Parcelable { + public final String hprofPath; + public final String refChain; - private static boolean hasInstalled; + public ManualDumpData(String hprofPath, String refChain) { + this.hprofPath = hprofPath; + this.refChain = refChain; + } - private static ManualDumpProcessor sProcessor; - private static IResultListener sListener; // only not null in process who called dumpAndAnalyse + protected ManualDumpData(Parcel in) { + hprofPath = in.readString(); + refChain = in.readString(); + } @Override - public void onReceive(final Context context, final Intent intent) { - if (intent == null) { - MatrixLog.e(TAG, "intent is null"); - return; - } - - MatrixHandlerThread.getDefaultHandler().postAtFrontOfQueue(new Runnable() { - @Override - public void run() { - if (ACTION_DUMP.equals(intent.getAction())) { - String leakProcess = intent.getStringExtra(KEY_LEAK_PROCESS); - String currentProcess = MatrixUtil.getProcessName(context); - if (!currentProcess.equals(leakProcess)) { - MatrixLog.v(TAG, "ACTION_DUMP: current process [%s] is NOT leaked process [%s]", currentProcess, leakProcess); - return; - } - - // leaked process - MatrixLog.v(TAG, "ACTION_DUMP: current process [%s] is leaked process [%s]", currentProcess, leakProcess); - - String leakActivity = intent.getStringExtra(KEY_LEAK_ACTIVITY); - String refKey = intent.getStringExtra(KEY_LEAK_REFKEY); - - ManualDumpData data = sProcessor.dumpAndAnalyse(leakActivity, refKey); - Intent resultIntent = new Intent(ACTION_RESULT); - if (data != null) { - resultIntent.putExtra(KEY_HPROF_PATH, data.hprofPath); - resultIntent.putExtra(KEY_REF_CHAIN, data.refChain); - } - String resultProcess = intent.getStringExtra(KEY_RESULT_PROCESS); - resultIntent.putExtra(KEY_RESULT_PROCESS, resultProcess); - context.sendBroadcast(resultIntent, - context.getPackageName() + DUMP_PERMISSION_SUFFIX); - } else if (ACTION_RESULT.equals(intent.getAction())) { - // result process - final String resultProcess = intent.getStringExtra(KEY_RESULT_PROCESS); - final String currentProcess = MatrixUtil.getProcessName(context); - if (!currentProcess.equals(resultProcess)) { - MatrixLog.v(TAG, "ACTION_RESULT: current process [%s] is NOT result process [%s]", currentProcess, resultProcess); - return; - } - - MatrixLog.v(TAG, "ACTION_RESULT: current process [%s] is result process [%s]", currentProcess, resultProcess); - - // generally, sListener must be NOT null - if (sListener == null) { - throw new NullPointerException("result listener is null!!!"); - } - - final String hprofPath = intent.getStringExtra(KEY_HPROF_PATH); - if (hprofPath == null) { - sListener.onFailed(); - return; - } - final String refChain = intent.getStringExtra(KEY_REF_CHAIN); - sListener.onSuccess(hprofPath, refChain); - sListener = null; - } - } - }); + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(hprofPath); + dest.writeString(refChain); } - private static void install(Context context, ManualDumpProcessor processor) { - IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_DUMP); - filter.addAction(ACTION_RESULT); - final String dumpPermission = context.getPackageName() + DUMP_PERMISSION_SUFFIX; - context.registerReceiver(new ManualDumpProcessorHelper(), filter, dumpPermission, null); - MatrixLog.d(TAG, "[%s] DUMP_PERMISSION is %s", MatrixUtil.getProcessName(context), dumpPermission); - hasInstalled = true; - sProcessor = processor; + @Override + public int describeContents() { + return 0; } - public static void dumpAndAnalyse(Context context, String leakProcess, String activity, String refKey, IResultListener resultListener) { - if (!hasInstalled) { - throw new IllegalStateException("ManualDumpProcessorHelper was not installed yet!!! maybe your target activity is not running in right process."); + public static final Creator CREATOR = new Creator() { + @Override + public ManualDumpData createFromParcel(Parcel in) { + return new ManualDumpData(in); } - final String currentProcess = MatrixUtil.getProcessName(context); - if (currentProcess.equalsIgnoreCase(leakProcess)) { - // dump and analyze for current process - ManualDumpData data = sProcessor.dumpAndAnalyse(activity, refKey); - if (data == null) { - resultListener.onFailed(); - } else { - resultListener.onSuccess(data.hprofPath, data.refChain); - } - } else { - sListener = resultListener; - MatrixLog.v(TAG, "[%s] send broadcast with permission: %s", currentProcess, - context.getPackageName() + DUMP_PERMISSION_SUFFIX); - Intent intent = new Intent(ACTION_DUMP); - intent.putExtra(KEY_LEAK_PROCESS, leakProcess); - intent.putExtra(KEY_LEAK_ACTIVITY, activity); - intent.putExtra(KEY_LEAK_REFKEY, refKey); - intent.putExtra(KEY_RESULT_PROCESS, currentProcess); - context.sendBroadcast(intent, context.getPackageName() + DUMP_PERMISSION_SUFFIX); - } - } - } - - public interface IResultListener { - void onSuccess(String hprof, String leakReference); - - void onFailed(); - } - - public static class ManualDumpData { - public final String hprofPath; - public final String refChain; - public ManualDumpData(String hprofPath, String refChain) { - this.hprofPath = hprofPath; - this.refChain = refChain; - } + @Override + public ManualDumpData[] newArray(int size) { + return new ManualDumpData[size]; + } + }; } } From 962af51d0eef94cc2d5cc7c992798b62d482dc99 Mon Sep 17 00:00:00 2001 From: aurorani Date: Thu, 18 Nov 2021 14:39:34 +0800 Subject: [PATCH 024/163] fix: Fork Analyse Processor now support publishing file-not-found issue. --- .../processor/ForkAnalyseProcessor.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 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 85f6e5c6e..657fddb34 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 @@ -47,14 +47,20 @@ private boolean dumpAndAnalyse(String activity, String key) { final File hprof = getDumpStorageManager().newHprofFile(); - if (hprof == null) { - MatrixLog.e(TAG, "cannot create hprof file"); - return false; + if (hprof != null) { + if (!MemoryDumpManager.dumpBlock(hprof.getPath())) { + MatrixLog.e(TAG, String.format("heap dump for further analyzing activity with key [%s] was failed, just ignore.", + key)); + return false; + } } - if (!MemoryDumpManager.dumpBlock(hprof.getPath())) { - MatrixLog.e(TAG, String.format("heap dump for further analyzing activity with key [%s] was failed, just ignore.", - key)); + if (hprof == null || hprof.length() == 0) { + publishIssue( + SharePluginInfo.IssueType.ERR_FILE_NOT_FOUND, + ResourceConfig.DumpMode.FORK_ANALYSE, + activity, key, "FileNull", "0"); + MatrixLog.e(TAG, "cannot create hprof file"); return false; } From 15e5f1b04bfeeb83950c176199ab7ec4e837e010 Mon Sep 17 00:00:00 2001 From: opdeng Date: Fri, 26 Nov 2021 11:19:46 +0800 Subject: [PATCH 025/163] add customize leak --- .../matrix/openglleak/OpenglLeakPlugin.java | 6 +- .../matrix/openglleak/hook/OpenGLHook.java | 10 +- .../openglleak/statistics/LeakMonitor.java | 234 +---------------- .../statistics/LeakMonitorCustomize.java | 4 + .../LeakMonitorForActivityLifecycle.java | 237 ++++++++++++++++++ .../statistics/OpenGLResRecorder.java | 35 +-- 6 files changed, 253 insertions(+), 273 deletions(-) create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorCustomize.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java 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 6a0ecc4b3..3f568f561 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 @@ -12,7 +12,7 @@ import com.tencent.matrix.openglleak.detector.IOpenglIndexDetector; import com.tencent.matrix.openglleak.detector.OpenglIndexDetectorService; import com.tencent.matrix.openglleak.hook.OpenGLHook; -import com.tencent.matrix.openglleak.statistics.LeakMonitor; +import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle; import com.tencent.matrix.openglleak.utils.EGLHelper; import com.tencent.matrix.plugin.Plugin; import com.tencent.matrix.plugin.PluginListener; @@ -102,7 +102,7 @@ private void executeHook(IBinder iBinder) { MatrixLog.e(TAG, "hook finish"); // 泄漏监控 - LeakMonitor.getInstance().start((Application) context.getApplicationContext()); + LeakMonitorForActivityLifecycle.getInstance().start((Application) context.getApplicationContext()); } catch (Throwable e) { e.printStackTrace(); } finally { @@ -172,7 +172,7 @@ public void setJavaStackDump(boolean open) { } public void setDoubleCheckTime(long time) { - LeakMonitor.getInstance().setDoubleCheckTime(time); + LeakMonitorForActivityLifecycle.getInstance().setDoubleCheckTime(time); } } 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 e69e79061..2bd70151e 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 @@ -3,7 +3,7 @@ import android.opengl.EGL14; import com.tencent.matrix.openglleak.comm.FuncNameString; -import com.tencent.matrix.openglleak.statistics.LeakMonitor; +import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle; import com.tencent.matrix.openglleak.statistics.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.OpenGLResRecorder; @@ -89,7 +89,7 @@ public static void onGlGenTextures(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitor.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -128,7 +128,7 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitor.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -167,7 +167,7 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitor.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -206,7 +206,7 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitor.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitor.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitor.java index 708c678b2..c1ad9f0de 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitor.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitor.java @@ -1,236 +1,6 @@ package com.tencent.matrix.openglleak.statistics; -import android.app.Activity; -import android.app.Application; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; +@Deprecated +public class LeakMonitor extends LeakMonitorForActivityLifecycle { -import com.tencent.matrix.util.MatrixLog; - -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class LeakMonitor implements Application.ActivityLifecycleCallbacks { - - private static final String TAG = "matrix.GPU_LeakMonitor"; - private static LeakMonitor mInstance = new LeakMonitor(); - - private HandlerThread mHT; - private Handler mH; - - private Map, List> maps; - private String currentActivityName = ""; - - private long mDoubleCheckTime = 1000 * 60 * 30; - private final long mDoubleCheckLooper = 1000 * 60 * 1; - - private LeakMonitor() { - mHT = new HandlerThread("LeakMonitor"); - mHT.start(); - mH = new Handler(mHT.getLooper()); - - mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); - - maps = new HashMap<>(); - } - - public static LeakMonitor getInstance() { - return mInstance; - } - - public void setDoubleCheckTime(long doubleCheckTime) { - mDoubleCheckTime = doubleCheckTime; - } - - public void setListener(LeakListener l) { - OpenGLResRecorder.getInstance().setLeakListener(l); - } - - public void start(Application context) { - MatrixLog.i(TAG, "start"); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - (context).registerActivityLifecycleCallbacks(mInstance); - } - } - - public String getCurrentActivityName() { - return currentActivityName; - } - - @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - currentActivityName = activity.getLocalClassName(); - - MatrixLog.i(TAG, "activity oncreate:" + currentActivityName + " :" + activity.hashCode()); - - WeakReference weakReference = new WeakReference<>(activity); - List actvityList = OpenGLResRecorder.getInstance().getAllHashCode(); - - maps.put(weakReference, actvityList); - } - - @Override - public void onActivityDestroyed(Activity activity) { - MatrixLog.i(TAG, - "activity ondestroy:" + activity.getLocalClassName() + " :" + activity.hashCode()); - - WeakReference target = null; - - Set mapSet = maps.keySet(); - Iterator it = mapSet.iterator(); - while (it.hasNext()) { - WeakReference weakReference = (WeakReference) it.next(); - - Activity a = (Activity) weakReference.get(); - if (a == null) { - // 空的话移除 - it.remove(); - continue; - } - - if ((a == activity)) { - target = weakReference; - break; - } - } - - // 找不到,跳过不处理 - if (target == null) { - return; - } - - String activityName = ""; - Activity aa = target.get(); - if (aa != null) { - activityName = aa.getLocalClassName(); - } - - final String activityStr = activityName; - final List createList = maps.get(target); - final List destroyList = OpenGLResRecorder.getInstance().getAllHashCode(); - - mH.post(new Runnable() { - @Override - public void run() { - boolean result = findLeak(createList, destroyList); - if (result) { - MatrixLog.i(TAG, activityStr + " leak! "); - } - } - }); - - // clear - maps.remove(target); - } - - private boolean findLeak(List createList, List destroyList) { - if ((createList == null) || (destroyList == null)) { - return false; - } - - boolean hasLeak = false; - - for (Integer destroy : destroyList) { - if (destroy == null) { - continue; - } - - boolean isLeak; - int i = 0; - for (Integer create : createList) { - if (create == null) { - i = i + 1; - continue; - } - - if (create.intValue() == destroy.intValue()) { - break; - } - - i = i + 1; - } - - if (i == createList.size()) { - isLeak = true; - } else { - isLeak = false; - } - - if (isLeak) { - OpenGLInfo leakInfo = OpenGLResRecorder.getInstance().getItemByHashCode(destroy); - - if ((leakInfo != null) && !leakInfo.getMaybeLeak()) { - OpenGLResRecorder.getInstance().getNativeStack(leakInfo); - OpenGLResRecorder.getInstance().setMaybeLeak(leakInfo); - - hasLeak = true; - } - } - } - - return hasLeak; - } - - @Override - public void onActivityStarted(Activity activity) { - - } - - @Override - public void onActivityResumed(Activity activity) { - currentActivityName = activity.getLocalClassName(); - } - - @Override - public void onActivityPaused(Activity activity) { - - } - - @Override - public void onActivityStopped(Activity activity) { - - } - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - - } - - public interface LeakListener { - void onMaybeLeak(OpenGLInfo info); - - void onLeak(OpenGLInfo info); - } - - private Runnable doubleCheckRunnable = new Runnable() { - @Override - public void run() { - long now = System.currentTimeMillis(); - - List copyList = OpenGLResRecorder.getInstance().getCopyList(); - MatrixLog.i(TAG, "double check list size:" + copyList.size()); - - for (OpenGLInfo item : copyList) { - if (item == null) { - continue; - } - - if (item.getMaybeLeak()) { - if ((now - item.getMaybeLeakTime()) > mDoubleCheckTime) { - OpenGLResRecorder.getInstance().setLeak(item); - OpenGLResRecorder.getInstance().remove(item); - } - } - } - - mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); - } - }; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorCustomize.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorCustomize.java new file mode 100644 index 000000000..2fa6ad6b8 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorCustomize.java @@ -0,0 +1,4 @@ +package com.tencent.matrix.openglleak.statistics; + +public class LeakMonitorCustomize { +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java new file mode 100644 index 000000000..76d2724e9 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java @@ -0,0 +1,237 @@ +package com.tencent.matrix.openglleak.statistics; + +import android.app.Activity; +import android.app.Application; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; + +import com.tencent.matrix.util.MatrixLog; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Deprecated +public class LeakMonitorForActivityLifecycle implements Application.ActivityLifecycleCallbacks { + + private static final String TAG = "matrix.GPU_LeakMonitor"; + private static LeakMonitorForActivityLifecycle mInstance = new LeakMonitorForActivityLifecycle(); + + private HandlerThread mHT; + private Handler mH; + + private Map, List> maps; + private String currentActivityName = ""; + + private long mDoubleCheckTime = 1000 * 60 * 30; + private final long mDoubleCheckLooper = 1000 * 60 * 1; + + protected LeakMonitorForActivityLifecycle() { + mHT = new HandlerThread("LeakMonitor"); + mHT.start(); + mH = new Handler(mHT.getLooper()); + + mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); + + maps = new HashMap<>(); + } + + public static LeakMonitorForActivityLifecycle getInstance() { + return mInstance; + } + + public void setDoubleCheckTime(long doubleCheckTime) { + mDoubleCheckTime = doubleCheckTime; + } + + public void setListener(LeakListener l) { + OpenGLResRecorder.getInstance().setLeakListener(l); + } + + public void start(Application context) { + MatrixLog.i(TAG, "start"); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + (context).registerActivityLifecycleCallbacks(mInstance); + } + } + + public String getCurrentActivityName() { + return currentActivityName; + } + + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + currentActivityName = activity.getLocalClassName(); + + MatrixLog.i(TAG, "activity oncreate:" + currentActivityName + " :" + activity.hashCode()); + + WeakReference weakReference = new WeakReference<>(activity); + List actvityList = OpenGLResRecorder.getInstance().getAllHashCode(); + + maps.put(weakReference, actvityList); + } + + @Override + public void onActivityDestroyed(Activity activity) { + MatrixLog.i(TAG, + "activity ondestroy:" + activity.getLocalClassName() + " :" + activity.hashCode()); + + WeakReference target = null; + + Set mapSet = maps.keySet(); + Iterator it = mapSet.iterator(); + while (it.hasNext()) { + WeakReference weakReference = (WeakReference) it.next(); + + Activity a = (Activity) weakReference.get(); + if (a == null) { + // 空的话移除 + it.remove(); + continue; + } + + if ((a == activity)) { + target = weakReference; + break; + } + } + + // 找不到,跳过不处理 + if (target == null) { + return; + } + + String activityName = ""; + Activity aa = target.get(); + if (aa != null) { + activityName = aa.getLocalClassName(); + } + + final String activityStr = activityName; + final List createList = maps.get(target); + final List destroyList = OpenGLResRecorder.getInstance().getAllHashCode(); + + mH.post(new Runnable() { + @Override + public void run() { + boolean result = findLeak(createList, destroyList); + if (result) { + MatrixLog.i(TAG, activityStr + " leak! "); + } + } + }); + + // clear + maps.remove(target); + } + + private boolean findLeak(List createList, List destroyList) { + if ((createList == null) || (destroyList == null)) { + return false; + } + + boolean hasLeak = false; + + for (Integer destroy : destroyList) { + if (destroy == null) { + continue; + } + + boolean isLeak; + int i = 0; + for (Integer create : createList) { + if (create == null) { + i = i + 1; + continue; + } + + if (create.intValue() == destroy.intValue()) { + break; + } + + i = i + 1; + } + + if (i == createList.size()) { + isLeak = true; + } else { + isLeak = false; + } + + if (isLeak) { + OpenGLInfo leakInfo = OpenGLResRecorder.getInstance().getItemByHashCode(destroy); + + if ((leakInfo != null) && !leakInfo.getMaybeLeak()) { + OpenGLResRecorder.getInstance().getNativeStack(leakInfo); + OpenGLResRecorder.getInstance().setMaybeLeak(leakInfo); + + hasLeak = true; + } + } + } + + return hasLeak; + } + + @Override + public void onActivityStarted(Activity activity) { + + } + + @Override + public void onActivityResumed(Activity activity) { + currentActivityName = activity.getLocalClassName(); + } + + @Override + public void onActivityPaused(Activity activity) { + + } + + @Override + public void onActivityStopped(Activity activity) { + + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + + } + + public interface LeakListener { + void onMaybeLeak(OpenGLInfo info); + + void onLeak(OpenGLInfo info); + } + + private Runnable doubleCheckRunnable = new Runnable() { + @Override + public void run() { + long now = System.currentTimeMillis(); + + List copyList = OpenGLResRecorder.getInstance().getCopyList(); + MatrixLog.i(TAG, "double check list size:" + copyList.size()); + + for (OpenGLInfo item : copyList) { + if (item == null) { + continue; + } + + if (item.getMaybeLeak()) { + if ((now - item.getMaybeLeakTime()) > mDoubleCheckTime) { + OpenGLResRecorder.getInstance().setLeak(item); + OpenGLResRecorder.getInstance().remove(item); + } + } + } + + mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); + } + }; +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index ddac6fdfe..d3e802d9b 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -2,7 +2,6 @@ import android.os.Handler; import android.os.HandlerThread; -import android.text.TextUtils; import java.util.ArrayList; import java.util.Iterator; @@ -17,7 +16,7 @@ public class OpenGLResRecorder { private HandlerThread mHandlerThread; private Handler mH; - private LeakMonitor.LeakListener mListener; + private LeakMonitorForActivityLifecycle.LeakListener mListener; private OpenGLResRecorder() { mHandlerThread = new HandlerThread("GpuResLeakMonitor"); @@ -30,7 +29,7 @@ public static OpenGLResRecorder getInstance() { return mInstance; } - public void setLeakListener(LeakMonitor.LeakListener mListener) { + public void setLeakListener(LeakMonitorForActivityLifecycle.LeakListener mListener) { this.mListener = mListener; } @@ -204,36 +203,6 @@ public void setMaybeLeak(OpenGLInfo info) { } } - private boolean isNeedIgnore(OpenGLInfo info) { - if (TextUtils.isEmpty(info.getJavaStack())) { - boolean isIgnore = true; - - String nativeStack = info.getNativeStack(); - if (!TextUtils.isEmpty(nativeStack)) { - String[] lines = nativeStack.split("\n"); - for (String line : lines) { - if (!TextUtils.isEmpty(line)) { - if (!line.contains("libmatrix-opengl-leak.so") - && !line.contains("libwechatbacktrace.so") - && !line.contains("libGLESv1_CM.so") - && !line.contains("libhwui.so") - && !line.contains("libutils.so") - && !line.contains("libandroid_runtime.so") - && !line.contains("libc.so") - && line.contains(".so")) { - isIgnore = false; - break; - } - } - } - } - - return isIgnore; - } - - return false; - } - public OpenGLInfo getItemByHashCode(int hashCode) { synchronized (infoList) { for (OpenGLInfo item : infoList) { From b8d2cf6b62f1dd16cf728961619d1041142043be Mon Sep 17 00:00:00 2001 From: opdeng Date: Fri, 26 Nov 2021 19:18:53 +0800 Subject: [PATCH 026/163] =?UTF-8?q?1.=20=E6=B7=BB=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=B3=84=E6=BC=8F=E7=9B=91=E6=8E=A7=202.=20A?= =?UTF-8?q?ctivity=20=E7=94=9F=E5=91=BD=E5=91=A8=E6=9C=9F=E6=B3=84?= =?UTF-8?q?=E6=BC=8F=E7=9B=91=E6=8E=A7=20@Deprecated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix/openglleak/hook/OpenGLHook.java | 20 ++--- .../openglleak/statistics/LeakMonitor.java | 6 -- .../LeakMonitorForActivityLifecycle.java | 34 ++++---- ...mize.java => LeakMonitorForCustomize.java} | 2 +- .../statistics/{ => source}/OpenGLInfo.java | 24 +++++- .../statistics/source/ResRecordManager.java | 80 +++++++++++++++++++ .../ResRecorderForActivityLifecycle.java} | 62 ++++---------- .../source/ResRecorderForCustomize.java | 40 ++++++++++ .../openglleak/utils/GlLeakHandlerThread.java | 17 ++++ ...LeakMonitorLog.java => OpenGLLeakLog.java} | 2 +- 10 files changed, 202 insertions(+), 85 deletions(-) delete mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitor.java rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/{LeakMonitorCustomize.java => LeakMonitorForCustomize.java} (57%) rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/{ => source}/OpenGLInfo.java (87%) create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/{OpenGLResRecorder.java => source/ResRecorderForActivityLifecycle.java} (70%) create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/{OpenGLLeakMonitorLog.java => OpenGLLeakLog.java} (96%) 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 2bd70151e..73d01b7fd 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 @@ -4,8 +4,8 @@ import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle; -import com.tencent.matrix.openglleak.statistics.OpenGLInfo; -import com.tencent.matrix.openglleak.statistics.OpenGLResRecorder; +import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; +import com.tencent.matrix.openglleak.statistics.source.ResRecordManager; import java.util.concurrent.atomic.AtomicInteger; @@ -90,7 +90,7 @@ public static void onGlGenTextures(int[] ids, String threadId, String javaStack, for (int id : ids) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); - OpenGLResRecorder.getInstance().gen(openGLInfo); + ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { getInstance().mListener.onGlGenTextures(openGLInfo); @@ -109,7 +109,7 @@ public static void onGlDeleteTextures(int[] ids, String threadId) { for (int id : ids) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, false); - OpenGLResRecorder.getInstance().delete(openGLInfo); + ResRecordManager.getInstance().delete(openGLInfo); if (getInstance().mListener != null) { getInstance().mListener.onGlDeleteTextures(openGLInfo); @@ -129,7 +129,7 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, for (int id : ids) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); - OpenGLResRecorder.getInstance().gen(openGLInfo); + ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { getInstance().mListener.onGlGenBuffers(openGLInfo); @@ -148,7 +148,7 @@ public static void onGlDeleteBuffers(int[] ids, String threadId) { for (int id : ids) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, false); - OpenGLResRecorder.getInstance().delete(openGLInfo); + ResRecordManager.getInstance().delete(openGLInfo); if (getInstance().mListener != null) { getInstance().mListener.onGlDeleteBuffers(openGLInfo); @@ -168,7 +168,7 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt for (int id : ids) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); - OpenGLResRecorder.getInstance().gen(openGLInfo); + ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { getInstance().mListener.onGlGenFramebuffers(openGLInfo); @@ -187,7 +187,7 @@ public static void onGlDeleteFramebuffers(int[] ids, String threadId) { for (int id : ids) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, false); - OpenGLResRecorder.getInstance().delete(openGLInfo); + ResRecordManager.getInstance().delete(openGLInfo); if (getInstance().mListener != null) { getInstance().mListener.onGlDeleteFramebuffers(openGLInfo); @@ -207,7 +207,7 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS for (int id : ids) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); - OpenGLResRecorder.getInstance().gen(openGLInfo); + ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { getInstance().mListener.onGlGenRenderbuffers(openGLInfo); @@ -226,7 +226,7 @@ public static void onGlDeleteRenderbuffers(int[] ids, String threadId) { for (int id : ids) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, false); - OpenGLResRecorder.getInstance().delete(openGLInfo); + ResRecordManager.getInstance().delete(openGLInfo); if (getInstance().mListener != null) { getInstance().mListener.onGlDeleteRenderbuffers(openGLInfo); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitor.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitor.java deleted file mode 100644 index c1ad9f0de..000000000 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitor.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.tencent.matrix.openglleak.statistics; - -@Deprecated -public class LeakMonitor extends LeakMonitorForActivityLifecycle { - -} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java index 76d2724e9..325c965eb 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java @@ -5,8 +5,10 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.HandlerThread; +import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; +import com.tencent.matrix.openglleak.statistics.source.ResRecorderForActivityLifecycle; +import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; import com.tencent.matrix.util.MatrixLog; import java.lang.ref.WeakReference; @@ -22,23 +24,19 @@ public class LeakMonitorForActivityLifecycle implements Application.ActivityLife private static final String TAG = "matrix.GPU_LeakMonitor"; private static LeakMonitorForActivityLifecycle mInstance = new LeakMonitorForActivityLifecycle(); - private HandlerThread mHT; private Handler mH; - private Map, List> maps; + private Map, List> maps = new HashMap<>(); private String currentActivityName = ""; + private ResRecorderForActivityLifecycle mResRecorder = new ResRecorderForActivityLifecycle(); + private long mDoubleCheckTime = 1000 * 60 * 30; private final long mDoubleCheckLooper = 1000 * 60 * 1; protected LeakMonitorForActivityLifecycle() { - mHT = new HandlerThread("LeakMonitor"); - mHT.start(); - mH = new Handler(mHT.getLooper()); - + mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); - - maps = new HashMap<>(); } public static LeakMonitorForActivityLifecycle getInstance() { @@ -50,7 +48,7 @@ public void setDoubleCheckTime(long doubleCheckTime) { } public void setListener(LeakListener l) { - OpenGLResRecorder.getInstance().setLeakListener(l); + mResRecorder.setLeakListener(l); } public void start(Application context) { @@ -72,7 +70,7 @@ public void onActivityCreated(Activity activity, Bundle savedInstanceState) { MatrixLog.i(TAG, "activity oncreate:" + currentActivityName + " :" + activity.hashCode()); WeakReference weakReference = new WeakReference<>(activity); - List actvityList = OpenGLResRecorder.getInstance().getAllHashCode(); + List actvityList = mResRecorder.getAllHashCode(); maps.put(weakReference, actvityList); } @@ -115,7 +113,7 @@ public void onActivityDestroyed(Activity activity) { final String activityStr = activityName; final List createList = maps.get(target); - final List destroyList = OpenGLResRecorder.getInstance().getAllHashCode(); + final List destroyList = mResRecorder.getAllHashCode(); mH.post(new Runnable() { @Override @@ -165,11 +163,11 @@ private boolean findLeak(List createList, List destroyList) { } if (isLeak) { - OpenGLInfo leakInfo = OpenGLResRecorder.getInstance().getItemByHashCode(destroy); + OpenGLInfo leakInfo = mResRecorder.getItemByHashCode(destroy); if ((leakInfo != null) && !leakInfo.getMaybeLeak()) { - OpenGLResRecorder.getInstance().getNativeStack(leakInfo); - OpenGLResRecorder.getInstance().setMaybeLeak(leakInfo); + mResRecorder.getNativeStack(leakInfo); + mResRecorder.setMaybeLeak(leakInfo); hasLeak = true; } @@ -215,7 +213,7 @@ public interface LeakListener { public void run() { long now = System.currentTimeMillis(); - List copyList = OpenGLResRecorder.getInstance().getCopyList(); + List copyList = mResRecorder.getCopyList(); MatrixLog.i(TAG, "double check list size:" + copyList.size()); for (OpenGLInfo item : copyList) { @@ -225,8 +223,8 @@ public void run() { if (item.getMaybeLeak()) { if ((now - item.getMaybeLeakTime()) > mDoubleCheckTime) { - OpenGLResRecorder.getInstance().setLeak(item); - OpenGLResRecorder.getInstance().remove(item); + mResRecorder.setLeak(item); + mResRecorder.remove(item); } } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorCustomize.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForCustomize.java similarity index 57% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorCustomize.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForCustomize.java index 2fa6ad6b8..02503874f 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorCustomize.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForCustomize.java @@ -1,4 +1,4 @@ package com.tencent.matrix.openglleak.statistics; -public class LeakMonitorCustomize { +public class LeakMonitorForCustomize { } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java similarity index 87% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java index 1901b8385..c91818758 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java @@ -1,7 +1,8 @@ -package com.tencent.matrix.openglleak.statistics; +package com.tencent.matrix.openglleak.statistics.source; import android.text.TextUtils; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; public class OpenGLInfo { @@ -183,4 +184,25 @@ public String toString() { '}'; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OpenGLInfo that = (OpenGLInfo) o; + return id == that.id && + eglContextNativeHandle == that.eglContextNativeHandle && + threadId.equals(that.threadId) && + type == that.type; + } + + @Override + public int hashCode() { + return Objects.hash(id, threadId, eglContextNativeHandle, type); + } + + @Override + protected void finalize() throws Throwable { + release(); + super.finalize(); + } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java new file mode 100644 index 000000000..0d4c2940b --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java @@ -0,0 +1,80 @@ +package com.tencent.matrix.openglleak.statistics.source; + +import android.os.Handler; + +import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; + +import java.util.LinkedList; +import java.util.List; + +public class ResRecordManager { + + private static ResRecordManager mInstance = new ResRecordManager(); + + private Handler mH; + + private List mCallbackList = new LinkedList<>(); + + private ResRecordManager() { + mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); + } + + public static ResRecordManager getInstance() { + return mInstance; + } + + public void gen(final OpenGLInfo oinfo) { + mH.post(new Runnable() { + @Override + public void run() { + if (oinfo == null) { + return; + } + + for (Callback cb : mCallbackList) { + if (null != cb) { + cb.gen(oinfo); + } + } + } + }); + } + + public void delete(final OpenGLInfo del) { + mH.post(new Runnable() { + @Override + public void run() { + if (del == null) { + return; + } + + for (Callback cb : mCallbackList) { + if (null != cb) { + cb.delete(del); + } + } + } + }); + } + + protected void registerCallback(Callback callback) { + if (null == callback) { + return; + } + mCallbackList.add(callback); + } + + protected void unregisterCallback(Callback callback) { + if (null == callback) { + return; + } + mCallbackList.remove(callback); + } + + interface Callback { + void gen(OpenGLInfo res); + + void delete(OpenGLInfo res); + } + +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java similarity index 70% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java index d3e802d9b..07f14a8e3 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java @@ -1,38 +1,33 @@ -package com.tencent.matrix.openglleak.statistics; +package com.tencent.matrix.openglleak.statistics.source; import android.os.Handler; -import android.os.HandlerThread; + +import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle; +import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; -public class OpenGLResRecorder { - - private List infoList = new ArrayList<>(); - - private static OpenGLResRecorder mInstance = new OpenGLResRecorder(); +@Deprecated +public class ResRecorderForActivityLifecycle implements ResRecordManager.Callback { - private HandlerThread mHandlerThread; + private List infoList = new LinkedList<>(); private Handler mH; private LeakMonitorForActivityLifecycle.LeakListener mListener; - private OpenGLResRecorder() { - mHandlerThread = new HandlerThread("GpuResLeakMonitor"); - mHandlerThread.start(); - - mH = new Handler(mHandlerThread.getLooper()); - } - - public static OpenGLResRecorder getInstance() { - return mInstance; + public ResRecorderForActivityLifecycle() { + mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); + ResRecordManager.getInstance().registerCallback(this); } public void setLeakListener(LeakMonitorForActivityLifecycle.LeakListener mListener) { this.mListener = mListener; } + @Override public void gen(final OpenGLInfo oinfo) { mH.post(new Runnable() { @Override @@ -48,6 +43,7 @@ public void run() { }); } + @Override public void delete(final OpenGLInfo del) { mH.post(new Runnable() { @Override @@ -57,27 +53,7 @@ public void run() { } synchronized (infoList) { - Iterator iterator = infoList.iterator(); - while (iterator.hasNext()) { - OpenGLInfo gen = iterator.next(); - if (gen == null) { - continue; - } - - if ((gen.getType() == del.getType()) && gen.getId() == del.getId()) { - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - if (gen.getEglContextNativeHandle() == del.getEglContextNativeHandle()) { - gen.release(); - iterator.remove(); - break; - } - } else if (gen.getThreadId().equals(del.getThreadId())) { - gen.release(); - iterator.remove(); - break; - } - } - } + infoList.remove(del); } } }); @@ -155,12 +131,6 @@ public void setLeak(OpenGLInfo info) { break; } -// if (isNeedIgnore(info)) { -// item.release(); -// iterator.remove(); -// continue; -// } - if ((item.getType() == info.getType()) && (item.getThreadId().equals(info.getThreadId())) && (item.getId() == info.getId())) { if (mListener != null) { mListener.onLeak(item); @@ -181,10 +151,6 @@ public void setMaybeLeak(OpenGLInfo info) { break; } -// if (isNeedIgnore(info)) { -// continue; -// } - if ((item.getType() == info.getType()) && (item.getThreadId().equals(info.getThreadId())) && (item.getId() == info.getId())) { item.setMaybeLeak(true); info.setMaybeLeak(true); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java new file mode 100644 index 000000000..8760ff23b --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java @@ -0,0 +1,40 @@ +package com.tencent.matrix.openglleak.statistics.source; + +import android.os.Handler; + +import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; + +import java.util.LinkedList; +import java.util.List; + +public class ResRecorderForCustomize implements ResRecordManager.Callback { + + private Handler mH; + + public ResRecorderForCustomize() { + mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); + ResRecordManager.getInstance().registerCallback(this); + } + + private List mList = new LinkedList<>(); + + @Override + public void gen(final OpenGLInfo res) { + mH.post(new Runnable() { + @Override + public void run() { + mList.add(res); + } + }); + } + + @Override + public void delete(final OpenGLInfo res) { + mH.post(new Runnable() { + @Override + public void run() { + mList.remove(res); + } + }); + } +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java new file mode 100644 index 000000000..eb9fd0139 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java @@ -0,0 +1,17 @@ +package com.tencent.matrix.openglleak.utils; + +import android.os.HandlerThread; + +public class GlLeakHandlerThread extends HandlerThread { + + private static GlLeakHandlerThread mInstance = new GlLeakHandlerThread("GpuResLeakMonitor"); + + private GlLeakHandlerThread(String name) { + super(name); + start(); + } + + public static GlLeakHandlerThread getInstance() { + return mInstance; + } +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakMonitorLog.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakLog.java similarity index 96% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakMonitorLog.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakLog.java index adb73990b..5e187a1e3 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakMonitorLog.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakLog.java @@ -1,6 +1,6 @@ package com.tencent.matrix.openglleak.utils; -public class OpenGLLeakMonitorLog { +public class OpenGLLeakLog { private static LogStub stub = null; From 5fce52674fed86db86824b31727629b03819a848 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Tue, 30 Nov 2021 15:54:25 +0800 Subject: [PATCH 027/163] add openGL info stack get together --- .../openglleak/statistics/OpenGLInfo.java | 18 +++ .../statistics/OpenGLResRecorder.java | 142 ++++++++++++++++++ 2 files changed, 160 insertions(+) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index 1901b8385..79d8374e4 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -2,6 +2,8 @@ import android.text.TextUtils; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class OpenGLInfo { @@ -17,6 +19,9 @@ public class OpenGLInfo { private long nativeStackPtr; private boolean genOrDelete; private TYPE type; + // use to dump + private int allocCount = 1; + private List idList = new ArrayList<>(); private boolean isRelease; @@ -119,6 +124,19 @@ public String getNativeStack() { return nativeStack; } + public int getAllocCount() { + return allocCount; + } + + public String getAllocIdList() { + return idList.toString(); + } + + public void incAllocRecord(int id) { + this.allocCount++; + this.idList.add(id); + } + public boolean getMaybeLeak() { return maybeLeak; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index ddac6fdfe..56e1612b3 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -1,12 +1,19 @@ package com.tencent.matrix.openglleak.statistics; +import android.annotation.SuppressLint; import android.os.Handler; import android.os.HandlerThread; import android.text.TextUtils; +import com.tencent.matrix.util.MatrixLog; + import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; public class OpenGLResRecorder { @@ -19,6 +26,8 @@ public class OpenGLResRecorder { private LeakMonitor.LeakListener mListener; + private static final String TAG = "Matrix.OpenGLResRecorder"; + private OpenGLResRecorder() { mHandlerThread = new HandlerThread("GpuResLeakMonitor"); mHandlerThread.start(); @@ -126,6 +135,139 @@ public List getAllHashCode() { return ll; } + public void dumpToFile(String filePath) { + + } + + @SuppressLint("DefaultLocale") + public String dumpToString() { + StringBuilder result = new StringBuilder(); + List openGLInfos = getCopyList(); + if (openGLInfos == null || openGLInfos.size() == 0) { + MatrixLog.e(TAG, "OpenGLResRecorder.getCopyList() is empty, break dump!!!"); + return ""; + } + Map infoMap = new HashMap<>(); + for (int i = 0; i < openGLInfos.size(); i++) { + + OpenGLInfo info = openGLInfos.get(i); + int javaHash = info.getJavaStack().hashCode(); + int nativeHash = info.getNativeStack().hashCode(); + + long infoHash = javaHash + nativeHash; + + OpenGLInfo oldInfo = infoMap.get(infoHash); + if (oldInfo == null) { + infoMap.put(infoHash, info); + } else { + boolean isSameType = info.getType() == oldInfo.getType(); + boolean isSameThread = info.getThreadId().equals(oldInfo.getThreadId()); + boolean isSameEglContext = info.getEglContextNativeHandle() == oldInfo.getEglContextNativeHandle(); + boolean isSameActivity = info.getActivityName().equals(oldInfo.getActivityName()); + + if (isSameType && isSameThread && isSameEglContext && isSameActivity) { + oldInfo.incAllocRecord(info.getId()); + infoMap.put(infoHash, oldInfo); + } + } + + List textureList = new ArrayList<>(); + List bufferList = new ArrayList<>(); + List framebufferList = new ArrayList<>(); + List renderbufferList = new ArrayList<>(); + + for (OpenGLInfo openGLInfo : infoMap.values()) { + if (openGLInfo.getType() == OpenGLInfo.TYPE.TEXTURE) { + textureList.add(openGLInfo); + } + if (openGLInfo.getType() == OpenGLInfo.TYPE.BUFFER) { + bufferList.add(openGLInfo); + } + if (openGLInfo.getType() == OpenGLInfo.TYPE.FRAME_BUFFERS) { + framebufferList.add(openGLInfo); + } + if (openGLInfo.getType() == OpenGLInfo.TYPE.RENDER_BUFFERS) { + renderbufferList.add(openGLInfo); + } + } + + Comparator comparator = new Comparator() { + @Override + public int compare(OpenGLInfo o1, OpenGLInfo o2) { + return o1.getAllocCount() - o2.getAllocCount(); + } + }; + + Collections.sort(textureList, comparator); + Collections.sort(bufferList, comparator); + Collections.sort(framebufferList, comparator); + Collections.sort(renderbufferList, comparator); + + final String dottedLine = "-------------------------------------------------------------------------"; + final String waveLine = "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"; + + result.append(dottedLine) + .append(String.format("\t\t\ttextures Count = %d", textureList.size())) + .append(String.format("\t\t\tbuffer Count = %d", bufferList.size())) + .append(String.format("\t\t\tframebuffer Count = %d", framebufferList.size())) + .append(String.format("\t\t\trenderbuffer Count = %d", renderbufferList.size())) + .append(dottedLine) + .append("\n") + .append(waveLine) + .append("\n") + .append("\t\t\ttexture part :") + .append(waveLine) + .append("\n") + .append(getResListString(textureList)) + .append('\n') + .append(waveLine) + .append("\t\t\tbuffers part :") + .append(waveLine) + .append("\n") + .append(getResListString(bufferList)) + .append("\n") + .append(waveLine) + .append("\n") + .append("\t\t\tframebuffers part :") + .append(waveLine) + .append("\n") + .append(getResListString(framebufferList)) + .append("\n") + .append(waveLine) + .append("\n") + .append("\t\t\trenderbuffer part :") + .append(waveLine) + .append("\n"); + } + return result.toString(); + } + + @SuppressLint("DefaultLocale") + private String getResListString(List resList) { + if (resList == null || resList.size() == 0) { + return ""; + } + + StringBuilder result = new StringBuilder(); + for (OpenGLInfo res : resList) { + result.append(String.format(" alloc count = %d", res.getAllocCount())) + .append("\n") + .append(String.format(" id = %s", res.getAllocIdList())) + .append("\n") + .append(String.format(" activity = %s", res.getActivityName())) + .append("\n") + .append(String.format(" type = %s", res.getType())) + .append("\n") + .append(String.format(" eglContext = %s", res.getEglContextNativeHandle())) + .append("\n") + .append(String.format(" java stack = %s", res.getJavaStack())) + .append("\n") + .append(String.format(" native stack = %s", res.getNativeStack())) + .append("\n"); + } + return result.toString(); + } + public void getNativeStack(OpenGLInfo info) { synchronized (infoList) { for (OpenGLInfo item : infoList) { From b4747898593f130c27e8e48b949796443f2faef9 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Tue, 30 Nov 2021 19:21:30 +0800 Subject: [PATCH 028/163] add dump to file --- .../statistics/OpenGLResRecorder.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 56e1612b3..17ce4dcfb 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -4,9 +4,15 @@ import android.os.Handler; import android.os.HandlerThread; import android.text.TextUtils; +import android.util.Log; import com.tencent.matrix.util.MatrixLog; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -135,10 +141,29 @@ public List getAllHashCode() { return ll; } + @SuppressLint("LongLogTag") public void dumpToFile(String filePath) { + File targetFile = new File(filePath); + + if (targetFile.exists()) { + targetFile.delete(); + } + + try { + targetFile.createNewFile(); + } catch (IOException e) { + Log.e(TAG, "[OpenGLResRecorder]: createNewFile Fail, filePath = " + filePath); + } + + try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile)))) { + writer.write(dumpToString()); + } catch (IOException e) { + Log.e(TAG, "[OpenGLResRecorder]: Create Stream Fail"); + } } + @SuppressLint("DefaultLocale") public String dumpToString() { StringBuilder result = new StringBuilder(); From 3ae6d540ccf1b31ad289dac996c7f9d3d0a3a064 Mon Sep 17 00:00:00 2001 From: opdeng Date: Tue, 30 Nov 2021 20:17:47 +0800 Subject: [PATCH 029/163] =?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...atrix_openglleak_statistics_OpenGLInfo.cpp | 4 +- .../matrix/openglleak/OpenglLeakPlugin.java | 11 +- .../matrix/openglleak/hook/OpenGLHook.java | 10 +- .../statistics/CustomizeLeakMonitor.java | 26 ++ .../statistics/LeakMonitorDefault.java | 71 +++++ .../LeakMonitorForActivityLifecycle.java | 286 ++++++++---------- .../LeakMonitorForActivityLifecycle_Old.java | 235 ++++++++++++++ .../statistics/LeakMonitorForCustomize.java | 4 - .../statistics/source/OpenGLInfo.java | 42 +-- .../statistics/source/ResRecordManager.java | 38 ++- .../ResRecorderForActivityLifecycle.java | 6 +- .../source/ResRecorderForCustomize.java | 54 +++- .../openglleak/utils/GlLeakHandlerThread.java | 1 - 13 files changed, 556 insertions(+), 232 deletions(-) create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle_Old.java delete mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForCustomize.java diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp index f2ee50de2..6efe732d0 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp @@ -59,7 +59,7 @@ void get_native_stack(wechat_backtrace::Backtrace* backtrace, char *&stack) { } -extern "C" JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_OpenGLInfo_releaseNative +extern "C" JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_source_OpenGLInfo_releaseNative (JNIEnv *env, jobject thiz, jlong jl) { int64_t addr = jl; @@ -67,7 +67,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_ delete ptr; } -extern "C" JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_OpenGLInfo_dumpNativeStack +extern "C" JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_source_OpenGLInfo_dumpNativeStack (JNIEnv *env, jobject thiz, jlong jl) { int64_t addr = jl; wechat_backtrace::Backtrace* ptr = (wechat_backtrace::Backtrace*)addr; 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 3f568f561..6d03f701c 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 @@ -12,8 +12,9 @@ import com.tencent.matrix.openglleak.detector.IOpenglIndexDetector; import com.tencent.matrix.openglleak.detector.OpenglIndexDetectorService; import com.tencent.matrix.openglleak.hook.OpenGLHook; -import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle; +import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle_Old; import com.tencent.matrix.openglleak.utils.EGLHelper; +import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; import com.tencent.matrix.plugin.Plugin; import com.tencent.matrix.plugin.PluginListener; import com.tencent.matrix.util.MatrixLog; @@ -43,6 +44,8 @@ public void registerReportCallback(OpenglReportCallback callback) { @Override public void init(Application app, PluginListener listener) { super.init(app, listener); + + GlLeakHandlerThread.getInstance().start(); } @Override @@ -102,7 +105,7 @@ private void executeHook(IBinder iBinder) { MatrixLog.e(TAG, "hook finish"); // 泄漏监控 - LeakMonitorForActivityLifecycle.getInstance().start((Application) context.getApplicationContext()); + LeakMonitorForActivityLifecycle_Old.getInstance().start((Application) context.getApplicationContext()); } catch (Throwable e) { e.printStackTrace(); } finally { @@ -171,8 +174,4 @@ public void setJavaStackDump(boolean open) { OpenGLHook.getInstance().setJavaStackDump(true); } - public void setDoubleCheckTime(long time) { - LeakMonitorForActivityLifecycle.getInstance().setDoubleCheckTime(time); - } - } 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 73d01b7fd..305b63dbb 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 @@ -3,7 +3,7 @@ import android.opengl.EGL14; import com.tencent.matrix.openglleak.comm.FuncNameString; -import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle; +import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle_Old; import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.source.ResRecordManager; @@ -89,7 +89,7 @@ public static void onGlGenTextures(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle_Old.getInstance().getCurrentActivityName(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -128,7 +128,7 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle_Old.getInstance().getCurrentActivityName(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -167,7 +167,7 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle_Old.getInstance().getCurrentActivityName(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -206,7 +206,7 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle_Old.getInstance().getCurrentActivityName(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java new file mode 100644 index 000000000..d454d588c --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java @@ -0,0 +1,26 @@ +package com.tencent.matrix.openglleak.statistics; + +import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; +import com.tencent.matrix.openglleak.statistics.source.ResRecorderForCustomize; + +import java.util.List; + +public class CustomizeLeakMonitor { + + private ResRecorderForCustomize mResRecorder; + + public CustomizeLeakMonitor() { + mResRecorder = new ResRecorderForCustomize(); + } + + public void checkStart() { + mResRecorder.clear(); + mResRecorder.start(); + } + + public List checkEnd() { + mResRecorder.end(); + return mResRecorder.getCopyList(); + } + +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java new file mode 100644 index 000000000..bf37cfa5c --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java @@ -0,0 +1,71 @@ +package com.tencent.matrix.openglleak.statistics; + +import android.os.Handler; + +import com.tencent.matrix.AppActiveMatrixDelegate; +import com.tencent.matrix.listeners.IAppForeground; +import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; +import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; + +import java.util.List; + +public class LeakMonitorDefault extends CustomizeLeakMonitor implements IAppForeground { + + private static final long CHECK_TIME = 1000L * 30; + + private Handler mH; + private LeakListener mLeakListener; + + private static LeakMonitorDefault mInstance = new LeakMonitorDefault(); + + private LeakMonitorDefault() { + mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); + } + + public void setLeakListener(LeakListener l) { + mLeakListener = l; + } + + public void start() { + AppActiveMatrixDelegate.INSTANCE.addListener(this); + } + + @Override + public void onForeground(boolean isForeground) { + if (isForeground) { + foreground(); + } else { + background(); + } + } + + private Runnable mRunnable = new Runnable() { + @Override + public void run() { + List leaks = checkEnd(); + + if (null == mLeakListener) { + return; + } + + for (OpenGLInfo item : leaks) { + if (null != item) { + mLeakListener.onLeak(item); + } + } + } + }; + + public void foreground() { + checkStart(); + mH.removeCallbacks(mRunnable); + } + + public void background() { + mH.postDelayed(mRunnable, CHECK_TIME); + } + + public interface LeakListener { + void onLeak(OpenGLInfo info); + } +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java index 325c965eb..eaf537b41 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java @@ -2,234 +2,206 @@ import android.app.Activity; import android.app.Application; -import android.os.Build; import android.os.Bundle; import android.os.Handler; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; -import com.tencent.matrix.openglleak.statistics.source.ResRecorderForActivityLifecycle; +import com.tencent.matrix.openglleak.statistics.source.ResRecordManager; import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; import com.tencent.matrix.util.MatrixLog; -import java.lang.ref.WeakReference; -import java.util.HashMap; +import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.Set; -@Deprecated public class LeakMonitorForActivityLifecycle implements Application.ActivityLifecycleCallbacks { - private static final String TAG = "matrix.GPU_LeakMonitor"; - private static LeakMonitorForActivityLifecycle mInstance = new LeakMonitorForActivityLifecycle(); + private static final String TAG = "matrix.LeakMonitorForActivityLifecycle"; private Handler mH; + private List mActivityLeakMonitor; + private List mMaybeLeakList; + private LeakListener mLeakListener; - private Map, List> maps = new HashMap<>(); - private String currentActivityName = ""; - - private ResRecorderForActivityLifecycle mResRecorder = new ResRecorderForActivityLifecycle(); - - private long mDoubleCheckTime = 1000 * 60 * 30; - private final long mDoubleCheckLooper = 1000 * 60 * 1; + private static final long DOUBLE_CHECK_TIME = 0L; + private static final long DOUBLE_CHECK_LOOPER = 1000L * 60 * 1; - protected LeakMonitorForActivityLifecycle() { + public LeakMonitorForActivityLifecycle() { mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); - mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); - } - - public static LeakMonitorForActivityLifecycle getInstance() { - return mInstance; - } + mActivityLeakMonitor = new LinkedList<>(); + mMaybeLeakList = new LinkedList<>(); - public void setDoubleCheckTime(long doubleCheckTime) { - mDoubleCheckTime = doubleCheckTime; - } - - public void setListener(LeakListener l) { - mResRecorder.setLeakListener(l); + mH.postDelayed(mDoubleCheck, DOUBLE_CHECK_LOOPER); } public void start(Application context) { MatrixLog.i(TAG, "start"); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - (context).registerActivityLifecycleCallbacks(mInstance); - } + context.registerActivityLifecycleCallbacks(this); } - public String getCurrentActivityName() { - return currentActivityName; + public void stop(Application context) { + context.unregisterActivityLifecycleCallbacks(this); } @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - currentActivityName = activity.getLocalClassName(); - - MatrixLog.i(TAG, "activity oncreate:" + currentActivityName + " :" + activity.hashCode()); + public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) { + ActivityLeakMonitor activityLeakMonitor = new ActivityLeakMonitor(activity.hashCode(), new CustomizeLeakMonitor()); + activityLeakMonitor.start(); - WeakReference weakReference = new WeakReference<>(activity); - List actvityList = mResRecorder.getAllHashCode(); - - maps.put(weakReference, actvityList); + synchronized (mActivityLeakMonitor) { + mActivityLeakMonitor.add(activityLeakMonitor); + } } @Override - public void onActivityDestroyed(Activity activity) { - MatrixLog.i(TAG, - "activity ondestroy:" + activity.getLocalClassName() + " :" + activity.hashCode()); - - WeakReference target = null; - - Set mapSet = maps.keySet(); - Iterator it = mapSet.iterator(); - while (it.hasNext()) { - WeakReference weakReference = (WeakReference) it.next(); - - Activity a = (Activity) weakReference.get(); - if (a == null) { - // 空的话移除 - it.remove(); - continue; - } - - if ((a == activity)) { - target = weakReference; - break; - } - } - - // 找不到,跳过不处理 - if (target == null) { - return; - } - - String activityName = ""; - Activity aa = target.get(); - if (aa != null) { - activityName = aa.getLocalClassName(); - } + public void onActivityDestroyed(@NonNull Activity activity) { + Integer activityHashCode = activity.hashCode(); + + synchronized (mActivityLeakMonitor) { + Iterator it = mActivityLeakMonitor.iterator(); + while (it.hasNext()) { + ActivityLeakMonitor item = it.next(); + if (null == item) { + continue; + } - final String activityStr = activityName; - final List createList = maps.get(target); - final List destroyList = mResRecorder.getAllHashCode(); + if (item.getActivityHashCode() == activityHashCode) { + it.remove(); + + List leaks = item.end(); + if (null != mLeakListener) { + for (OpenGLInfo leakItem : leaks) { + if (null != leakItem) { + mLeakListener.onMaybeLeak(leakItem); + + synchronized (mMaybeLeakList) { + // 可能泄漏,需要做 double check + mMaybeLeakList.add(new MaybeLeakOpenGLInfo(leakItem)); + } + } + } + } - mH.post(new Runnable() { - @Override - public void run() { - boolean result = findLeak(createList, destroyList); - if (result) { - MatrixLog.i(TAG, activityStr + " leak! "); + break; } } - }); - - // clear - maps.remove(target); + } } - private boolean findLeak(List createList, List destroyList) { - if ((createList == null) || (destroyList == null)) { - return false; - } + public void setLeakListener(LeakMonitorForActivityLifecycle.LeakListener l) { + mLeakListener = l; + } - boolean hasLeak = false; + private Runnable mDoubleCheck = new Runnable() { + @Override + public void run() { + long now = System.currentTimeMillis(); - for (Integer destroy : destroyList) { - if (destroy == null) { - continue; - } + synchronized (mMaybeLeakList) { + Iterator it = mMaybeLeakList.iterator(); + while (it.hasNext()) { + MaybeLeakOpenGLInfo item = it.next(); + if (null == item) { + continue; + } - boolean isLeak; - int i = 0; - for (Integer create : createList) { - if (create == null) { - i = i + 1; - continue; - } + if ((now - item.getMaybeLeakTime()) > DOUBLE_CHECK_TIME) { + it.remove(); - if (create.intValue() == destroy.intValue()) { - break; + if (null != mLeakListener) { + if (ResRecordManager.getInstance().isGLInfoRelease(item)) { + mLeakListener.onLeak(item); + } + } + } } - - i = i + 1; - } - - if (i == createList.size()) { - isLeak = true; - } else { - isLeak = false; } - if (isLeak) { - OpenGLInfo leakInfo = mResRecorder.getItemByHashCode(destroy); - - if ((leakInfo != null) && !leakInfo.getMaybeLeak()) { - mResRecorder.getNativeStack(leakInfo); - mResRecorder.setMaybeLeak(leakInfo); - - hasLeak = true; - } - } + mH.postDelayed(mDoubleCheck, DOUBLE_CHECK_LOOPER); } - - return hasLeak; - } + }; @Override - public void onActivityStarted(Activity activity) { + public void onActivityStarted(@NonNull Activity activity) { } @Override - public void onActivityResumed(Activity activity) { - currentActivityName = activity.getLocalClassName(); + public void onActivityResumed(@NonNull Activity activity) { + } @Override - public void onActivityPaused(Activity activity) { + public void onActivityPaused(@NonNull Activity activity) { } @Override - public void onActivityStopped(Activity activity) { + public void onActivityStopped(@NonNull Activity activity) { } @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) { } - public interface LeakListener { - void onMaybeLeak(OpenGLInfo info); + class ActivityLeakMonitor { + private int mActivityHashCode; + private CustomizeLeakMonitor mMonitor; - void onLeak(OpenGLInfo info); + ActivityLeakMonitor(int hashcode, CustomizeLeakMonitor m) { + mActivityHashCode = hashcode; + mMonitor = m; + } + + void start() { + if (null != mMonitor) { + mMonitor.checkStart(); + } + } + + List end() { + List ret = new ArrayList<>(); + if (null == mMonitor) { + return ret; + } + + ret.addAll(mMonitor.checkEnd()); + + return ret; + } + + int getActivityHashCode() { + return mActivityHashCode; + } } - private Runnable doubleCheckRunnable = new Runnable() { - @Override - public void run() { - long now = System.currentTimeMillis(); + class MaybeLeakOpenGLInfo extends OpenGLInfo { - List copyList = mResRecorder.getCopyList(); - MatrixLog.i(TAG, "double check list size:" + copyList.size()); + long mMaybeLeakTime; - for (OpenGLInfo item : copyList) { - if (item == null) { - continue; - } + MaybeLeakOpenGLInfo(OpenGLInfo clone) { + super(clone); + } - if (item.getMaybeLeak()) { - if ((now - item.getMaybeLeakTime()) > mDoubleCheckTime) { - mResRecorder.setLeak(item); - mResRecorder.remove(item); - } - } - } + void setMaybeLeakTime(long t) { + mMaybeLeakTime = t; + } - mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); + long getMaybeLeakTime(long t) { + return mMaybeLeakTime; } - }; + } + + public interface LeakListener { + void onMaybeLeak(OpenGLInfo info); + + void onLeak(OpenGLInfo info); + } + } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle_Old.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle_Old.java new file mode 100644 index 000000000..6507007d8 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle_Old.java @@ -0,0 +1,235 @@ +package com.tencent.matrix.openglleak.statistics; + +import android.app.Activity; +import android.app.Application; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; + +import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; +import com.tencent.matrix.openglleak.statistics.source.ResRecorderForActivityLifecycle; +import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; +import com.tencent.matrix.util.MatrixLog; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Deprecated +public class LeakMonitorForActivityLifecycle_Old extends CustomizeLeakMonitor implements Application.ActivityLifecycleCallbacks { + + private static final String TAG = "matrix.GPU_LeakMonitor"; + private static LeakMonitorForActivityLifecycle_Old mInstance = new LeakMonitorForActivityLifecycle_Old(); + + private Handler mH; + + private Map, List> maps = new HashMap<>(); + private String currentActivityName = ""; + + private ResRecorderForActivityLifecycle mResRecorder = new ResRecorderForActivityLifecycle(); + + private long mDoubleCheckTime = 1000 * 60 * 30; + private final long mDoubleCheckLooper = 1000 * 60 * 1; + + protected LeakMonitorForActivityLifecycle_Old() { + mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); + mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); + } + + public static LeakMonitorForActivityLifecycle_Old getInstance() { + return mInstance; + } + + public void setDoubleCheckTime(long doubleCheckTime) { + mDoubleCheckTime = doubleCheckTime; + } + + public void setListener(LeakListener l) { + mResRecorder.setLeakListener(l); + } + + public void start(Application context) { + MatrixLog.i(TAG, "start"); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + (context).registerActivityLifecycleCallbacks(mInstance); + } + } + + public String getCurrentActivityName() { + return currentActivityName; + } + + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + currentActivityName = activity.getLocalClassName(); + + MatrixLog.i(TAG, "activity oncreate:" + currentActivityName + " :" + activity.hashCode()); + + WeakReference weakReference = new WeakReference<>(activity); + List actvityList = mResRecorder.getAllHashCode(); + + maps.put(weakReference, actvityList); + } + + @Override + public void onActivityDestroyed(Activity activity) { + MatrixLog.i(TAG, + "activity ondestroy:" + activity.getLocalClassName() + " :" + activity.hashCode()); + + WeakReference target = null; + + Set mapSet = maps.keySet(); + Iterator it = mapSet.iterator(); + while (it.hasNext()) { + WeakReference weakReference = (WeakReference) it.next(); + + Activity a = (Activity) weakReference.get(); + if (a == null) { + // 空的话移除 + it.remove(); + continue; + } + + if ((a == activity)) { + target = weakReference; + break; + } + } + + // 找不到,跳过不处理 + if (target == null) { + return; + } + + String activityName = ""; + Activity aa = target.get(); + if (aa != null) { + activityName = aa.getLocalClassName(); + } + + final String activityStr = activityName; + final List createList = maps.get(target); + final List destroyList = mResRecorder.getAllHashCode(); + + mH.post(new Runnable() { + @Override + public void run() { + boolean result = findLeak(createList, destroyList); + if (result) { + MatrixLog.i(TAG, activityStr + " leak! "); + } + } + }); + + // clear + maps.remove(target); + } + + private boolean findLeak(List createList, List destroyList) { + if ((createList == null) || (destroyList == null)) { + return false; + } + + boolean hasLeak = false; + + for (Integer destroy : destroyList) { + if (destroy == null) { + continue; + } + + boolean isLeak; + int i = 0; + for (Integer create : createList) { + if (create == null) { + i = i + 1; + continue; + } + + if (create.intValue() == destroy.intValue()) { + break; + } + + i = i + 1; + } + + if (i == createList.size()) { + isLeak = true; + } else { + isLeak = false; + } + + if (isLeak) { + OpenGLInfo leakInfo = mResRecorder.getItemByHashCode(destroy); + + if ((leakInfo != null) && !leakInfo.getMaybeLeak()) { + mResRecorder.getNativeStack(leakInfo); + mResRecorder.setMaybeLeak(leakInfo); + + hasLeak = true; + } + } + } + + return hasLeak; + } + + @Override + public void onActivityStarted(Activity activity) { + + } + + @Override + public void onActivityResumed(Activity activity) { + currentActivityName = activity.getLocalClassName(); + } + + @Override + public void onActivityPaused(Activity activity) { + + } + + @Override + public void onActivityStopped(Activity activity) { + + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + + } + + public interface LeakListener { + void onMaybeLeak(OpenGLInfo info); + + void onLeak(OpenGLInfo info); + } + + private Runnable doubleCheckRunnable = new Runnable() { + @Override + public void run() { + long now = System.currentTimeMillis(); + + List copyList = mResRecorder.getCopyList(); + MatrixLog.i(TAG, "double check list size:" + copyList.size()); + + for (OpenGLInfo item : copyList) { + if (item == null) { + continue; + } + + if (item.getMaybeLeak()) { + if ((now - item.getMaybeLeakTime()) > mDoubleCheckTime) { + mResRecorder.setLeak(item); + mResRecorder.remove(item); + } + } + } + + mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); + } + }; +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForCustomize.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForCustomize.java deleted file mode 100644 index 02503874f..000000000 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForCustomize.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.tencent.matrix.openglleak.statistics; - -public class LeakMonitorForCustomize { -} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java index c91818758..a33db0c37 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java @@ -19,16 +19,12 @@ public class OpenGLInfo { private boolean genOrDelete; private TYPE type; - private boolean isRelease; - private boolean maybeLeak = false; private long maybeLeakCheckTime = 0L; private boolean isReported = false; private String activityName; - private AtomicInteger counter; - public enum TYPE { TEXTURE, BUFFER, FRAME_BUFFERS, RENDER_BUFFERS } @@ -43,12 +39,10 @@ public OpenGLInfo(OpenGLInfo clone) { this.nativeStackPtr = clone.nativeStackPtr; this.genOrDelete = clone.genOrDelete; this.type = clone.type; - this.isRelease = clone.isRelease; this.maybeLeakCheckTime = clone.maybeLeakCheckTime; this.isReported = clone.isReported; this.maybeLeak = clone.maybeLeak; this.activityName = clone.activityName; - this.counter = clone.counter; } public OpenGLInfo(int error) { @@ -72,7 +66,6 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.genOrDelete = genOrDelete; this.type = type; this.activityName = activityName; - this.counter = counter; } public int getId() { @@ -105,16 +98,10 @@ public String getJavaStack() { public String getNativeStack() { if (TextUtils.isEmpty(nativeStack)) { - if (!isRelease) { - synchronized (counter) { - if (counter.get() > 0) { - if (this.nativeStackPtr != 0) { - nativeStack = dumpNativeStack(this.nativeStackPtr); - } else { - nativeStack = ""; - } - } - } + if (this.nativeStackPtr != 0) { + nativeStack = dumpNativeStack(this.nativeStackPtr); + } else { + nativeStack = ""; } } return nativeStack; @@ -144,24 +131,12 @@ public void setMaybeLeakCheckTime(long time) { this.maybeLeakCheckTime = time; } - public void release() { - if (isRelease) { - return; - } - isRelease = true; - + protected void release() { if (nativeStackPtr == 0) { return; } - synchronized (counter) { - int count = counter.get(); - if (count == 1) { - releaseNative(nativeStackPtr); - } - - counter.set(count - 1); - } + releaseNative(nativeStackPtr); } private native void releaseNative(long nativeStackPtr); @@ -200,9 +175,4 @@ public int hashCode() { return Objects.hash(id, threadId, eglContextNativeHandle, type); } - @Override - protected void finalize() throws Throwable { - release(); - super.finalize(); - } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java index 0d4c2940b..e1bfed0a5 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java @@ -14,6 +14,7 @@ public class ResRecordManager { private Handler mH; private List mCallbackList = new LinkedList<>(); + private List mInfoList = new LinkedList<>(); private ResRecordManager() { mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); @@ -23,17 +24,21 @@ public static ResRecordManager getInstance() { return mInstance; } - public void gen(final OpenGLInfo oinfo) { + public void gen(final OpenGLInfo gen) { mH.post(new Runnable() { @Override public void run() { - if (oinfo == null) { + if (gen == null) { return; } + synchronized (mInfoList) { + mInfoList.add(gen); + } + for (Callback cb : mCallbackList) { if (null != cb) { - cb.gen(oinfo); + cb.gen(gen); } } } @@ -48,6 +53,22 @@ public void run() { return; } + synchronized (mInfoList) { + // 之前可能释放过 + int index = mInfoList.indexOf(del); + if (-1 == index) { + return; + } + + OpenGLInfo info = mInfoList.get(index); + if (null == info) { + return; + } + + info.release(); + mInfoList.remove(del); + } + for (Callback cb : mCallbackList) { if (null != cb) { cb.delete(del); @@ -61,6 +82,11 @@ protected void registerCallback(Callback callback) { if (null == callback) { return; } + + if (mCallbackList.contains(callback)) { + return; + } + mCallbackList.add(callback); } @@ -71,6 +97,12 @@ protected void unregisterCallback(Callback callback) { mCallbackList.remove(callback); } + public boolean isGLInfoRelease(OpenGLInfo item) { + synchronized (mInfoList) { + return !mInfoList.contains(item); + } + } + interface Callback { void gen(OpenGLInfo res); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java index 07f14a8e3..533c39b46 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java @@ -2,7 +2,7 @@ import android.os.Handler; -import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle; +import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle_Old; import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; import java.util.ArrayList; @@ -16,14 +16,14 @@ public class ResRecorderForActivityLifecycle implements ResRecordManager.Callbac private List infoList = new LinkedList<>(); private Handler mH; - private LeakMonitorForActivityLifecycle.LeakListener mListener; + private LeakMonitorForActivityLifecycle_Old.LeakListener mListener; public ResRecorderForActivityLifecycle() { mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); ResRecordManager.getInstance().registerCallback(this); } - public void setLeakListener(LeakMonitorForActivityLifecycle.LeakListener mListener) { + public void setLeakListener(LeakMonitorForActivityLifecycle_Old.LeakListener mListener) { this.mListener = mListener; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java index 8760ff23b..27b43f84f 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java @@ -4,37 +4,61 @@ import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class ResRecorderForCustomize implements ResRecordManager.Callback { - private Handler mH; - public ResRecorderForCustomize() { - mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); - ResRecordManager.getInstance().registerCallback(this); } private List mList = new LinkedList<>(); + public void start() { + ResRecordManager.getInstance().registerCallback(this); + } + + public void end() { + ResRecordManager.getInstance().unregisterCallback(this); + } + @Override public void gen(final OpenGLInfo res) { - mH.post(new Runnable() { - @Override - public void run() { - mList.add(res); - } - }); + synchronized (mList) { + mList.add(res); + } } @Override public void delete(final OpenGLInfo res) { - mH.post(new Runnable() { - @Override - public void run() { - mList.remove(res); + synchronized (mList) { + mList.remove(res); + } + } + + public List getCopyList() { + List ll = new ArrayList<>(); + + synchronized (mList) { + for (OpenGLInfo item : mList) { + if (item == null) { + break; + } + + OpenGLInfo clone = new OpenGLInfo(item); + ll.add(clone); + } + } + + return ll; + } + + public void clear() { + synchronized (mList) { + if (null != mList) { + mList.clear(); } - }); + } } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java index eb9fd0139..707993f25 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java @@ -8,7 +8,6 @@ public class GlLeakHandlerThread extends HandlerThread { private GlLeakHandlerThread(String name) { super(name); - start(); } public static GlLeakHandlerThread getInstance() { From 7cab57c1a4d54e4d5463caa767fca50383e899ce Mon Sep 17 00:00:00 2001 From: yvesluo Date: Tue, 30 Nov 2021 21:09:11 +0800 Subject: [PATCH 030/163] resource-canary: remove manufacture dependency --- .../matrix/resource/CanaryWorkerService.java | 11 ++++++----- .../matrix/resource/config/ResourceConfig.java | 16 ++++++++++++++-- .../resource/processor/BaseLeakProcessor.java | 7 +++++-- 3 files changed, 25 insertions(+), 9 deletions(-) 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 4eaabf501..6322137d1 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 @@ -16,13 +16,17 @@ package com.tencent.matrix.resource; +import static com.tencent.matrix.resource.common.utils.StreamUtil.closeQuietly; +import static com.tencent.matrix.resource.common.utils.StreamUtil.copyFileToStream; + import android.content.Context; import android.content.Intent; import android.os.Build; +import com.tencent.matrix.Matrix; import com.tencent.matrix.resource.analyzer.model.HeapDump; -import com.tencent.matrix.resource.hproflib.HprofBufferShrinker; import com.tencent.matrix.resource.dumper.DumpStorageManager; +import com.tencent.matrix.resource.hproflib.HprofBufferShrinker; import com.tencent.matrix.util.MatrixLog; import java.io.BufferedOutputStream; @@ -38,9 +42,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import static com.tencent.matrix.resource.common.utils.StreamUtil.closeQuietly; -import static com.tencent.matrix.resource.common.utils.StreamUtil.copyFileToStream; - /** * Created by tangyinsheng on 2017/7/11. * @@ -100,7 +101,7 @@ private void doShrinkHprofAndReport(HeapDump heapDump) { final PrintWriter pw = new PrintWriter(new OutputStreamWriter(zos, Charset.forName("UTF-8"))); pw.println("# Resource Canary Result Infomation. THIS FILE IS IMPORTANT FOR THE ANALYZER !!"); pw.println("sdkVersion=" + Build.VERSION.SDK_INT); - pw.println("manufacturer=" + Build.MANUFACTURER); + pw.println("manufacturer=" + Matrix.with().getPluginByClass(ResourcePlugin.class).getConfig().getManufacture()); pw.println("hprofEntry=" + shrinkedHProfEntry.getName()); pw.println("leakedActivityKey=" + heapDump.getReferenceKey()); pw.flush(); diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/ResourceConfig.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/ResourceConfig.java index 32f907e43..ba9836095 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/ResourceConfig.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/ResourceConfig.java @@ -45,12 +45,14 @@ public enum DumpMode { private final DumpMode mDumpHprofMode; private final boolean mDetectDebugger; private final String mTargetActivity; + private final String mManufacture; - private ResourceConfig(IDynamicConfig dynamicConfig, DumpMode dumpHprofMode, boolean detectDebuger, String targetActivity) { + private ResourceConfig(IDynamicConfig dynamicConfig, DumpMode dumpHprofMode, boolean detectDebuger, String targetActivity, String manufacture) { this.mDynamicConfig = dynamicConfig; this.mDumpHprofMode = dumpHprofMode; this.mDetectDebugger = detectDebuger; this.mTargetActivity = targetActivity; + this.mManufacture = manufacture; } public long getScanIntervalMillis() { @@ -77,12 +79,17 @@ public boolean getDetectDebugger() { return mDetectDebugger; } + public String getManufacture() { + return mManufacture; + } + public static final class Builder { private DumpMode mDefaultDumpHprofMode = DEFAULT_DUMP_HPROF_MODE; private IDynamicConfig dynamicConfig; private String mTargetActivity; private boolean mDetectDebugger = false; + private String mManufacture; public Builder dynamicConfig(IDynamicConfig dynamicConfig) { this.dynamicConfig = dynamicConfig; @@ -104,8 +111,13 @@ public Builder setManualDumpTargetActivity(String targetActivity) { return this; } + public Builder setManufacture(String manufacture) { + mManufacture = manufacture; + return this; + } + public ResourceConfig build() { - return new ResourceConfig(dynamicConfig, mDefaultDumpHprofMode, mDetectDebugger, mTargetActivity); + return new ResourceConfig(dynamicConfig, mDefaultDumpHprofMode, mDetectDebugger, mTargetActivity, mManufacture); } } } 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 7d67aebe1..ea5313ac6 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 @@ -2,8 +2,10 @@ import android.os.Build; +import com.tencent.matrix.Matrix; import com.tencent.matrix.report.Issue; import com.tencent.matrix.resource.CanaryWorkerService; +import com.tencent.matrix.resource.ResourcePlugin; import com.tencent.matrix.resource.analyzer.ActivityLeakAnalyzer; import com.tencent.matrix.resource.analyzer.model.ActivityLeakResult; import com.tencent.matrix.resource.analyzer.model.AndroidExcludedRefs; @@ -13,9 +15,9 @@ import com.tencent.matrix.resource.analyzer.model.HeapSnapshot; import com.tencent.matrix.resource.config.ResourceConfig; import com.tencent.matrix.resource.config.SharePluginInfo; -import com.tencent.matrix.resource.watcher.ActivityRefWatcher; 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; import org.json.JSONException; @@ -79,7 +81,8 @@ public void onDestroy() { protected ActivityLeakResult analyze(File hprofFile, String referenceKey) { final HeapSnapshot heapSnapshot; ActivityLeakResult result; - final ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults(Build.VERSION.SDK_INT, Build.MANUFACTURER).build(); + String manufacture = Matrix.with().getPluginByClass(ResourcePlugin.class).getConfig().getManufacture(); + final ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults(Build.VERSION.SDK_INT, manufacture).build(); try { heapSnapshot = new HeapSnapshot(hprofFile); result = new ActivityLeakAnalyzer(referenceKey, excludedRefs).analyze(heapSnapshot); From 26b4f20ced1c18b7fc516a052b0ac168318e9457 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 2 Sep 2021 20:02:52 +0800 Subject: [PATCH 031/163] add hook glTexImage2D --- ..._matrix_openglleak_detector_FuncSeeker.cpp | 60 +++++++++++++++++++ ...nt_matrix_openglleak_detector_FuncSeeker.h | 9 +++ ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 17 ++++++ .../src/main/cpp/my_functions.h | 16 +++++ .../matrix-opengl-leak/src/main/cpp/type.h | 3 + .../matrix/openglleak/OpenglLeakPlugin.java | 4 +- .../openglleak/comm/FuncNameString.java | 2 + .../openglleak/detector/FuncSeeker.java | 8 +++ .../detector/OpenglIndexDetectorService.java | 8 ++- .../matrix/openglleak/hook/OpenGLHook.java | 4 ++ .../matrix/openglleak/utils/EGLHelper.java | 5 ++ 11 files changed, 134 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp index 04d8ab7b2..d864ef550 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp @@ -125,5 +125,65 @@ JNICALL Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlGetErrorInde int result = i_glGetError; i_glGetError = 0; + return result; +} + +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getBindFuncIndex(JNIEnv *env, jclass clazz, + jstring bind_func_name) { + return 0; +} + +static System_GlTexImage2D _system_glTexImage2D = NULL; +static int i_glTexImage2D = 0; +static bool has_hook_glTexImage2D = false; + +GL_APICALL void GL_APIENTRY _my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const void *pixels) { + if (!has_hook_glTexImage2D) { + has_hook_glTexImage2D = true; + } + + _system_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); +} + + +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage2DIndex(JNIEnv *env, jclass clazz) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return -1; + } + + for (i_glTexImage2D = 0; i_glTexImage2D < 1000; i_glTexImage2D++) { + if (has_hook_glTexImage2D) { + i_glTexImage2D = i_glTexImage2D - 1; + + void **method = (void **) (&hooks->gl.foo1 + i_glTexImage2D); + *method = (void *) _system_glTexImage2D; + break; + } + + if (_system_glTexImage2D != NULL) { + void **method = (void **) (&hooks->gl.foo1 + (i_glTexImage2D - 1)); + *method = (void *) _system_glTexImage2D; + } + + void **replaceMethod = (void **) (&hooks->gl.foo1 + i_glTexImage2D); + _system_glTexImage2D = (System_GlTexImage2D) *replaceMethod; + + *replaceMethod = (void *) _my_glTexImage2D; + + glTexImage2D(0,0,0,0,0,0,0,0,NULL); + } + + // release + _system_glTexImage2D = NULL; + has_hook_glTexImage2D = false; + int result = i_glTexImage2D; + i_glTexImage2D = 0; + return result; } \ No newline at end of file diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h index f5a490e31..320f43f2c 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h @@ -24,6 +24,15 @@ JNIEXPORT jint JNICALL Java_com_tencent_matrix_openglleak_detector_FuncSeeker_ge (JNIEnv *, jclass, jstring); +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getBindFuncIndex(JNIEnv *env, jclass clazz, + jstring bind_func_name); + +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage2DIndex(JNIEnv *env, jclass clazz); + #ifdef __cplusplus } #endif 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 7b42aaae2..1982d05d8 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 @@ -253,3 +253,20 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op return true; } +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlTexImage2D(JNIEnv *env, jclass clazz, jint index) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return false; + } + + void **origFunPtr = NULL; + + origFunPtr = (void **) (&hooks->gl.foo1 + index); + system_glTexImage2D = (System_GlTexImage2D) *origFunPtr; + *origFunPtr = (void *) my_glTexImage2D; + + return true; +} + 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 e0e87beb8..5a11eb64c 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 @@ -30,6 +30,7 @@ static System_GlNormal_TYPE system_glDeleteFramebuffers = NULL; static System_GlNormal_TYPE system_glGenRenderbuffers = NULL; static System_GlNormal_TYPE system_glDeleteRenderbuffers = NULL; static System_GlGetError_TYPE system_glGetError = NULL; +static System_GlTexImage2D system_glTexImage2D = NULL; static JavaVM *m_java_vm; @@ -528,5 +529,20 @@ GL_APICALL int GL_APIENTRY my_glGetError() { return 0; } +GL_APICALL void GL_APIENTRY my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const void *pixels) { + if(NULL != system_glTexImage2D) { + system_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + + __android_log_print(ANDROID_LOG_ERROR, "matrix.OpenglIndexDetectorService", "my_glTexImage2D width = %d", width); + __android_log_print(ANDROID_LOG_ERROR, "matrix.OpenglIndexDetectorService", "my_glTexImage2D height = %d", height); + __android_log_print(ANDROID_LOG_ERROR, "matrix.OpenglIndexDetectorService", "my_glTexImage2D type = %d", type); + + long size = width * height * 32; + __android_log_print(ANDROID_LOG_ERROR, "matrix.OpenglIndexDetectorService", "my_glTexImage2D size = %ld", size); + + } +} + #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 88f967cec..ed1988b4a 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 @@ -20,6 +20,9 @@ typedef void (*System_GlDeleteTexture_TYPE)(GLsizei n, const GLuint *textures); typedef void (*System_GlNormal_TYPE)(GLsizei n, const GLuint *normal); +typedef void (*System_GlTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const void *pixels); + System_GlNormal_TYPE get_target_func_ptr(const char *func_name); #endif //OPENGL_API_HOOK_TYPE_H \ No newline at end of file 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 6a0ecc4b3..b76696d8a 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 @@ -78,7 +78,8 @@ private void executeHook(IBinder iBinder) { int hookResult = map.get(FuncNameString.GL_GEN_TEXTURES) * map.get(FuncNameString.GL_DELETE_TEXTURES) * map.get(FuncNameString.GL_GEN_BUFFERS) * map.get(FuncNameString.GL_DELETE_BUFFERS) * map.get(FuncNameString.GL_GEN_FRAMEBUFFERS) * map.get(FuncNameString.GL_DELETE_FRAMEBUFFERS) - * map.get(FuncNameString.GL_GEN_RENDERBUFFERS) * map.get(FuncNameString.GL_DELETE_RENDERBUFFERS); + * map.get(FuncNameString.GL_GEN_RENDERBUFFERS) * map.get(FuncNameString.GL_DELETE_RENDERBUFFERS) + * map.get(FuncNameString.GL_TEX_IMAGE_2D); MatrixLog.e(TAG, "hookResult = " + hookResult); if (hookResult == 0) { if (OpenglLeakPlugin.sCallback != null) { @@ -99,6 +100,7 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_DELETE_FRAMEBUFFERS, map.get(FuncNameString.GL_DELETE_FRAMEBUFFERS)); OpenGLHook.getInstance().hook(FuncNameString.GL_GEN_RENDERBUFFERS, map.get(FuncNameString.GL_GEN_RENDERBUFFERS)); OpenGLHook.getInstance().hook(FuncNameString.GL_DELETE_RENDERBUFFERS, map.get(FuncNameString.GL_DELETE_RENDERBUFFERS)); + OpenGLHook.getInstance().hook(FuncNameString.GL_TEX_IMAGE_2D, map.get(FuncNameString.GL_TEX_IMAGE_2D)); MatrixLog.e(TAG, "hook finish"); // 泄漏监控 diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java index cb587040c..4fa5dd4cf 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java @@ -11,5 +11,7 @@ public class FuncNameString { public static final String GL_DELETE_FRAMEBUFFERS = "glDeleteFramebuffers"; public static final String GL_GEN_RENDERBUFFERS = "glGenRenderbuffers"; public static final String GL_DELETE_RENDERBUFFERS = "glDeleteRenderbuffers"; + public static final String GL_TEX_IMAGE_2D = "glTexImage2D"; + public static final String GL_BIND_TEXTURES = "glBindTextures"; } 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 d2bacfea3..888626ec9 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 @@ -9,6 +9,10 @@ public static int getFuncIndex(String targetFuncName) { return getGlGetErrorIndex(); } else if (targetFuncName.startsWith("glGen") || targetFuncName.startsWith("glDelete")) { return getTargetFuncIndex(targetFuncName); + } else if (targetFuncName.startsWith("glBind")) { + return getBindFuncIndex(targetFuncName); + } else if (targetFuncName.equals("glTexImage2D")) { + return getGlTexImage2DIndex(); } return 0; @@ -18,4 +22,8 @@ public static int getFuncIndex(String targetFuncName) { private static native int getTargetFuncIndex(String targetFuncName); + private static native int getBindFuncIndex(String bindFuncName); + + private static native int getGlTexImage2DIndex(); + } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java index 09b30b6d9..805ce9716 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java @@ -63,7 +63,10 @@ private Map seekOpenglFuncIndex() { int glDeleteRenderbuffersIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_DELETE_RENDERBUFFERS); MatrixLog.i(TAG, "glDeleteRenderbuffers index:" + glDeleteRenderbuffersIndex); - if ((glGenTexturesIndex * glDeleteTexturesIndex * glGenBuffersIndex * glDeleteBuffersIndex * glGenFramebuffersIndex * glDeleteFramebuffersIndex * glGenRenderbuffersIndex * glDeleteRenderbuffersIndex) == 0) { + int glTexImage2DIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_TEX_IMAGE_2D); + MatrixLog.i(TAG, "glTexImage2DIndex index:" + glTexImage2DIndex); + + if ((glGenTexturesIndex * glDeleteTexturesIndex * glGenBuffersIndex * glDeleteBuffersIndex * glGenFramebuffersIndex * glDeleteFramebuffersIndex * glGenRenderbuffersIndex * glDeleteRenderbuffersIndex * glTexImage2DIndex) == 0) { MatrixLog.e(TAG, "seek func index fail!"); return null; } @@ -77,8 +80,11 @@ private Map seekOpenglFuncIndex() { out.put(FuncNameString.GL_DELETE_FRAMEBUFFERS, glDeleteFramebuffersIndex); out.put(FuncNameString.GL_GEN_RENDERBUFFERS, glGenRenderbuffersIndex); out.put(FuncNameString.GL_DELETE_RENDERBUFFERS, glDeleteRenderbuffersIndex); + out.put(FuncNameString.GL_TEX_IMAGE_2D, glTexImage2DIndex); MatrixLog.i(TAG, "seek func index succ!"); + + EGLHelper.release(); return out; } 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 e69e79061..6c2519edc 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 @@ -50,6 +50,8 @@ public boolean hook(String targetFuncName, int index) { return hookGlGenRenderbuffers(index); } else if (targetFuncName.equals(FuncNameString.GL_DELETE_RENDERBUFFERS)) { return hookGlDeleteRenderbuffers(index); + } else if (targetFuncName.equals(FuncNameString.GL_TEX_IMAGE_2D)) { + return hookGlTexImage2D(index); } return false; @@ -79,6 +81,8 @@ public boolean hook(String targetFuncName, int index) { private static native boolean hookGlGetError(int index); + private static native boolean hookGlTexImage2D(int index); + public static void onGlGenTextures(int[] ids, String threadId, String javaStack, long nativeStackPtr) { if (ids.length > 0) { AtomicInteger counter = new AtomicInteger(ids.length); 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 459d29f81..d822ccba5 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 @@ -75,4 +75,9 @@ public static void initOpenGL() { GLES20.glFlush(); } + public static void release() { + EGL14.eglDestroySurface(mEGLDisplay, mEglSurface); + EGL14.eglDestroyContext(mEGLDisplay, mEglContext); + } + } From 177a7d8c59f9f991bdfe3bb910cb4050117c00e6 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 3 Sep 2021 17:24:16 +0800 Subject: [PATCH 032/163] pick 1c1c7c00 --- ..._matrix_openglleak_detector_FuncSeeker.cpp | 76 +++++- ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 74 ++++++ .../src/main/cpp/my_functions.h | 54 ++++- .../matrix-opengl-leak/src/main/cpp/type.cpp | 14 ++ .../matrix-opengl-leak/src/main/cpp/type.h | 4 + .../matrix/openglleak/OpenglLeakPlugin.java | 8 +- .../openglleak/comm/FuncNameString.java | 5 +- .../detector/OpenglIndexDetectorService.java | 17 +- .../matrix/openglleak/hook/OpenGLHook.java | 92 +++++++- .../openglleak/statistics/BindCenter.java | 25 ++ .../matrix/openglleak/statistics/BindMap.java | 174 ++++++++++++++ .../openglleak/statistics/OpenGLInfo.java | 54 ++++- .../statistics/OpenGLResRecorder.java | 70 ++++-- .../openglleak/utils/ExecuteCenter.java | 30 +++ .../wxperf/sample/OpenglLeakActivity.java | 147 ++++++++++++ .../tencent/wxperf/sample/OpenglRender.java | 222 ++++++++++++++++++ 16 files changed, 1015 insertions(+), 51 deletions(-) create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java create mode 100644 matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglLeakActivity.java create mode 100644 matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglRender.java diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp index d864ef550..31d084cdd 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp @@ -21,16 +21,17 @@ static System_GlNormal_TYPE _system_glGenNormal = NULL; static int i_glGenNormal = 0; static bool has_hook_glGenNormal = false; -GL_APICALL void GL_APIENTRY _my_glNormal(GLsizei n,GLuint *normal) { - if(!has_hook_glGenNormal) { +GL_APICALL void GL_APIENTRY _my_glNormal(GLsizei n, GLuint *normal) { + if (!has_hook_glGenNormal) { has_hook_glGenNormal = true; } _system_glGenNormal(n, normal); } -extern "C" JNIEXPORT jint JNICALL Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getTargetFuncIndex(JNIEnv *env, jclass, - jstring target_func_name) { +extern "C" JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getTargetFuncIndex(JNIEnv *env, jclass, + jstring target_func_name) { gl_hooks_t *hooks = get_gl_hooks(); if (NULL == hooks) { return 0; @@ -128,24 +129,81 @@ JNICALL Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlGetErrorInde return result; } +static System_GlBind_TYPE _system_glBind = NULL; +static int i_glBind = 0; +static bool has_hook_glBind = false; + +GL_APICALL void GL_APIENTRY _my_glBind(GLenum target, GLuint resourceId) { + if (!has_hook_glBind) { + has_hook_glBind = true; + } + + _system_glBind(target, resourceId); +} + extern "C" JNIEXPORT jint JNICALL Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getBindFuncIndex(JNIEnv *env, jclass clazz, jstring bind_func_name) { - return 0; + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return 0; + } + + System_GlBind_TYPE bind_func = get_bind_func_ptr(env->GetStringUTFChars(bind_func_name, JNI_FALSE)); + if (NULL == bind_func_name) { + return 0; + } + + for (i_glBind = 0; i_glBind < 500; i_glBind++) { + if (has_hook_glBind) { + i_glBind = i_glBind - 1; + + void **method = (void **) (&hooks->gl.foo1 + i_glBind); + *method = (void *) _system_glBind; + break; + } + + if (_system_glBind != NULL) { + void **method = (void **) (&hooks->gl.foo1 + (i_glBind - 1)); + *method = (void *) _system_glBind; + } + + void **replaceMethod = (void **) (&hooks->gl.foo1 + i_glBind); + _system_glBind = (System_GlBind_TYPE) *replaceMethod; + + *replaceMethod = (void *) _my_glBind; + + // 验证是否已经拿到偏移值 + HOOK_O_FUNC(bind_func, 0, NULL); + } + + if (i_glBind == 500) { + i_glBind = 0; + } + + // release + _system_glBind = NULL; + has_hook_glBind = false; + int result = i_glBind; + i_glBind = 0; + + return result; } static System_GlTexImage2D _system_glTexImage2D = NULL; static int i_glTexImage2D = 0; static bool has_hook_glTexImage2D = false; -GL_APICALL void GL_APIENTRY _my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, - GLint border, GLenum format, GLenum type, const void *pixels) { +GL_APICALL void GL_APIENTRY +_my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const void *pixels) { if (!has_hook_glTexImage2D) { has_hook_glTexImage2D = true; } - _system_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + _system_glTexImage2D(target, level, internalformat, width, height, border, format, type, + pixels); } @@ -176,7 +234,7 @@ Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage2DIndex(JNIE *replaceMethod = (void *) _my_glTexImage2D; - glTexImage2D(0,0,0,0,0,0,0,0,NULL); + glTexImage2D(0, 0, 0, 0, 0, 0, 0, 0, NULL); } // release 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 1982d05d8..035bc0a31 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 @@ -38,6 +38,12 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_getStack = env->GetStaticMethodID(class_OpenGLHook, "getStack", "()Ljava/lang/String;"); + method_onGlBindTexture = env->GetStaticMethodID(class_OpenGLHook, "onGlBindTexture", "(II)V"); + method_onGlBindBuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindBuffer", "(II)V"); + method_onGlBindFramebuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindFramebuffer", "(II)V"); + method_onGlBindRenderbuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindRenderbuffer", "(II)V"); + method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IJ)V"); + return true; } @@ -270,3 +276,71 @@ Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlTexImage2D(JNIEnv *env, return true; } +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindTexture(JNIEnv *env, jclass clazz, jint index) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return false; + } + + void **origFunPtr = NULL; + + origFunPtr = (void **) (&hooks->gl.foo1 + index); + system_glBindTexture = (System_GlBind_TYPE) *origFunPtr; + *origFunPtr = (void *) my_glBindTexture; + + return true; +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindBuffer(JNIEnv *env, jclass clazz, jint index) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return false; + } + + void **origFunPtr = NULL; + + origFunPtr = (void **) (&hooks->gl.foo1 + index); + system_glBindBuffer = (System_GlBind_TYPE) *origFunPtr; + *origFunPtr = (void *) my_glBindBuffer; + + return true; +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindFramebuffer(JNIEnv *env, jclass clazz, jint index) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return false; + } + + void **origFunPtr = NULL; + + origFunPtr = (void **) (&hooks->gl.foo1 + index); + system_glBindFramebuffer = (System_GlBind_TYPE) *origFunPtr; + *origFunPtr = (void *) my_glBindFramebuffer; + + return true; +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindRenderbuffer(JNIEnv *env, jclass clazz, jint index) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return false; + } + + void **origFunPtr = NULL; + + origFunPtr = (void **) (&hooks->gl.foo1 + index); + system_glBindRenderbuffer = (System_GlBind_TYPE) *origFunPtr; + *origFunPtr = (void *) my_glBindRenderbuffer; + + return true; +} + 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 5a11eb64c..a9bbe8218 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 @@ -31,6 +31,10 @@ static System_GlNormal_TYPE system_glGenRenderbuffers = NULL; static System_GlNormal_TYPE system_glDeleteRenderbuffers = NULL; static System_GlGetError_TYPE system_glGetError = NULL; static System_GlTexImage2D system_glTexImage2D = NULL; +static System_GlBind_TYPE system_glBindTexture = NULL; +static System_GlBind_TYPE system_glBindBuffer = NULL; +static System_GlBind_TYPE system_glBindFramebuffer = NULL; +static System_GlBind_TYPE system_glBindRenderbuffer = NULL; static JavaVM *m_java_vm; @@ -45,6 +49,11 @@ static jmethodID method_onGlGenRenderbuffers; static jmethodID method_onGlDeleteRenderbuffers; static jmethodID method_getStack; static jmethodID method_onGetError; +static jmethodID method_onGlBindTexture; +static jmethodID method_onGlBindBuffer; +static jmethodID method_onGlBindFramebuffer; +static jmethodID method_onGlBindRenderbuffer; +static jmethodID method_onGlTexImage2D; const size_t BUF_SIZE = 1024; @@ -533,16 +542,51 @@ GL_APICALL void GL_APIENTRY my_glTexImage2D(GLenum target, GLint level, GLint in GLint border, GLenum format, GLenum type, const void *pixels) { if(NULL != system_glTexImage2D) { system_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + long size = width * height * 32; - __android_log_print(ANDROID_LOG_ERROR, "matrix.OpenglIndexDetectorService", "my_glTexImage2D width = %d", width); - __android_log_print(ANDROID_LOG_ERROR, "matrix.OpenglIndexDetectorService", "my_glTexImage2D height = %d", height); - __android_log_print(ANDROID_LOG_ERROR, "matrix.OpenglIndexDetectorService", "my_glTexImage2D type = %d", type); + JNIEnv *env = GET_ENV(); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, size); + + } +} - long size = width * height * 32; - __android_log_print(ANDROID_LOG_ERROR, "matrix.OpenglIndexDetectorService", "my_glTexImage2D size = %ld", size); +GL_APICALL void GL_APIENTRY my_glBindTexture(GLenum target, GLuint resourceId) { + if(NULL != system_glBindTexture) { + system_glBindTexture(target, resourceId); + JNIEnv *env = GET_ENV(); + + char* javaStack = get_java_stack(); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindTexture, target, resourceId); } } +GL_APICALL void GL_APIENTRY my_glBindBuffer(GLenum target, GLuint resourceId) { + if(NULL != system_glBindTexture) { + system_glBindBuffer(target, resourceId); + JNIEnv *env = GET_ENV(); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindBuffer, target, resourceId); + + } +} + +GL_APICALL void GL_APIENTRY my_glBindFramebuffer(GLenum target, GLuint resourceId) { + if(NULL != system_glBindTexture) { + system_glBindFramebuffer(target, resourceId); + JNIEnv *env = GET_ENV(); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindFramebuffer, target, resourceId); + + } +} + +GL_APICALL void GL_APIENTRY my_glBindRenderbuffer(GLenum target, GLuint resourceId) { + if(NULL != system_glBindTexture) { + system_glBindRenderbuffer(target, resourceId); + JNIEnv *env = GET_ENV(); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindRenderbuffer, target, resourceId); + } +} + + #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.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp index 266fae73c..46fdf217b 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp @@ -24,5 +24,19 @@ System_GlNormal_TYPE get_target_func_ptr(const char *func_name) { return (System_GlNormal_TYPE) glDeleteRenderbuffers; } + return NULL; +} + +System_GlBind_TYPE get_bind_func_ptr(const char *func_name) { + if (strcmp(func_name, "glBindTexture") == 0) { + return (System_GlBind_TYPE) glBindTexture; + } else if (strcmp(func_name, "glBindBuffer") == 0) { + return (System_GlBind_TYPE) glBindBuffer; + } else if (strcmp(func_name, "glBindFramebuffer") == 0) { + return (System_GlBind_TYPE) glBindFramebuffer; + } else if (strcmp(func_name, "glBindRenderbuffer") == 0) { + return (System_GlBind_TYPE) glBindRenderbuffer; + } + return NULL; } \ 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 ed1988b4a..caf2bac12 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 @@ -20,9 +20,13 @@ typedef void (*System_GlDeleteTexture_TYPE)(GLsizei n, const GLuint *textures); typedef void (*System_GlNormal_TYPE)(GLsizei n, const GLuint *normal); +typedef void (*System_GlBind_TYPE)(GLenum target, GLuint resourceId); + typedef void (*System_GlTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); System_GlNormal_TYPE get_target_func_ptr(const char *func_name); +System_GlBind_TYPE get_bind_func_ptr(const char *func_name); + #endif //OPENGL_API_HOOK_TYPE_H \ No newline at end of file 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 b76696d8a..fa4a4fc7f 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 @@ -79,7 +79,9 @@ private void executeHook(IBinder iBinder) { * map.get(FuncNameString.GL_GEN_BUFFERS) * map.get(FuncNameString.GL_DELETE_BUFFERS) * map.get(FuncNameString.GL_GEN_FRAMEBUFFERS) * map.get(FuncNameString.GL_DELETE_FRAMEBUFFERS) * map.get(FuncNameString.GL_GEN_RENDERBUFFERS) * map.get(FuncNameString.GL_DELETE_RENDERBUFFERS) - * map.get(FuncNameString.GL_TEX_IMAGE_2D); + * map.get(FuncNameString.GL_TEX_IMAGE_2D) * map.get(FuncNameString.GL_BIND_TEXTURE) + * map.get(FuncNameString.GL_BIND_BUFFER) * map.get(FuncNameString.GL_BIND_FRAMEBUFFER) + * map.get(FuncNameString.GL_BIND_RENDERBUFFER); MatrixLog.e(TAG, "hookResult = " + hookResult); if (hookResult == 0) { if (OpenglLeakPlugin.sCallback != null) { @@ -101,6 +103,10 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_GEN_RENDERBUFFERS, map.get(FuncNameString.GL_GEN_RENDERBUFFERS)); OpenGLHook.getInstance().hook(FuncNameString.GL_DELETE_RENDERBUFFERS, map.get(FuncNameString.GL_DELETE_RENDERBUFFERS)); OpenGLHook.getInstance().hook(FuncNameString.GL_TEX_IMAGE_2D, map.get(FuncNameString.GL_TEX_IMAGE_2D)); + OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_TEXTURE, map.get(FuncNameString.GL_BIND_TEXTURE)); + OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_BUFFER, map.get(FuncNameString.GL_BIND_BUFFER)); + OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_FRAMEBUFFER, map.get(FuncNameString.GL_BIND_FRAMEBUFFER)); + OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_RENDERBUFFER, map.get(FuncNameString.GL_BIND_RENDERBUFFER)); MatrixLog.e(TAG, "hook finish"); // 泄漏监控 diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java index 4fa5dd4cf..a4dbbd6db 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java @@ -12,6 +12,9 @@ public class FuncNameString { public static final String GL_GEN_RENDERBUFFERS = "glGenRenderbuffers"; public static final String GL_DELETE_RENDERBUFFERS = "glDeleteRenderbuffers"; public static final String GL_TEX_IMAGE_2D = "glTexImage2D"; - public static final String GL_BIND_TEXTURES = "glBindTextures"; + public static final String GL_BIND_TEXTURE = "glBindTexture"; + public static final String GL_BIND_FRAMEBUFFER = "glBindFramebuffer"; + public static final String GL_BIND_BUFFER = "glBindBuffer"; + public static final String GL_BIND_RENDERBUFFER = "glBindRenderbuffer"; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java index 805ce9716..7725d57b0 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java @@ -66,7 +66,18 @@ private Map seekOpenglFuncIndex() { int glTexImage2DIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_TEX_IMAGE_2D); MatrixLog.i(TAG, "glTexImage2DIndex index:" + glTexImage2DIndex); - if ((glGenTexturesIndex * glDeleteTexturesIndex * glGenBuffersIndex * glDeleteBuffersIndex * glGenFramebuffersIndex * glDeleteFramebuffersIndex * glGenRenderbuffersIndex * glDeleteRenderbuffersIndex * glTexImage2DIndex) == 0) { + int glBindTextureIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_BIND_TEXTURE); + MatrixLog.i(TAG, "glBindTextureIndex index:" + glBindTextureIndex); + int glBindBufferIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_BIND_BUFFER); + MatrixLog.i(TAG, "glBindBufferIndex index:" + glBindBufferIndex); + int glBindFramebufferIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_BIND_FRAMEBUFFER); + MatrixLog.i(TAG, "glBindFramebufferIndex index:" + glBindFramebufferIndex); + int glBindRenderbufferIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_BIND_RENDERBUFFER); + MatrixLog.i(TAG, "glBindRenderbufferIndex index:" + glBindRenderbufferIndex); + + if ((glGenTexturesIndex * glDeleteTexturesIndex * glGenBuffersIndex * glDeleteBuffersIndex * glGenFramebuffersIndex + * glDeleteFramebuffersIndex * glGenRenderbuffersIndex * glDeleteRenderbuffersIndex * glTexImage2DIndex + * glBindTextureIndex * glBindBufferIndex * glBindFramebufferIndex * glBindRenderbufferIndex) == 0) { MatrixLog.e(TAG, "seek func index fail!"); return null; } @@ -81,6 +92,10 @@ private Map seekOpenglFuncIndex() { out.put(FuncNameString.GL_GEN_RENDERBUFFERS, glGenRenderbuffersIndex); out.put(FuncNameString.GL_DELETE_RENDERBUFFERS, glDeleteRenderbuffersIndex); out.put(FuncNameString.GL_TEX_IMAGE_2D, glTexImage2DIndex); + out.put(FuncNameString.GL_BIND_TEXTURE, glBindTextureIndex); + out.put(FuncNameString.GL_BIND_BUFFER, glBindBufferIndex); + out.put(FuncNameString.GL_BIND_FRAMEBUFFER, glBindFramebufferIndex); + out.put(FuncNameString.GL_BIND_RENDERBUFFER, glBindRenderbufferIndex); MatrixLog.i(TAG, "seek func index succ!"); 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 6c2519edc..21ce47ec0 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 @@ -3,12 +3,18 @@ import android.opengl.EGL14; import com.tencent.matrix.openglleak.comm.FuncNameString; +import com.tencent.matrix.openglleak.statistics.BindCenter; import com.tencent.matrix.openglleak.statistics.LeakMonitor; import com.tencent.matrix.openglleak.statistics.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.OpenGLResRecorder; +import com.tencent.matrix.util.MatrixLog; import java.util.concurrent.atomic.AtomicInteger; +import static com.tencent.matrix.openglleak.statistics.OpenGLInfo.OP_GEN; +import static com.tencent.matrix.openglleak.statistics.OpenGLInfo.OP_DELETE; +import static com.tencent.matrix.openglleak.statistics.OpenGLInfo.OP_BIND; + public class OpenGLHook { static { @@ -52,6 +58,14 @@ public boolean hook(String targetFuncName, int index) { return hookGlDeleteRenderbuffers(index); } else if (targetFuncName.equals(FuncNameString.GL_TEX_IMAGE_2D)) { return hookGlTexImage2D(index); + } else if (targetFuncName.equals(FuncNameString.GL_BIND_TEXTURE)) { + return hookGlBindTexture(index); + } else if (targetFuncName.equals(FuncNameString.GL_BIND_BUFFER)) { + return hookGlBindBuffer(index); + } else if (targetFuncName.equals(FuncNameString.GL_BIND_FRAMEBUFFER)) { + return hookGlBindFramebuffer(index); + } else if (targetFuncName.equals(FuncNameString.GL_BIND_RENDERBUFFER)) { + return hookGlBindRenderbuffer(index); } return false; @@ -83,6 +97,14 @@ public boolean hook(String targetFuncName, int index) { private static native boolean hookGlTexImage2D(int index); + private static native boolean hookGlBindTexture(int index); + + private static native boolean hookGlBindBuffer(int index); + + private static native boolean hookGlBindFramebuffer(int index); + + private static native boolean hookGlBindRenderbuffer(int index); + public static void onGlGenTextures(int[] ids, String threadId, String javaStack, long nativeStackPtr) { if (ids.length > 0) { AtomicInteger counter = new AtomicInteger(ids.length); @@ -93,9 +115,8 @@ public static void onGlGenTextures(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitor.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, OP_GEN, LeakMonitor.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); - if (getInstance().mListener != null) { getInstance().mListener.onGlGenTextures(openGLInfo); } @@ -112,7 +133,7 @@ public static void onGlDeleteTextures(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, false); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, OP_GEN); OpenGLResRecorder.getInstance().delete(openGLInfo); if (getInstance().mListener != null) { @@ -132,7 +153,7 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitor.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, OP_GEN, LeakMonitor.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -151,7 +172,7 @@ public static void onGlDeleteBuffers(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, false); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, OP_DELETE); OpenGLResRecorder.getInstance().delete(openGLInfo); if (getInstance().mListener != null) { @@ -171,7 +192,7 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitor.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, OP_GEN, LeakMonitor.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -190,7 +211,7 @@ public static void onGlDeleteFramebuffers(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, false); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, OP_DELETE); OpenGLResRecorder.getInstance().delete(openGLInfo); if (getInstance().mListener != null) { @@ -210,7 +231,7 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitor.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, OP_GEN, LeakMonitor.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -229,7 +250,7 @@ public static void onGlDeleteRenderbuffers(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, false); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, OP_DELETE); OpenGLResRecorder.getInstance().delete(openGLInfo); if (getInstance().mListener != null) { @@ -239,6 +260,59 @@ public static void onGlDeleteRenderbuffers(int[] ids, String threadId) { } } + public static void onGlBindTexture(int target, int id) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLInfo info = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, eglContextId, OP_BIND); + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.TEXTURE, target, eglContextId, info); + } + + public static void onGlBindBuffer(int target, int id) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLInfo info = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, eglContextId, OP_BIND); + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.BUFFER, target, eglContextId, info); + } + + public static void onGlBindFramebuffer(int target, int id) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLInfo info = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, eglContextId, OP_BIND); + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.FRAME_BUFFERS, target, eglContextId, info); + } + + public static void onGlBindRenderbuffer(int target, int id) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLInfo info = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, eglContextId, OP_BIND); + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.RENDER_BUFFERS, target, eglContextId, info); + } + + public static void onGlTexImage2D(int target, long size) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLInfo info = BindCenter.getInstance().getCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + if (info == null) { + MatrixLog.e(TAG, "getCurrentResourceIdByTarget result == null"); + return; + } + OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); + if (openGLInfo != null) { + openGLInfo.setSize(size); + OpenGLResRecorder.getInstance().replace(openGLInfo); + } + } + public static void onGetError(int eid) { if (getInstance().mListener != null) { getInstance().mListener.onGetError(new OpenGLInfo(eid)); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java new file mode 100644 index 000000000..d1047f88a --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java @@ -0,0 +1,25 @@ +package com.tencent.matrix.openglleak.statistics; + +public class BindCenter { + + private static final String TAG = "matrix.BindCenter"; + + private static final BindCenter mInstance = new BindCenter(); + + public static BindCenter getInstance() { + return mInstance; + } + + private BindCenter() { + } + + public void glBindResource(OpenGLInfo.TYPE type, int target, long eglContextId, OpenGLInfo info) { + BindMap.getInstance().putBindInfo(type, eglContextId, target, info); + } + + public OpenGLInfo getCurrentResourceIdByTarget(OpenGLInfo.TYPE type, long eglContextId, int target) { + return BindMap.getInstance().getBindInfo(type, eglContextId, target); + } + + +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java new file mode 100644 index 000000000..bb405dd70 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java @@ -0,0 +1,174 @@ +package com.tencent.matrix.openglleak.statistics; + +import com.tencent.matrix.openglleak.utils.ExecuteCenter; +import com.tencent.matrix.util.MatrixLog; + +import java.util.HashMap; +import java.util.Map; + +import static android.opengl.GLES20.GL_TEXTURE_2D; +import static android.opengl.GLES30.GL_TEXTURE_2D_ARRAY; +import static android.opengl.GLES30.GL_TEXTURE_3D; +import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP; + +public class BindMap { + + private static final String TAG = "matrix.BindMap"; + + private static final BindMap mInstance = new BindMap(); + + private final Map> bindTextureMap; + private final Map> bindBufferMap; + private final Map> bindFramebufferMap; + private final Map> bindRenderbufferMap; + + static BindMap getInstance() { + return mInstance; + } + + private BindMap() { + bindTextureMap = new HashMap<>(); + bindBufferMap = new HashMap<>(); + bindFramebufferMap = new HashMap<>(); + bindRenderbufferMap = new HashMap<>(); + } + + private OpenGLInfo getBindTextureInfo(long eglContextId, int target) { + synchronized (bindTextureMap) { + Map subTextureMap = bindTextureMap.get(eglContextId); + if (subTextureMap == null) { + subTextureMap = new HashMap<>(); + bindTextureMap.put(eglContextId, subTextureMap); + } + return subTextureMap.get(target); + } + } + + private OpenGLInfo getBindBufferInfo(long eglContextId, int target) { + synchronized (bindBufferMap) { + Map subBufferMap = bindBufferMap.get(eglContextId); + if (subBufferMap == null) { + subBufferMap = new HashMap<>(); + } + return subBufferMap.get(target); + } + } + + private OpenGLInfo getBindFramebufferInfo(long eglContextId, int target) { + synchronized (bindFramebufferMap) { + Map subFramebufferMap = bindFramebufferMap.get(eglContextId); + if (subFramebufferMap == null) { + subFramebufferMap = new HashMap<>(); + } + return subFramebufferMap.get(target); + } + } + + private OpenGLInfo getBindRenderbufferInfo(long eglContextId, int target) { + synchronized (bindRenderbufferMap) { + Map subRenderbufferMap = bindRenderbufferMap.get(eglContextId); + if (subRenderbufferMap == null) { + subRenderbufferMap = new HashMap<>(); + } + return subRenderbufferMap.get(target); + } + } + + private void putInBindTextureMap(final long eglContext, final int target, final OpenGLInfo info) { + if (!isSupportTargetOfTexture(target)) { + MatrixLog.e(TAG, "putInBindTextureMap input un support target = %d", target); + return; + } + synchronized (bindTextureMap) { + Map subTextureMap = bindTextureMap.get(eglContext); + if (subTextureMap == null) { + subTextureMap = new HashMap<>(); + bindTextureMap.put(eglContext, subTextureMap); + } + subTextureMap.put(target, info); + } + } + + private boolean isSupportTarget(OpenGLInfo.TYPE type, int target) { + if (type == OpenGLInfo.TYPE.TEXTURE) { + return isSupportTargetOfTexture(target); + } + if (type == OpenGLInfo.TYPE.BUFFER) { + return isSupportTargetOfBuffer(target); + } + if (type == OpenGLInfo.TYPE.FRAME_BUFFERS) { + return isSupportTargetOfFramebuffer(target); + } + if (type == OpenGLInfo.TYPE.RENDER_BUFFERS) { + return isSupportTargetOfRenderbuffer(target); + } + return false; + } + + private boolean isSupportTargetOfTexture(int target) { + return target == GL_TEXTURE_2D || target == GL_TEXTURE_3D + || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_CUBE_MAP; + } + + private boolean isSupportTargetOfBuffer(int target) { + return false; + } + + private boolean isSupportTargetOfFramebuffer(int target) { + return false; + } + + private boolean isSupportTargetOfRenderbuffer(int target) { + return false; + } + + public OpenGLInfo getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int target) { + switch (type) { + case BUFFER: + return getBindBufferInfo(eglContextId, target); + case TEXTURE: + return getBindTextureInfo(eglContextId, target); + case FRAME_BUFFERS: + return getBindFramebufferInfo(eglContextId, target); + case RENDER_BUFFERS: + return getBindRenderbufferInfo(eglContextId, target); + } + return null; + } + + + public void putBindInfo(final OpenGLInfo.TYPE type, final long eglContextId, final int target, final OpenGLInfo info) { + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + switch (type) { + case BUFFER: + putInBindBufferMap(eglContextId, target, info); + break; + case TEXTURE: + putInBindTextureMap(eglContextId, target, info); + break; + case FRAME_BUFFERS: + putInBindFramebufferMap(eglContextId, target, info); + break; + case RENDER_BUFFERS: + putInBindRenderbufferMap(eglContextId, target, info); + break; + } + } + }); + } + + private void putInBindRenderbufferMap(long eglContextId, int target, OpenGLInfo info) { + //todo + } + + private void putInBindFramebufferMap(long eglContextId, int target, OpenGLInfo info) { + //todo + } + + private void putInBindBufferMap(long eglContextId, int target, OpenGLInfo info) { + //todo + } + +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index 79d8374e4..fc273d950 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -10,6 +10,10 @@ public class OpenGLInfo { private static final String TAG = "OpenGLInfo.TAG"; + public static final int OP_GEN = 0x6565; + public static final int OP_DELETE = 0x6566; + public static final int OP_BIND = 0x6567; + private int id; private int error; private String threadId = ""; @@ -17,7 +21,8 @@ public class OpenGLInfo { private String javaStack = ""; private String nativeStack = ""; private long nativeStackPtr; - private boolean genOrDelete; + private int operate; + private long size; private TYPE type; // use to dump private int allocCount = 1; @@ -37,6 +42,7 @@ public enum TYPE { TEXTURE, BUFFER, FRAME_BUFFERS, RENDER_BUFFERS } + public OpenGLInfo(OpenGLInfo clone) { this.id = clone.id; this.error = clone.error; @@ -45,7 +51,7 @@ public OpenGLInfo(OpenGLInfo clone) { this.javaStack = clone.javaStack; this.nativeStack = clone.nativeStack; this.nativeStackPtr = clone.nativeStackPtr; - this.genOrDelete = clone.genOrDelete; + this.operate = clone.operate; this.type = clone.type; this.isRelease = clone.isRelease; this.maybeLeakCheckTime = clone.maybeLeakCheckTime; @@ -59,21 +65,32 @@ public OpenGLInfo(int error) { this.error = error; } - public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, boolean genOrDelete) { + public OpenGLInfo(TYPE type) { + this.type = type; + } + + public OpenGLInfo(TYPE type, int id, long eglContextNativeHandle, int operate) { + this.id = id; + this.eglContextNativeHandle = eglContextNativeHandle; + this.operate = operate; + this.type = type; + } + + public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, int operate) { this.id = id; this.threadId = threadId; this.eglContextNativeHandle = eglContextNativeHandle; - this.genOrDelete = genOrDelete; + this.operate = operate; this.type = type; } - public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, boolean genOrDelete, String activityName, AtomicInteger counter) { + public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, int operate, String activityName, AtomicInteger counter) { this.id = id; this.threadId = threadId; this.eglContextNativeHandle = eglContextNativeHandle; this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; - this.genOrDelete = genOrDelete; + this.operate = operate; this.type = type; this.activityName = activityName; this.counter = counter; @@ -124,6 +141,7 @@ public String getNativeStack() { return nativeStack; } + public int getAllocCount() { return allocCount; } @@ -137,6 +155,27 @@ public void incAllocRecord(int id) { this.idList.add(id); } + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + private String getOpStr() { + if (operate == OP_GEN) { + return "gen"; + } + if (operate == OP_DELETE) { + return "delete"; + } + if (operate == OP_BIND) { + return "bind"; + } + return "unkown"; + } + public boolean getMaybeLeak() { return maybeLeak; } @@ -191,8 +230,7 @@ public String toString() { "id=" + id + ", activityName=" + activityName + ", type='" + type.toString() + '\'' + - ", error=" + error + - ", isGen=" + genOrDelete + + ", size='" + size + '\'' + ", threadId='" + threadId + '\'' + ", eglContextNativeHandle='" + eglContextNativeHandle + '\'' + ", javaStack='" + javaStack + '\'' + diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 17ce4dcfb..1a9e9bf40 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -13,6 +13,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import com.tencent.matrix.openglleak.utils.ExecuteCenter; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -23,22 +25,16 @@ public class OpenGLResRecorder { - private List infoList = new ArrayList<>(); + private final List infoList = new ArrayList<>(); - private static OpenGLResRecorder mInstance = new OpenGLResRecorder(); + private static final OpenGLResRecorder mInstance = new OpenGLResRecorder(); - private HandlerThread mHandlerThread; - private Handler mH; private LeakMonitor.LeakListener mListener; private static final String TAG = "Matrix.OpenGLResRecorder"; private OpenGLResRecorder() { - mHandlerThread = new HandlerThread("GpuResLeakMonitor"); - mHandlerThread.start(); - - mH = new Handler(mHandlerThread.getLooper()); } public static OpenGLResRecorder getInstance() { @@ -50,7 +46,7 @@ public void setLeakListener(LeakMonitor.LeakListener mListener) { } public void gen(final OpenGLInfo oinfo) { - mH.post(new Runnable() { + ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { if (oinfo == null) { @@ -65,7 +61,7 @@ public void run() { } public void delete(final OpenGLInfo del) { - mH.post(new Runnable() { + ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { if (del == null) { @@ -116,13 +112,37 @@ public List getCopyList() { return ll; } - public void remove(OpenGLInfo info) { - if (infoList == null) { - return; - } - synchronized (infoList) { - infoList.remove(info); - } + public void remove(final OpenGLInfo info) { + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + if (infoList == null) { + return; + } + synchronized (infoList) { + infoList.remove(info); + } + } + }); + } + + public void replace(final OpenGLInfo info) { + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + if (infoList == null) { + return; + } + synchronized (infoList) { + for (int i = 0; i < infoList.size(); i++) { + if (info == infoList.get(i)) { + infoList.set(i, info); + return; + } + } + } + } + }); } public List getAllHashCode() { @@ -417,4 +437,20 @@ public OpenGLInfo getItemByHashCode(int hashCode) { return null; } + public OpenGLInfo getItemByEGLContextAndId(OpenGLInfo.TYPE type, long eglContext, int id) { + synchronized (infoList) { + for (OpenGLInfo item : infoList) { + if (item == null) { + break; + } + + if (type == item.getType() && item.getEglContextNativeHandle() == eglContext && item.getId() == id) { + return item; + } + } + } + + return null; + } + } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java new file mode 100644 index 000000000..10b9f2ae1 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java @@ -0,0 +1,30 @@ +package com.tencent.matrix.openglleak.utils; + +import android.os.Handler; +import android.os.HandlerThread; + +public class ExecuteCenter { + + private static final ExecuteCenter mInstance = new ExecuteCenter(); + + private final Handler mHandler; + + public static ExecuteCenter getInstance() { + return mInstance; + } + + private ExecuteCenter() { + HandlerThread mHandlerThread = new HandlerThread("matrix.GpuResLeakMonitor"); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + } + + public void post(Runnable runnable) { + mHandler.post(runnable); + } + + public void postDelay(Runnable runnable, long million) { + mHandler.postDelayed(runnable, million); + } + +} diff --git a/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglLeakActivity.java b/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglLeakActivity.java new file mode 100644 index 000000000..8c0e13891 --- /dev/null +++ b/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglLeakActivity.java @@ -0,0 +1,147 @@ +package com.tencent.wxperf.sample; + +import androidx.appcompat.app.AppCompatActivity; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.opengl.GLES10; +import android.opengl.GLES20; +import android.opengl.GLES32; +import android.opengl.GLSurfaceView; +import android.opengl.GLUtils; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Process; +import android.util.Log; +import android.view.View; +import android.widget.FrameLayout; + +import com.tencent.matrix.hook.HookManager; +import com.tencent.matrix.hook.memory.MemoryHook; +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.IntBuffer; + +public class OpenglLeakActivity extends AppCompatActivity { + + private static final String TAG = "Backtrace.Benchmark"; + + private int[] mTextures = new int[1]; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_opengl_leak); + Log.e(TAG, "OpenglLeakActivity onCreate success call"); + +// dump(); + + Log.e(TAG, "\n------------------------------------------------------------------------------------------------------------------------------------\n"); + + Log.e(TAG, "make openGL resource start"); + EGLHelper.initOpenGL(); + Log.e(TAG, "make openGL resource end"); + + Log.e(TAG, "\n------------------------------------------------------------------------------------------------------------------------------------\n"); + +// dump(); + + findViewById(R.id.button_finish_activity).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.e(TAG, "click button_finish_activity & do finish"); + finish(); + } + }); + +// OpenglRender render = new OpenglRender(this, mTextures[0]); +// render.loadTexture(); + + FrameLayout layout = findViewById(R.id.frame_layout_surface_view); + GLSurfaceView glView = new GLSurfaceView(this); + glView.setEGLContextClientVersion(2); + OpenglRender render = new OpenglRender(this, mTextures[0]); + glView.setRenderer(render); + layout.addView(glView); + +// HookManager.INSTANCE.dumpToLog(TAG); + + +// File fileDir = new File(LOG_FILE_DIR); +// fileDir.mkdir(); +// File logFile = new File(LOG_FILE_PATH); +// if (logFile.exists()) { +// logFile.delete(); +// } +// HookManager.INSTANCE.dumpToFile(logFile.getAbsolutePath()); +// +// readFile(logFile.getAbsolutePath()); + +// HookManager.INSTANCE.clearList(); + } + + @Override + protected void onResume() { + super.onResume(); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + dump("test"); + } + }, 10000); + + } + + @Override + protected void onDestroy() { + dump("OpenglLeak"); + EGLHelper.release(); + super.onDestroy(); + } + + private void dump(String lifeCycle) { + + @SuppressLint("SdCardPath") final String logFilePath = + TestApp.getContext().getExternalCacheDir() + File.separator + Process.myPid() + "_" + lifeCycle + "_gpu_memory_hook.log"; + + @SuppressLint("SdCardPath") final String jsonFilePath = + TestApp.getContext().getExternalCacheDir() + File.separator + Process.myPid() + "_" + lifeCycle + "_gpu_memory_hook.json"; + + File logFile = new File(logFilePath); + File jsonFile = new File(jsonFilePath); + + if (logFile.exists()) { + boolean result = logFile.delete(); + Log.e(TAG, "delete logFile result = " + result); + } + try { + logFile.createNewFile(); + } catch (IOException e) { + Log.e(TAG, "logFile create fail"); + } + + if (jsonFile.exists()) { + boolean result = jsonFile.delete(); + Log.e(TAG, "delete jsonFile result = " + result); + } + try { + jsonFile.createNewFile(); + } catch (IOException e) { + Log.e(TAG, "jsonFile create fail"); + } + + MemoryHook.INSTANCE.dump(logFile.getAbsolutePath(), jsonFile.getAbsolutePath()); + Log.e(TAG, logFile.getAbsolutePath()); + } + + +} \ No newline at end of file diff --git a/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglRender.java b/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglRender.java new file mode 100644 index 000000000..bf923d8d7 --- /dev/null +++ b/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglRender.java @@ -0,0 +1,222 @@ +package com.tencent.wxperf.sample; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.opengl.GLES20; +import android.opengl.GLSurfaceView; +import android.opengl.GLUtils; +import android.os.Process; +import android.util.Log; + +import com.tencent.matrix.hook.memory.MemoryHook; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +public class OpenglRender implements GLSurfaceView.Renderer { + + private static final String TAG = "Backtrace.Benchmark"; + + private static final String VERTEX_SHADER = "attribute vec4 vPosition;\n" + + "attribute vec2 vCoordinate;\n" + + "varying vec2 aCoordinate;\n" + + "void main() {\n" + + "gl_Position = vPosition;\n" + + "aCoordinate = vCoordinate;\n" + + "}"; + + private static final String FRAGMENT_SHADER = "precision mediump float;\n" + + "uniform sampler2D vTexture;\n" + + "varying vec2 aCoordinate;\n" + + "void main() {\n" + + "gl_FragColor = texture2D(vTexture,aCoordinate);\n" + + "}"; + + private float[] vertex = { + -1.0f, 1.0f, //左上角 + -1.0f, -1.0f, //左下角 + 1.0f, 1.0f, //右上角 + 1.0f, -1.0f //右下角 + }; + + private final float[] sCoord = { + 0f, 0f, //左上角 + 0f, 1f, //左下角 + 1f, 0f, //右上角 + 1f, 1f //右下角 + }; + + private FloatBuffer mVertexBuffer; + + private FloatBuffer mFragmentBuffer; + + private int mProgram; + + private int mVPosition; + + private int mVCoordinate; + + private int mVTexture; + + private Context mContext; + + private int mTextureid; + + private int[] textures = new int[1]; + + public OpenglRender(Context context, int textureid) { + mContext = context; + mTextureid = textureid; + mVertexBuffer = ByteBuffer.allocateDirect(vertex.length * 4) + .order(ByteOrder.nativeOrder()) + .asFloatBuffer().put(vertex); + mVertexBuffer.position(0); + + mFragmentBuffer = ByteBuffer.allocateDirect(sCoord.length * 4) + .order(ByteOrder.nativeOrder()) + .asFloatBuffer().put(sCoord); + mFragmentBuffer.position(0); + + Log.e("Backtrace.Benchmark", "OpenglRender = " + Thread.currentThread().getName()); + } + + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + int vertex_shader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER); + int fragment_shader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER); + + mProgram = GLES20.glCreateProgram(); + GLES20.glAttachShader(mProgram, vertex_shader); + GLES20.glAttachShader(mProgram, fragment_shader); + + GLES20.glLinkProgram(mProgram); + + int[] linkStatus = new int[1]; + GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0); + if (linkStatus[0] != GLES20.GL_TRUE) { + String info = GLES20.glGetProgramInfoLog(mProgram); + GLES20.glDeleteProgram(mProgram); + throw new RuntimeException("Could not link program: " + info); + } + + mVPosition = GLES20.glGetAttribLocation(mProgram, "vPosition"); + mVCoordinate = GLES20.glGetAttribLocation(mProgram, "vCoordinate"); + mVTexture = GLES20.glGetUniformLocation(mProgram, "vTexture"); + + Log.e("Backtrace.Benchmark", "onSurfaceCreated = " + Thread.currentThread().getName()); + loadTexture(); + dump("OpenglRender"); + + } + + private void dump(String lifeCycle) { + + @SuppressLint("SdCardPath") final String logFilePath = + TestApp.getContext().getExternalCacheDir() + File.separator + Process.myPid() + "_" + lifeCycle + "_gpu_memory_hook.log"; + + @SuppressLint("SdCardPath") final String jsonFilePath = + TestApp.getContext().getExternalCacheDir() + File.separator + Process.myPid() + "_" + lifeCycle + "_gpu_memory_hook.json"; + + File logFile = new File(logFilePath); + File jsonFile = new File(jsonFilePath); + + if (logFile.exists()) { + boolean result = logFile.delete(); + Log.e(TAG, "delete logFile result = " + result); + } + try { + logFile.createNewFile(); + } catch (IOException e) { + Log.e(TAG, "logFile create fail"); + } + + if (jsonFile.exists()) { + boolean result = jsonFile.delete(); + Log.e(TAG, "delete jsonFile result = " + result); + } + try { + jsonFile.createNewFile(); + } catch (IOException e) { + Log.e(TAG, "jsonFile create fail"); + } + + MemoryHook.INSTANCE.dump(logFile.getAbsolutePath(), jsonFile.getAbsolutePath()); + Log.e(TAG, logFile.getAbsolutePath()); + } + + + public void loadTexture() { + GLES20.glGenTextures(1, IntBuffer.wrap(textures)); +// GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureid); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); + //激活第0个纹理 + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glUniform1i(mVTexture, 0); + //设置环绕和过滤方式 + //环绕(超出纹理坐标范围):(s==x t==y GL_REPEAT 重复) + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); + //过滤(纹理像素映射到坐标点):(缩小、放大:GL_LINEAR线性) + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + + Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.test1); + //设置图片 + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); + bitmap.recycle(); + //解绑纹理 + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); + } + + private int loadShader(int glVertexShader, String vertexShader) { + int glCreateShader = GLES20.glCreateShader(glVertexShader); + GLES20.glShaderSource(glCreateShader, vertexShader); + GLES20.glCompileShader(glCreateShader); + int[] compiled = new int[1]; + GLES20.glGetShaderiv(glCreateShader, GLES20.GL_COMPILE_STATUS, compiled, 0); + if (compiled[0] != GLES20.GL_TRUE) { + GLES20.glDeleteShader(glCreateShader); + return -1; + } + return glCreateShader; + } + + @Override + public void onSurfaceChanged(GL10 gl, int width, int height) { + GLES20.glViewport(0, 0, width, height); + } + + @Override + public void onDrawFrame(GL10 gl) { + + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + GLES20.glClearColor(1.0f, 0, 0, 1f); + //使用源程序 + GLES20.glUseProgram(mProgram); + //绑定绘制纹理 +// GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureid); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); + //使顶点属性数组有效 + GLES20.glEnableVertexAttribArray(mVPosition); + //为顶点属性赋值 + GLES20.glVertexAttribPointer(mVPosition, 2, GLES20.GL_FLOAT, false, 8, mVertexBuffer); + + GLES20.glEnableVertexAttribArray(mVCoordinate); + GLES20.glVertexAttribPointer(mVCoordinate, 2, GLES20.GL_FLOAT, false, 8, mFragmentBuffer); + //绘制图形 + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + //解绑纹理 + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); + + } +} From 5bed198e6d83e578883d0a221c4013cf5b6ca11b Mon Sep 17 00:00:00 2001 From: yvesluo Date: Wed, 1 Dec 2021 11:39:05 +0800 Subject: [PATCH 033/163] sample: set manufacture for resource plugin --- .../src/main/java/sample/tencent/matrix/MatrixApplication.java | 2 ++ samples/sample-android/build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) 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 feddd47fb..b916cacbb 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 @@ -19,6 +19,7 @@ import android.app.Application; import android.content.Context; import android.content.Intent; +import android.os.Build; import com.tencent.matrix.Matrix; import com.tencent.matrix.batterycanary.BatteryMonitorPlugin; @@ -153,6 +154,7 @@ private ResourcePlugin configureResourcePlugin(DynamicConfigImplDemo dynamicConf .dynamicConfig(dynamicConfig) .setAutoDumpHprofMode(mode) .setManualDumpTargetActivity(ManualDumpActivity.class.getName()) + .setManufacture(Build.MANUFACTURER) .build(); ResourcePlugin.activityLeakFixer(this); diff --git a/samples/sample-android/build.gradle b/samples/sample-android/build.gradle index d49ef8645..55b0d3651 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.2" + MATRIX_VERSION = "2.0.2-SNAPSHOT" GROUP = 'com.tencent.matrix' VERSION_NAME = "${MATRIX_VERSION}" From 7055d0478532946c4347263642e948caa9fc73c2 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Tue, 14 Sep 2021 10:32:10 +0800 Subject: [PATCH 034/163] add type judge --- .../src/main/cpp/my_functions.h | 7 ++- .../matrix-opengl-leak/src/main/cpp/type.cpp | 55 ++++++++++++++++++- .../matrix-opengl-leak/src/main/cpp/type.h | 6 ++ .../matrix/openglleak/hook/OpenGLHook.java | 2 + 4 files changed, 67 insertions(+), 3 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 a9bbe8218..5cadb1584 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 @@ -542,7 +542,12 @@ GL_APICALL void GL_APIENTRY my_glTexImage2D(GLenum target, GLint level, GLint in GLint border, GLenum format, GLenum type, const void *pixels) { if(NULL != system_glTexImage2D) { system_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + int pixel = Utils::getSizeOfPerPixel(internalformat, format, type); long size = width * height * 32; + __android_log_print(ANDROID_LOG_ERROR, "Backtrace.Benchmark", "format == %d", format); + __android_log_print(ANDROID_LOG_ERROR, "Backtrace.Benchmark", "internalformat == %d", internalformat); + __android_log_print(ANDROID_LOG_ERROR, "Backtrace.Benchmark", "type == %d", type); + __android_log_print(ANDROID_LOG_ERROR, "Backtrace.Benchmark", "size == %ld", size); JNIEnv *env = GET_ENV(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, size); @@ -555,8 +560,6 @@ GL_APICALL void GL_APIENTRY my_glBindTexture(GLenum target, GLuint resourceId) { if(NULL != system_glBindTexture) { system_glBindTexture(target, resourceId); JNIEnv *env = GET_ENV(); - - char* javaStack = get_java_stack(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindTexture, target, resourceId); } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp index 46fdf217b..70e6c686c 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp @@ -3,7 +3,10 @@ // #include "type.h" -#include +#include +#include + +#define BIT 8 System_GlNormal_TYPE get_target_func_ptr(const char *func_name) { if (strcmp(func_name, "glGenTextures") == 0) { @@ -39,4 +42,54 @@ System_GlBind_TYPE get_bind_func_ptr(const char *func_name) { } return NULL; +} + +int getPartByFormat(GLint internalformat, GLenum format, int bit) { + switch (format) { + case GL_RGB: + case GL_RGBA: + default:return 1; + } +} + +int getSizeOfPerPixelByFormat(GLint internalformat, GLenum format) { + + if (internalformat == GL_RGB565) { + return 2; + } + + if (internalformat == GL_RGB5_A1) { + return 2; + } + + if (internalformat == GL_RGBA4) { + return 2; + } + + + return 0; +} + + +namespace Utils { + + int getSizeOfPerPixel(GLint internalformat, GLenum format, GLenum type) { + switch (type) { + case GL_UNSIGNED_BYTE: + return getSizeOfPerPixelByFormat(internalformat, format); + case GL_UNSIGNED_SHORT_5_6_5: + return 2; + case GL_UNSIGNED_SHORT_4_4_4_4: + return 2; + case GL_UNSIGNED_SHORT_5_5_5_1: + return 2; + case GL_BYTE: + case GL_UNSIGNED_INT: + case GL_INT: + case GL_FLOAT: + default: + return 0; + } + } + } \ 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 caf2bac12..0a934688a 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 @@ -29,4 +29,10 @@ System_GlNormal_TYPE get_target_func_ptr(const char *func_name); System_GlBind_TYPE get_bind_func_ptr(const char *func_name); +namespace Utils { + + int getSizeOfPerPixel(GLint internalformat, GLenum format, GLenum type); + +} + #endif //OPENGL_API_HOOK_TYPE_H \ No newline at end of file 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 21ce47ec0..ee036ab15 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 @@ -1,6 +1,7 @@ package com.tencent.matrix.openglleak.hook; import android.opengl.EGL14; +import android.util.Log; import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.BindCenter; @@ -311,6 +312,7 @@ public static void onGlTexImage2D(int target, long size) { openGLInfo.setSize(size); OpenGLResRecorder.getInstance().replace(openGLInfo); } + Log.e("Backtrace.Benchmark", "onGlTexImage2D egl context = " + eglContextId); } public static void onGetError(int eid) { From 7b4db2b68798977f7acd35f45bfea5c726a879a4 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Tue, 14 Sep 2021 15:42:45 +0800 Subject: [PATCH 035/163] hook glTexImage3D --- .../matrix-opengl-leak/CMakeLists.txt | 1 + ..._matrix_openglleak_detector_FuncSeeker.cpp | 61 ++++- ...nt_matrix_openglleak_detector_FuncSeeker.h | 4 + ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 21 +- ...encent_matrix_openglleak_hook_OpenGLHook.h | 8 + .../src/main/cpp/my_functions.h | 22 +- .../matrix-opengl-leak/src/main/cpp/type.cpp | 247 +++++++++++++++--- .../matrix-opengl-leak/src/main/cpp/type.h | 34 ++- .../matrix/openglleak/OpenglLeakPlugin.java | 1 + .../openglleak/comm/FuncNameString.java | 1 + .../openglleak/detector/FuncSeeker.java | 4 + .../detector/OpenglIndexDetectorService.java | 7 +- .../matrix/openglleak/hook/OpenGLHook.java | 199 ++++++++++---- 13 files changed, 496 insertions(+), 114 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt b/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt index e80e76944..a3c10383e 100644 --- a/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt +++ b/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt @@ -73,6 +73,7 @@ target_link_libraries( # Specifies the target library. # included in the NDK. PRIVATE ${log-lib} GLESv2 + GLESv3 PRIVATE ${EXT_DEP}/lib/${ANDROID_ABI}/libwechatbacktrace.so ) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp index 31d084cdd..d5946501c 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -15,7 +14,6 @@ #define HOOK_O_FUNC(func, params...) func(params) #define LOG_TAG "matrix.opengl" -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) static System_GlNormal_TYPE _system_glGenNormal = NULL; static int i_glGenNormal = 0; @@ -37,7 +35,8 @@ Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getTargetFuncIndex(JNIEnv return 0; } - System_GlNormal_TYPE target_func = get_target_func_ptr(env->GetStringUTFChars(target_func_name, JNI_FALSE)); + System_GlNormal_TYPE target_func = get_target_func_ptr( + env->GetStringUTFChars(target_func_name, JNI_FALSE)); if (NULL == target_func) { return 0; } @@ -244,4 +243,58 @@ Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage2DIndex(JNIE i_glTexImage2D = 0; return result; -} \ No newline at end of file +} + + +static System_GlTexImage3D _system_glTexImage3D = NULL; +static int i_glTexImage3D = 0; +static bool has_hook_glTexImage3D = false; + +GL_APICALL void GL_APIENTRY +_my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { + if (!has_hook_glTexImage3D) { + has_hook_glTexImage3D = true; + } + + _system_glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); +} + + +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage3DIndex(JNIEnv *env, jclass clazz) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return -1; + } + + for (i_glTexImage3D = 0; i_glTexImage3D < 1000; i_glTexImage3D++) { + if (has_hook_glTexImage3D) { + i_glTexImage3D = i_glTexImage3D - 1; + + void **method = (void **) (&hooks->gl.foo1 + i_glTexImage3D); + *method = (void *) _system_glTexImage3D; + break; + } + + if (_system_glTexImage3D != NULL) { + void **method = (void **) (&hooks->gl.foo1 + (i_glTexImage3D - 1)); + *method = (void *) _system_glTexImage3D; + } + + void **replaceMethod = (void **) (&hooks->gl.foo1 + i_glTexImage3D); + _system_glTexImage3D = (System_GlTexImage3D) *replaceMethod; + + *replaceMethod = (void *) _my_glTexImage3D; + + glTexImage3D(0, 0, 0, 0,0, 0, 0, 0, 0, NULL); + } + + // release + _system_glTexImage3D = NULL; + has_hook_glTexImage3D = false; + int result = i_glTexImage3D; + i_glTexImage3D = 0; + + return result; +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h index 320f43f2c..31ebfcb31 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h @@ -33,6 +33,10 @@ extern "C" JNIEXPORT jint JNICALL Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage2DIndex(JNIEnv *env, jclass clazz); +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage3DIndex(JNIEnv *env, jclass clazz); + #ifdef __cplusplus } #endif 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 035bc0a31..6d2c8732f 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 @@ -42,8 +42,8 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_onGlBindBuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindBuffer", "(II)V"); method_onGlBindFramebuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindFramebuffer", "(II)V"); method_onGlBindRenderbuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindRenderbuffer", "(II)V"); - method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IJ)V"); - + method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IJIII)V"); + method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IJIII)V"); return true; } @@ -276,6 +276,23 @@ Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlTexImage2D(JNIEnv *env, return true; } +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlTexImage3D(JNIEnv *env, jclass clazz, jint index) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return false; + } + + void **origFunPtr = NULL; + + origFunPtr = (void **) (&hooks->gl.foo1 + index); + system_glTexImage3D = (System_GlTexImage3D) *origFunPtr; + *origFunPtr = (void *) my_glTexImage3D; + + return true; +} + extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindTexture(JNIEnv *env, jclass clazz, jint index) { 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 cc3a7c302..05f98976c 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 @@ -105,6 +105,14 @@ JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_OpenGLHook_ho (JNIEnv *, jclass, jint); +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlTexImage2D(JNIEnv *env, jclass clazz, jint index); + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlTexImage3D(JNIEnv *env, jclass clazz, jint index); + #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 5cadb1584..2763be569 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 @@ -31,6 +31,7 @@ static System_GlNormal_TYPE system_glGenRenderbuffers = NULL; static System_GlNormal_TYPE system_glDeleteRenderbuffers = NULL; static System_GlGetError_TYPE system_glGetError = NULL; static System_GlTexImage2D system_glTexImage2D = NULL; +static System_GlTexImage3D system_glTexImage3D = NULL; static System_GlBind_TYPE system_glBindTexture = NULL; static System_GlBind_TYPE system_glBindBuffer = NULL; static System_GlBind_TYPE system_glBindFramebuffer = NULL; @@ -54,6 +55,7 @@ static jmethodID method_onGlBindBuffer; static jmethodID method_onGlBindFramebuffer; static jmethodID method_onGlBindRenderbuffer; static jmethodID method_onGlTexImage2D; +static jmethodID method_onGlTexImage3D; const size_t BUF_SIZE = 1024; @@ -543,15 +545,21 @@ GL_APICALL void GL_APIENTRY my_glTexImage2D(GLenum target, GLint level, GLint in if(NULL != system_glTexImage2D) { system_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); int pixel = Utils::getSizeOfPerPixel(internalformat, format, type); - long size = width * height * 32; - __android_log_print(ANDROID_LOG_ERROR, "Backtrace.Benchmark", "format == %d", format); - __android_log_print(ANDROID_LOG_ERROR, "Backtrace.Benchmark", "internalformat == %d", internalformat); - __android_log_print(ANDROID_LOG_ERROR, "Backtrace.Benchmark", "type == %d", type); - __android_log_print(ANDROID_LOG_ERROR, "Backtrace.Benchmark", "size == %ld", size); - + long size = width * height * pixel; JNIEnv *env = GET_ENV(); - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, size); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, size, internalformat, format, type); + + } +} +GL_APICALL void GL_APIENTRY my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { + if(NULL != system_glTexImage3D) { + system_glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); + int pixel = Utils::getSizeOfPerPixel(internalformat, format, type); + long size = width * height * depth * pixel; + JNIEnv *env = GET_ENV(); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage3D, target, size, internalformat, format, type); } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp index 70e6c686c..0dde4114a 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp @@ -4,9 +4,6 @@ #include "type.h" #include -#include - -#define BIT 8 System_GlNormal_TYPE get_target_func_ptr(const char *func_name) { if (strcmp(func_name, "glGenTextures") == 0) { @@ -44,52 +41,224 @@ System_GlBind_TYPE get_bind_func_ptr(const char *func_name) { return NULL; } -int getPartByFormat(GLint internalformat, GLenum format, int bit) { - switch (format) { - case GL_RGB: - case GL_RGBA: - default:return 1; - } -} +namespace Utils { -int getSizeOfPerPixelByFormat(GLint internalformat, GLenum format) { + /* + * support by OpenGL ES Software Development Kit + */ + int getSizeOfPerPixel(GLint internalformat, GLenum format, GLenum type) { - if (internalformat == GL_RGB565) { - return 2; - } + // GL_RED + if (internalformat == GL_R8 && format == GL_RED && type == GL_UNSIGNED_BYTE) { + return 1; + } + if (internalformat == GL_R8_SNORM && format == GL_RED && type == GL_BYTE) { + return 1; + } + if (internalformat == GL_R16F && format == GL_RED && + (type == GL_HALF_FLOAT || type == GL_FLOAT)) { + return 2; + } + if (internalformat == GL_R32F && format == GL_RED && type == GL_FLOAT) { + return 4; + } - if (internalformat == GL_RGB5_A1) { - return 2; - } + // GL_RED_INTEGER + if (internalformat == GL_R8UI && format == GL_RED_INTEGER && type == GL_UNSIGNED_BYTE) { + return 1; + } + if (internalformat == GL_R8I && format == GL_RED_INTEGER && type == GL_BYTE) { + return 1; + } + if (internalformat == GL_R16UI && format == GL_RED_INTEGER && type == GL_UNSIGNED_SHORT) { + return 2; + } + if (internalformat == GL_R16I && format == GL_RED_INTEGER && type == GL_SHORT) { + return 2; + } + if (internalformat == GL_R32UI && format == GL_RED_INTEGER && type == GL_UNSIGNED_INT) { + return 4; + } + if (internalformat == GL_R32I && format == GL_RED_INTEGER && type == GL_INT) { + return 4; + } - if (internalformat == GL_RGBA4) { - return 2; - } + // GL_RG + if (internalformat == GL_RG8 && format == GL_RG && type == GL_UNSIGNED_BYTE) { + return 2; + } + if (internalformat == GL_RG8_SNORM && format == GL_RG && type == GL_BYTE) { + return 2; + } + if (internalformat == GL_RG16F && format == GL_RG && + (type == GL_HALF_FLOAT || type == GL_FLOAT)) { + return 4; + } + if (internalformat == GL_RG32F && format == GL_RG && type == GL_FLOAT) { + return 8; + } + // GL_RG_INTEGER + if (internalformat == GL_RG8UI && format == GL_RG_INTEGER && type == GL_UNSIGNED_BYTE) { + return 2; + } + if (internalformat == GL_RG8I && format == GL_RG_INTEGER && type == GL_BYTE) { + return 2; + } + if (internalformat == GL_RG16UI && format == GL_RG_INTEGER && type == GL_UNSIGNED_SHORT) { + return 4; + } + if (internalformat == GL_RG16I && format == GL_RG_INTEGER && type == GL_SHORT) { + return 4; + } + if (internalformat == GL_RG32UI && format == GL_RG_INTEGER && type == GL_UNSIGNED_INT) { + return 8; + } + if (internalformat == GL_RG32I && format == GL_RG_INTEGER && type == GL_INT) { + return 8; + } - return 0; -} + // GL_RGB + if (internalformat == GL_RGB8 && format == GL_RGB && type == GL_UNSIGNED_BYTE) { + return 3; + } + if (internalformat == GL_SRGB8 && format == GL_RGB && type == GL_UNSIGNED_BYTE) { + return 3; + } + if (internalformat == GL_RGB565 && format == GL_RGB && + (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT_5_6_5)) { + return 2; + } + if (internalformat == GL_RGB8_SNORM && format == GL_RGB && type == GL_BYTE) { + return 3; + } + if (internalformat == GL_R11F_G11F_B10F && format == GL_RGB + && (type == GL_UNSIGNED_INT_10F_11F_11F_REV || type == GL_HALF_FLOAT || + type == GL_FLOAT)) { + return 4; + } + if (internalformat == GL_RGB9_E5 && format == GL_RGB + && (type == GL_UNSIGNED_INT_5_9_9_9_REV || type == GL_HALF_FLOAT || type == GL_FLOAT)) { + return 4; + } + if (internalformat == GL_RGB16F && format == GL_RGB && + (type == GL_HALF_FLOAT || type == GL_FLOAT)) { + return 6; + } + if (internalformat == GL_RGB32F && format == GL_RGB && type == GL_FLOAT) { + return 12; + } + // GL_RGB_INTEGER + if (internalformat == GL_RGB8UI && format == GL_RGB_INTEGER && type == GL_UNSIGNED_BYTE) { + return 3; + } + if (internalformat == GL_RGB8I && format == GL_RGB_INTEGER && type == GL_BYTE) { + return 3; + } + if (internalformat == GL_RGB16UI && format == GL_RGB_INTEGER && type == GL_UNSIGNED_SHORT) { + return 6; + } + if (internalformat == GL_RGB16I && format == GL_RGB_INTEGER && type == GL_SHORT) { + return 6; + } + if (internalformat == GL_RGB32UI && format == GL_RGB_INTEGER && type == GL_UNSIGNED_INT) { + return 12; + } + if (internalformat == GL_RGB32I && format == GL_RGB_INTEGER && type == GL_INT) { + return 12; + } -namespace Utils { + // GL_RGBA + if (internalformat == GL_RGBA && format == GL_RGBA) { + return 4; + } + if (internalformat == GL_RGBA8 && format == GL_RGBA && type == GL_UNSIGNED_BYTE) { + return 4; + } + if (internalformat == GL_SRGB8_ALPHA8 && format == GL_RGBA && type == GL_UNSIGNED_BYTE) { + return 4; + } + if (internalformat == GL_RGBA8_SNORM && format == GL_RGBA && type == GL_BYTE) { + return 4; + } + if (internalformat == GL_RGB5_A1 && format == GL_RGBA && + (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT_5_5_5_1 || + type == GL_UNSIGNED_INT_2_10_10_10_REV)) { + return 2; + } + if (internalformat == GL_RGBA4 && format == GL_RGBA && + (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT_4_4_4_4)) { + return 2; + } + if (internalformat == GL_RGB10_A2 && format == GL_RGBA && + type == GL_UNSIGNED_INT_2_10_10_10_REV) { + return 4; + } + if (internalformat == GL_RGBA16F && format == GL_RGBA && + (type == GL_HALF_FLOAT || type == GL_FLOAT)) { + return 8; + } + if (internalformat == GL_RGBA32F && format == GL_RGBA && type == GL_FLOAT) { + return 16; + } - int getSizeOfPerPixel(GLint internalformat, GLenum format, GLenum type) { - switch (type) { - case GL_UNSIGNED_BYTE: - return getSizeOfPerPixelByFormat(internalformat, format); - case GL_UNSIGNED_SHORT_5_6_5: - return 2; - case GL_UNSIGNED_SHORT_4_4_4_4: - return 2; - case GL_UNSIGNED_SHORT_5_5_5_1: - return 2; - case GL_BYTE: - case GL_UNSIGNED_INT: - case GL_INT: - case GL_FLOAT: - default: - return 0; + // GL_RGBA_INTEGER + if (internalformat == GL_RGBA8UI && format == GL_RGBA_INTEGER && type == GL_UNSIGNED_BYTE) { + return 4; + } + if (internalformat == GL_RGBA8I && format == GL_RGBA_INTEGER && type == GL_BYTE) { + return 4; + } + if (internalformat == GL_RGB10_A2UI && format == GL_RGBA_INTEGER && + type == GL_UNSIGNED_INT_2_10_10_10_REV) { + return 4; + } + if (internalformat == GL_RGBA16UI && format == GL_RGBA_INTEGER && + type == GL_UNSIGNED_SHORT) { + return 8; + } + if (internalformat == GL_RGBA16I && format == GL_RGBA_INTEGER && type == GL_SHORT) { + return 8; + } + if (internalformat == GL_RGBA32I && format == GL_RGBA_INTEGER && type == GL_INT) { + return 16; + } + if (internalformat == GL_RGBA32UI && format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT) { + return 16; + } + + // GL_DEPTH_COMPONENT + if (internalformat == GL_DEPTH_COMPONENT16 && format == GL_DEPTH_COMPONENT && + (type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT)) { + return 2; } + if (internalformat == GL_DEPTH_COMPONENT24 && format == GL_DEPTH_COMPONENT && + type == GL_UNSIGNED_INT) { + return 3; + } + if (internalformat == GL_DEPTH_COMPONENT32F && format == GL_DEPTH_COMPONENT && + type == GL_FLOAT) { + return 4; + } + + // GL_DEPTH24_STENCIL8 + if (internalformat == GL_DEPTH24_STENCIL8 && format == GL_DEPTH_STENCIL && + type == GL_UNSIGNED_INT_24_8) { + return 4; + } + if (internalformat == GL_DEPTH32F_STENCIL8 && format == GL_DEPTH_STENCIL && + type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV) { + return 5; + } + + // GL_STENCIL_INDEX + if (internalformat == GL_STENCIL_INDEX8 && format == GL_STENCIL_INDEX && + type == GL_UNSIGNED_BYTE) { + return 1; + } + + return 0; } } \ 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 0a934688a..ed97e3f91 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 @@ -2,7 +2,17 @@ // Created by 邓沛堆 on 2020-05-26. // +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #ifndef OPENGL_API_HOOK_TYPE_H #define OPENGL_API_HOOK_TYPE_H @@ -16,14 +26,30 @@ typedef int (*System_GlGetError_TYPE)(void); typedef void (*System_GlGenTexture_TYPE)(GLsizei n, GLuint *textures); -typedef void (*System_GlDeleteTexture_TYPE)(GLsizei n, const GLuint *textures); - typedef void (*System_GlNormal_TYPE)(GLsizei n, const GLuint *normal); typedef void (*System_GlBind_TYPE)(GLenum target, GLuint resourceId); -typedef void (*System_GlTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, - GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (*System_GlTexImage2D)(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void *pixels); + +typedef void (*System_GlTexImage3D)(GLenum target, + GLint level, + GLint internalFormat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void *data); System_GlNormal_TYPE get_target_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 fa4a4fc7f..608201767 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 @@ -103,6 +103,7 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_GEN_RENDERBUFFERS, map.get(FuncNameString.GL_GEN_RENDERBUFFERS)); OpenGLHook.getInstance().hook(FuncNameString.GL_DELETE_RENDERBUFFERS, map.get(FuncNameString.GL_DELETE_RENDERBUFFERS)); OpenGLHook.getInstance().hook(FuncNameString.GL_TEX_IMAGE_2D, map.get(FuncNameString.GL_TEX_IMAGE_2D)); + OpenGLHook.getInstance().hook(FuncNameString.GL_TEX_IMAGE_3D, map.get(FuncNameString.GL_TEX_IMAGE_3D)); OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_TEXTURE, map.get(FuncNameString.GL_BIND_TEXTURE)); OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_BUFFER, map.get(FuncNameString.GL_BIND_BUFFER)); OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_FRAMEBUFFER, map.get(FuncNameString.GL_BIND_FRAMEBUFFER)); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java index a4dbbd6db..46d7590d8 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java @@ -12,6 +12,7 @@ public class FuncNameString { public static final String GL_GEN_RENDERBUFFERS = "glGenRenderbuffers"; public static final String GL_DELETE_RENDERBUFFERS = "glDeleteRenderbuffers"; public static final String GL_TEX_IMAGE_2D = "glTexImage2D"; + public static final String GL_TEX_IMAGE_3D = "glTexImage3D"; public static final String GL_BIND_TEXTURE = "glBindTexture"; public static final String GL_BIND_FRAMEBUFFER = "glBindFramebuffer"; public static final String GL_BIND_BUFFER = "glBindBuffer"; 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 888626ec9..e37869172 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 @@ -13,6 +13,8 @@ public static int getFuncIndex(String targetFuncName) { return getBindFuncIndex(targetFuncName); } else if (targetFuncName.equals("glTexImage2D")) { return getGlTexImage2DIndex(); + } else if (targetFuncName.equals("glTexImage3D")) { + return getGlTexImage3DIndex(); } return 0; @@ -26,4 +28,6 @@ public static int getFuncIndex(String targetFuncName) { private static native int getGlTexImage2DIndex(); + private static native int getGlTexImage3DIndex(); + } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java index 7725d57b0..ea7941b8d 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java @@ -17,7 +17,7 @@ public class OpenglIndexDetectorService extends Service { private final static String TAG = "matrix.OpenglIndexDetectorService"; - private IOpenglIndexDetector.Stub stub = new IOpenglIndexDetector.Stub() { + private final IOpenglIndexDetector.Stub stub = new IOpenglIndexDetector.Stub() { @Override public Map seekIndex() throws RemoteException { return seekOpenglFuncIndex(); @@ -65,6 +65,8 @@ private Map seekOpenglFuncIndex() { int glTexImage2DIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_TEX_IMAGE_2D); MatrixLog.i(TAG, "glTexImage2DIndex index:" + glTexImage2DIndex); + int glTexImage3DIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_TEX_IMAGE_3D); + MatrixLog.i(TAG, "glTexImage3DIndex index:" + glTexImage3DIndex); int glBindTextureIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_BIND_TEXTURE); MatrixLog.i(TAG, "glBindTextureIndex index:" + glBindTextureIndex); @@ -76,7 +78,7 @@ private Map seekOpenglFuncIndex() { MatrixLog.i(TAG, "glBindRenderbufferIndex index:" + glBindRenderbufferIndex); if ((glGenTexturesIndex * glDeleteTexturesIndex * glGenBuffersIndex * glDeleteBuffersIndex * glGenFramebuffersIndex - * glDeleteFramebuffersIndex * glGenRenderbuffersIndex * glDeleteRenderbuffersIndex * glTexImage2DIndex + * glDeleteFramebuffersIndex * glGenRenderbuffersIndex * glDeleteRenderbuffersIndex * glTexImage2DIndex * glTexImage3DIndex * glBindTextureIndex * glBindBufferIndex * glBindFramebufferIndex * glBindRenderbufferIndex) == 0) { MatrixLog.e(TAG, "seek func index fail!"); return null; @@ -92,6 +94,7 @@ private Map seekOpenglFuncIndex() { out.put(FuncNameString.GL_GEN_RENDERBUFFERS, glGenRenderbuffersIndex); out.put(FuncNameString.GL_DELETE_RENDERBUFFERS, glDeleteRenderbuffersIndex); out.put(FuncNameString.GL_TEX_IMAGE_2D, glTexImage2DIndex); + out.put(FuncNameString.GL_TEX_IMAGE_3D, glTexImage3DIndex); out.put(FuncNameString.GL_BIND_TEXTURE, glBindTextureIndex); out.put(FuncNameString.GL_BIND_BUFFER, glBindBufferIndex); out.put(FuncNameString.GL_BIND_FRAMEBUFFER, glBindFramebufferIndex); 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 ee036ab15..5d9f711eb 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 @@ -1,7 +1,6 @@ package com.tencent.matrix.openglleak.hook; import android.opengl.EGL14; -import android.util.Log; import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.BindCenter; @@ -24,8 +23,11 @@ public class OpenGLHook { private static final String TAG = "MicroMsg.OpenGLHook"; - private static OpenGLHook mInstance = new OpenGLHook(); - private Listener mListener; + private static final OpenGLHook mInstance = new OpenGLHook(); + private ResourceListener mResourceListener; + private ErrorListener mErrorListener; + private BindListener mBindListener; + private MemoryListener mMemoryListener; private OpenGLHook() { } @@ -34,39 +36,54 @@ public static OpenGLHook getInstance() { return mInstance; } - public void setListener(Listener l) { - mListener = l; + public void setResourceListener(ResourceListener listener) { + mResourceListener = listener; + } + + public void setErrorListener(ErrorListener listener) { + mErrorListener = listener; + } + + public void setBindListener(BindListener listener) { + mBindListener = listener; + } + + public void setMemoryListener(MemoryListener listener) { + mMemoryListener = listener; } public boolean hook(String targetFuncName, int index) { - if (targetFuncName.equals(FuncNameString.GL_GET_ERROR)) { - return hookGlGetError(index); - } else if (targetFuncName.equals(FuncNameString.GL_GEN_TEXTURES)) { - return hookGlGenTextures(index); - } else if (targetFuncName.equals(FuncNameString.GL_DELETE_TEXTURES)) { - return hookGlDeleteTextures(index); - } else if (targetFuncName.equals(FuncNameString.GL_GEN_BUFFERS)) { - return hookGlGenBuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_DELETE_BUFFERS)) { - return hookGlDeleteBuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_GEN_FRAMEBUFFERS)) { - return hookGlGenFramebuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_DELETE_FRAMEBUFFERS)) { - return hookGlDeleteFramebuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_GEN_RENDERBUFFERS)) { - return hookGlGenRenderbuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_DELETE_RENDERBUFFERS)) { - return hookGlDeleteRenderbuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_TEX_IMAGE_2D)) { - return hookGlTexImage2D(index); - } else if (targetFuncName.equals(FuncNameString.GL_BIND_TEXTURE)) { - return hookGlBindTexture(index); - } else if (targetFuncName.equals(FuncNameString.GL_BIND_BUFFER)) { - return hookGlBindBuffer(index); - } else if (targetFuncName.equals(FuncNameString.GL_BIND_FRAMEBUFFER)) { - return hookGlBindFramebuffer(index); - } else if (targetFuncName.equals(FuncNameString.GL_BIND_RENDERBUFFER)) { - return hookGlBindRenderbuffer(index); + switch (targetFuncName) { + case FuncNameString.GL_GET_ERROR: + return hookGlGetError(index); + case FuncNameString.GL_GEN_TEXTURES: + return hookGlGenTextures(index); + case FuncNameString.GL_DELETE_TEXTURES: + return hookGlDeleteTextures(index); + case FuncNameString.GL_GEN_BUFFERS: + return hookGlGenBuffers(index); + case FuncNameString.GL_DELETE_BUFFERS: + return hookGlDeleteBuffers(index); + case FuncNameString.GL_GEN_FRAMEBUFFERS: + return hookGlGenFramebuffers(index); + case FuncNameString.GL_DELETE_FRAMEBUFFERS: + return hookGlDeleteFramebuffers(index); + case FuncNameString.GL_GEN_RENDERBUFFERS: + return hookGlGenRenderbuffers(index); + case FuncNameString.GL_DELETE_RENDERBUFFERS: + return hookGlDeleteRenderbuffers(index); + case FuncNameString.GL_TEX_IMAGE_2D: + return hookGlTexImage2D(index); + case FuncNameString.GL_TEX_IMAGE_3D: + return hookGlTexImage3D(index); + case FuncNameString.GL_BIND_TEXTURE: + return hookGlBindTexture(index); + case FuncNameString.GL_BIND_BUFFER: + return hookGlBindBuffer(index); + case FuncNameString.GL_BIND_FRAMEBUFFER: + return hookGlBindFramebuffer(index); + case FuncNameString.GL_BIND_RENDERBUFFER: + return hookGlBindRenderbuffer(index); } return false; @@ -98,6 +115,8 @@ public boolean hook(String targetFuncName, int index) { private static native boolean hookGlTexImage2D(int index); + private static native boolean hookGlTexImage3D(int index); + private static native boolean hookGlBindTexture(int index); private static native boolean hookGlBindBuffer(int index); @@ -118,8 +137,8 @@ public static void onGlGenTextures(int[] ids, String threadId, String javaStack, for (int id : ids) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, OP_GEN, LeakMonitor.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlGenTextures(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlGenTextures(openGLInfo); } } } @@ -137,8 +156,8 @@ public static void onGlDeleteTextures(int[] ids, String threadId) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, OP_GEN); OpenGLResRecorder.getInstance().delete(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlDeleteTextures(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlDeleteTextures(openGLInfo); } } } @@ -157,8 +176,8 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, OP_GEN, LeakMonitor.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlGenBuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlGenBuffers(openGLInfo); } } } @@ -176,8 +195,8 @@ public static void onGlDeleteBuffers(int[] ids, String threadId) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, OP_DELETE); OpenGLResRecorder.getInstance().delete(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlDeleteBuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlDeleteBuffers(openGLInfo); } } } @@ -196,8 +215,8 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, OP_GEN, LeakMonitor.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlGenFramebuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlGenFramebuffers(openGLInfo); } } } @@ -215,8 +234,8 @@ public static void onGlDeleteFramebuffers(int[] ids, String threadId) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, OP_DELETE); OpenGLResRecorder.getInstance().delete(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlDeleteFramebuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlDeleteFramebuffers(openGLInfo); } } } @@ -235,8 +254,8 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, OP_GEN, LeakMonitor.getInstance().getCurrentActivityName(), counter); OpenGLResRecorder.getInstance().gen(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlGenRenderbuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlGenRenderbuffers(openGLInfo); } } } @@ -254,8 +273,8 @@ public static void onGlDeleteRenderbuffers(int[] ids, String threadId) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, OP_DELETE); OpenGLResRecorder.getInstance().delete(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlDeleteRenderbuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlDeleteRenderbuffers(openGLInfo); } } } @@ -268,6 +287,10 @@ public static void onGlBindTexture(int target, int id) { } OpenGLInfo info = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, eglContextId, OP_BIND); BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.TEXTURE, target, eglContextId, info); + + if (getInstance().mBindListener != null) { + getInstance().mBindListener.onGlBindTexture(target, id); + } } public static void onGlBindBuffer(int target, int id) { @@ -277,6 +300,10 @@ public static void onGlBindBuffer(int target, int id) { } OpenGLInfo info = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, eglContextId, OP_BIND); BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.BUFFER, target, eglContextId, info); + + if (getInstance().mBindListener != null) { + getInstance().mBindListener.onGlBindBuffer(target, id); + } } public static void onGlBindFramebuffer(int target, int id) { @@ -286,6 +313,10 @@ public static void onGlBindFramebuffer(int target, int id) { } OpenGLInfo info = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, eglContextId, OP_BIND); BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.FRAME_BUFFERS, target, eglContextId, info); + + if (getInstance().mBindListener != null) { + getInstance().mBindListener.onGlBindFramebuffer(target, id); + } } public static void onGlBindRenderbuffer(int target, int id) { @@ -295,16 +326,20 @@ public static void onGlBindRenderbuffer(int target, int id) { } OpenGLInfo info = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, eglContextId, OP_BIND); BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.RENDER_BUFFERS, target, eglContextId, info); + + if (getInstance().mBindListener != null) { + getInstance().mBindListener.onGlBindRenderbuffer(target, id); + } } - public static void onGlTexImage2D(int target, long size) { + public static void onGlTexImage2D(int target, long size, int internalFormat, int format, int type) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } OpenGLInfo info = BindCenter.getInstance().getCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); if (info == null) { - MatrixLog.e(TAG, "getCurrentResourceIdByTarget result == null"); + MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget result == null"); return; } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); @@ -312,17 +347,69 @@ public static void onGlTexImage2D(int target, long size) { openGLInfo.setSize(size); OpenGLResRecorder.getInstance().replace(openGLInfo); } - Log.e("Backtrace.Benchmark", "onGlTexImage2D egl context = " + eglContextId); + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlTexImage2D(target, size, internalFormat, format, type); + } + + } + + public static void onGlTexImage3D(int target, long size, int internalFormat, int format, int type) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLInfo info = BindCenter.getInstance().getCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + if (info == null) { + MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null"); + return; + } + OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); + if (openGLInfo != null) { + openGLInfo.setSize(size); + OpenGLResRecorder.getInstance().replace(openGLInfo); + } + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlTexImage3D(target, size, internalFormat, format, type); + } + } public static void onGetError(int eid) { - if (getInstance().mListener != null) { - getInstance().mListener.onGetError(new OpenGLInfo(eid)); + if (getInstance().mErrorListener != null) { + getInstance().mErrorListener.onGlError(eid); } } - public interface Listener { - void onGetError(OpenGLInfo info); + + public interface ErrorListener { + + void onGlError(int eid); + + } + + public interface BindListener { + + void onGlBindTexture(int target, int id); + + void onGlBindBuffer(int target, int id); + + void onGlBindRenderbuffer(int target, int id); + + void onGlBindFramebuffer(int target, int id); + + } + + public interface MemoryListener { + + void onGlTexImage2D(int target, long size, int internalFormat, int format, int type); + + void onGlTexImage3D(int target, long size, int internalFormat, int format, int type); + + } + + public interface ResourceListener { void onGlGenTextures(OpenGLInfo info); From faeec1eb2edb6d3a087548c82b915df2a900a800 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 16 Sep 2021 20:06:44 +0800 Subject: [PATCH 036/163] add new api func seeker --- ..._matrix_openglleak_detector_FuncSeeker.cpp | 125 +++++++++++++++++- ...nt_matrix_openglleak_detector_FuncSeeker.h | 11 ++ ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 1 - .../matrix-opengl-leak/src/main/cpp/type.h | 10 ++ .../openglleak/comm/FuncNameString.java | 2 + .../openglleak/detector/FuncSeeker.java | 8 ++ .../detector/OpenglIndexDetectorService.java | 8 +- 7 files changed, 157 insertions(+), 8 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp index d5946501c..822d6dd95 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp @@ -149,7 +149,8 @@ Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getBindFuncIndex(JNIEnv * return 0; } - System_GlBind_TYPE bind_func = get_bind_func_ptr(env->GetStringUTFChars(bind_func_name, JNI_FALSE)); + System_GlBind_TYPE bind_func = get_bind_func_ptr( + env->GetStringUTFChars(bind_func_name, JNI_FALSE)); if (NULL == bind_func_name) { return 0; } @@ -208,7 +209,8 @@ _my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width extern "C" JNIEXPORT jint JNICALL -Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage2DIndex(JNIEnv *env, jclass clazz) { +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage2DIndex(JNIEnv *env, + jclass clazz) { gl_hooks_t *hooks = get_gl_hooks(); if (NULL == hooks) { return -1; @@ -251,18 +253,21 @@ static int i_glTexImage3D = 0; static bool has_hook_glTexImage3D = false; GL_APICALL void GL_APIENTRY -_my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { +_my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { if (!has_hook_glTexImage3D) { has_hook_glTexImage3D = true; } - _system_glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); + _system_glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, + pixels); } extern "C" JNIEXPORT jint JNICALL -Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage3DIndex(JNIEnv *env, jclass clazz) { +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage3DIndex(JNIEnv *env, + jclass clazz) { gl_hooks_t *hooks = get_gl_hooks(); if (NULL == hooks) { return -1; @@ -287,7 +292,7 @@ Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage3DIndex(JNIE *replaceMethod = (void *) _my_glTexImage3D; - glTexImage3D(0, 0, 0, 0,0, 0, 0, 0, 0, NULL); + glTexImage3D(0, 0, 0, 0, 0, 0, 0, 0, 0, NULL); } // release @@ -298,3 +303,111 @@ Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage3DIndex(JNIE return result; } + + +static System_GlBufferData _system_glBufferData = NULL; +static int i_glBufferData = 0; +static bool has_hook_glBufferData = false; + +GL_APICALL void GL_APIENTRY +_my_glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) { + if (!has_hook_glBufferData) { + has_hook_glBufferData = true; + } + + _system_glBufferData(target, size, data, usage); +} + +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlBufferDataIndex(JNIEnv *env, + jclass clazz) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return -1; + } + + for (i_glBufferData = 0; i_glBufferData < 1000; i_glBufferData++) { + if (has_hook_glBufferData) { + i_glBufferData = i_glBufferData - 1; + + void **method = (void **) (&hooks->gl.foo1 + i_glBufferData); + *method = (void *) _system_glBufferData; + break; + } + + if (_system_glBufferData != NULL) { + void **method = (void **) (&hooks->gl.foo1 + (i_glBufferData - 1)); + *method = (void *) _system_glBufferData; + } + + void **replaceMethod = (void **) (&hooks->gl.foo1 + i_glBufferData); + _system_glBufferData = (System_GlBufferData) *replaceMethod; + + *replaceMethod = (void *) _my_glBufferData; + + glBufferData(0, 0, NULL, 0); + } + + // release + _system_glBufferData = NULL; + has_hook_glBufferData = false; + int result = i_glBufferData; + i_glBufferData = 0; + + return result; +} + +static System_GlRenderbufferStorage _system_glRenderbufferStorage = NULL; +static int i_glRenderbufferStorage = 0; +static bool has_hook_glRenderbufferStorage = false; + +GL_APICALL void GL_APIENTRY +_my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { + if (!has_hook_glRenderbufferStorage) { + has_hook_glRenderbufferStorage = true; + } + + _system_glRenderbufferStorage(target, internalformat, width, height.); +} + +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlRenderbufferStorageIndex(JNIEnv *env, + jclass clazz) { + + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return -1; + } + + for (i_glRenderbufferStorage = 0; i_glRenderbufferStorage < 1000; i_glRenderbufferStorage++) { + if (has_hook_glRenderbufferStorage) { + i_glRenderbufferStorage = i_glRenderbufferStorage - 1; + + void **method = (void **) (&hooks->gl.foo1 + i_glRenderbufferStorage); + *method = (void *) _system_glRenderbufferStorage; + break; + } + + if (_system_glRenderbufferStorage != NULL) { + void **method = (void **) (&hooks->gl.foo1 + (i_glRenderbufferStorage - 1)); + *method = (void *) _system_glRenderbufferStorage; + } + + void **replaceMethod = (void **) (&hooks->gl.foo1 + i_glRenderbufferStorage); + _system_glRenderbufferStorage = (System_GlRenderbufferStorage) *replaceMethod; + + *replaceMethod = (void *) _my_glRenderbufferStorage; + + glRenderbufferStorage(0, 0, 0, 0); + } + + // release + _system_glRenderbufferStorage = NULL; + has_hook_glRenderbufferStorage = false; + int result = i_glRenderbufferStorage; + i_glRenderbufferStorage = 0; + + return result; +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h index 31ebfcb31..f6eb2436e 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.h @@ -37,6 +37,17 @@ extern "C" JNIEXPORT jint JNICALL Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage3DIndex(JNIEnv *env, jclass clazz); + +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlBufferDataIndex(JNIEnv *env, jclass clazz); + + +extern "C" +JNIEXPORT jint JNICALL +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlRenderbufferStorageIndex(JNIEnv *env, jclass clazz); + + #ifdef __cplusplus } #endif 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 6d2c8732f..39cbb0ef4 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 @@ -360,4 +360,3 @@ Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindRenderbuffer(JNIEnv return true; } - 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 ed97e3f91..bb6ad6427 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 @@ -51,6 +51,16 @@ typedef void (*System_GlTexImage3D)(GLenum target, GLenum type, const void *data); +typedef void (*System_GlBufferData)(GLenum target, + GLsizeiptr size, + const GLvoid *data, + GLenum usage); + +typedef void (*System_GlRenderbufferStorage)(GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height); + 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/comm/FuncNameString.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java index 46d7590d8..b1895745f 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/comm/FuncNameString.java @@ -17,5 +17,7 @@ public class FuncNameString { public static final String GL_BIND_FRAMEBUFFER = "glBindFramebuffer"; public static final String GL_BIND_BUFFER = "glBindBuffer"; public static final String GL_BIND_RENDERBUFFER = "glBindRenderbuffer"; + public static final String GL_BUFFER_DATA = "glBufferData"; + public static final String GL_RENDER_BUFFER_STORAGE = "glRenderbufferStorage"; } 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 e37869172..363a90ce8 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 @@ -15,6 +15,10 @@ public static int getFuncIndex(String targetFuncName) { return getGlTexImage2DIndex(); } else if (targetFuncName.equals("glTexImage3D")) { return getGlTexImage3DIndex(); + } else if (targetFuncName.equals("glBufferData")) { + return getGlBufferDataIndex(); + } else if (targetFuncName.equals("glRenderbufferStorage")) { + return getGlRenderbufferStorageIndex(); } return 0; @@ -30,4 +34,8 @@ public static int getFuncIndex(String targetFuncName) { private static native int getGlTexImage3DIndex(); + private static native int getGlBufferDataIndex(); + + private static native int getGlRenderbufferStorageIndex(); + } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java index ea7941b8d..a97238892 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java @@ -77,9 +77,15 @@ private Map seekOpenglFuncIndex() { int glBindRenderbufferIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_BIND_RENDERBUFFER); MatrixLog.i(TAG, "glBindRenderbufferIndex index:" + glBindRenderbufferIndex); + int glBufferDataIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_BUFFER_DATA); + MatrixLog.i(TAG, "glBufferData index:" + glBufferDataIndex); + int glRenderbufferStorageIndex = FuncSeeker.getFuncIndex(FuncNameString.GL_RENDER_BUFFER_STORAGE); + MatrixLog.i(TAG, "glRenderbufferStorage index:" + glRenderbufferStorageIndex); + if ((glGenTexturesIndex * glDeleteTexturesIndex * glGenBuffersIndex * glDeleteBuffersIndex * glGenFramebuffersIndex * glDeleteFramebuffersIndex * glGenRenderbuffersIndex * glDeleteRenderbuffersIndex * glTexImage2DIndex * glTexImage3DIndex - * glBindTextureIndex * glBindBufferIndex * glBindFramebufferIndex * glBindRenderbufferIndex) == 0) { + * glBindTextureIndex * glBindBufferIndex * glBindFramebufferIndex * glBindRenderbufferIndex + * glRenderbufferStorageIndex * glBufferDataIndex) == 0) { MatrixLog.e(TAG, "seek func index fail!"); return null; } From b1e52c0242b1d27d610b71a9ee66b519312be0cd Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 17 Sep 2021 15:14:09 +0800 Subject: [PATCH 037/163] pick b0ed08f7092b5ff21a13147b2ec3197df91cd4f7 --- ..._matrix_openglleak_detector_FuncSeeker.cpp | 8 +- ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 39 ++++++ .../src/main/cpp/my_functions.h | 111 +++++++++++------ .../matrix-opengl-leak/src/main/cpp/type.cpp | 44 +++++++ .../matrix-opengl-leak/src/main/cpp/type.h | 2 + .../matrix/openglleak/OpenglLeakPlugin.java | 10 +- .../detector/OpenglIndexDetectorService.java | 2 + .../matrix/openglleak/hook/OpenGLHook.java | 67 +++++++++- .../matrix/openglleak/statistics/BindMap.java | 115 ++++++------------ .../openglleak/statistics/OpenGLInfo.java | 1 + 10 files changed, 278 insertions(+), 121 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp index 822d6dd95..2afafbfa1 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp @@ -266,8 +266,7 @@ _my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width extern "C" JNIEXPORT jint JNICALL -Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage3DIndex(JNIEnv *env, - jclass clazz) { +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlTexImage3DIndex(JNIEnv *env, jclass clazz) { gl_hooks_t *hooks = get_gl_hooks(); if (NULL == hooks) { return -1; @@ -320,8 +319,7 @@ _my_glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usag extern "C" JNIEXPORT jint JNICALL -Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlBufferDataIndex(JNIEnv *env, - jclass clazz) { +Java_com_tencent_matrix_openglleak_detector_FuncSeeker_getGlBufferDataIndex(JNIEnv *env, jclass clazz) { gl_hooks_t *hooks = get_gl_hooks(); if (NULL == hooks) { return -1; @@ -368,7 +366,7 @@ _my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, G has_hook_glRenderbufferStorage = true; } - _system_glRenderbufferStorage(target, internalformat, width, height.); + _system_glRenderbufferStorage(target, internalformat, width, height); } extern "C" 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 39cbb0ef4..b33af5ea7 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 @@ -44,6 +44,8 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_onGlBindRenderbuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindRenderbuffer", "(II)V"); method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IJIII)V"); method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IJIII)V"); + method_onGlBufferData = env->GetStaticMethodID(class_OpenGLHook, "onGlBufferData", "(IJI)V"); + method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IJI)V"); return true; } @@ -360,3 +362,40 @@ Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindRenderbuffer(JNIEnv return true; } + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBufferData(JNIEnv *env, jclass clazz, jint index) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return false; + } + + void **origFunPtr = NULL; + + origFunPtr = (void **) (&hooks->gl.foo1 + index); + system_glBufferData = (System_GlBufferData) *origFunPtr; + *origFunPtr = (void *) my_glBufferData; + + return true; +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlRenderbufferStorage(JNIEnv *env, jclass clazz, jint index) { + gl_hooks_t *hooks = get_gl_hooks(); + if (NULL == hooks) { + return false; + } + + void **origFunPtr = NULL; + + origFunPtr = (void **) (&hooks->gl.foo1 + index); + system_glRenderbufferStorage = (System_GlRenderbufferStorage) *origFunPtr; + *origFunPtr = (void *) my_glRenderbufferStorage; + + return true; +} + + + 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 2763be569..415327757 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 @@ -20,6 +20,7 @@ using namespace std; #define MEMHOOK_BACKTRACE_MAX_FRAMES MAX_FRAME_SHORT #define RENDER_THREAD_NAME "RenderThread" +#define max(a, b) ((a) > (b) ? (a) : (b)) static System_GlNormal_TYPE system_glGenTextures = NULL; static System_GlNormal_TYPE system_glDeleteTextures = NULL; @@ -36,6 +37,8 @@ static System_GlBind_TYPE system_glBindTexture = NULL; static System_GlBind_TYPE system_glBindBuffer = NULL; 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 JavaVM *m_java_vm; @@ -56,6 +59,8 @@ static jmethodID method_onGlBindFramebuffer; static jmethodID method_onGlBindRenderbuffer; static jmethodID method_onGlTexImage2D; static jmethodID method_onGlTexImage3D; +static jmethodID method_onGlBufferData; +static jmethodID method_onGlRenderbufferStorage; const size_t BUF_SIZE = 1024; @@ -63,11 +68,13 @@ static pthread_once_t g_onceInitTls = PTHREAD_ONCE_INIT; static pthread_key_t g_tlsJavaEnv; static bool is_stacktrace_enabled = true; + void enable_stacktrace(bool enable) { is_stacktrace_enabled = enable; } static bool is_javastack_enabled = true; + void enable_javastack(bool enable) { is_javastack_enabled = enable; } @@ -175,21 +182,23 @@ GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { get_thread_id_string(thread_id); jstring j_thread_id = env->NewStringUTF(thread_id); - wechat_backtrace::Backtrace* backtracePrt = 0; + wechat_backtrace::Backtrace *backtracePrt = 0; if (is_stacktrace_enabled) { - wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER(MEMHOOK_BACKTRACE_MAX_FRAMES); + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( + MEMHOOK_BACKTRACE_MAX_FRAMES); 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(backtracePrt->frames.get(), backtracePrt->max_frames, + backtracePrt->frame_size); } jstring java_stack; char *javaStack; - if(is_javastack_enabled) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -200,7 +209,7 @@ GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { java_stack, (int64_t) backtracePrt); delete[] result; - if(is_javastack_enabled) { + if (is_javastack_enabled) { free(javaStack); } @@ -268,21 +277,23 @@ GL_APICALL void GL_APIENTRY my_glGenBuffers(GLsizei n, GLuint *buffers) { get_thread_id_string(thread_id); jstring j_thread_id = env->NewStringUTF(thread_id); - wechat_backtrace::Backtrace* backtracePrt = 0; + wechat_backtrace::Backtrace *backtracePrt = 0; if (is_stacktrace_enabled) { - wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER(MEMHOOK_BACKTRACE_MAX_FRAMES); + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( + MEMHOOK_BACKTRACE_MAX_FRAMES); 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(backtracePrt->frames.get(), backtracePrt->max_frames, + backtracePrt->frame_size); } jstring java_stack; char *javaStack; - if(is_javastack_enabled) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -293,7 +304,7 @@ GL_APICALL void GL_APIENTRY my_glGenBuffers(GLsizei n, GLuint *buffers) { java_stack, (int64_t) backtracePrt); delete[] result; - if(is_javastack_enabled) { + if (is_javastack_enabled) { free(javaStack); } @@ -360,21 +371,23 @@ GL_APICALL void GL_APIENTRY my_glGenFramebuffers(GLsizei n, GLuint *buffers) { get_thread_id_string(thread_id); jstring j_thread_id = env->NewStringUTF(thread_id); - wechat_backtrace::Backtrace* backtracePrt = 0; + wechat_backtrace::Backtrace *backtracePrt = 0; if (is_stacktrace_enabled) { - wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER(MEMHOOK_BACKTRACE_MAX_FRAMES); + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( + MEMHOOK_BACKTRACE_MAX_FRAMES); 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(backtracePrt->frames.get(), backtracePrt->max_frames, + backtracePrt->frame_size); } jstring java_stack; char *javaStack; - if(is_javastack_enabled) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -385,7 +398,7 @@ GL_APICALL void GL_APIENTRY my_glGenFramebuffers(GLsizei n, GLuint *buffers) { j_thread_id, java_stack, (int64_t) backtracePrt); delete[] result; - if(is_javastack_enabled) { + if (is_javastack_enabled) { free(javaStack); } @@ -453,21 +466,23 @@ GL_APICALL void GL_APIENTRY my_glGenRenderbuffers(GLsizei n, GLuint *buffers) { get_thread_id_string(thread_id); jstring j_thread_id = env->NewStringUTF(thread_id); - wechat_backtrace::Backtrace* backtracePrt = 0; + wechat_backtrace::Backtrace *backtracePrt = 0; if (is_stacktrace_enabled) { - wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER(MEMHOOK_BACKTRACE_MAX_FRAMES); + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( + MEMHOOK_BACKTRACE_MAX_FRAMES); 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(backtracePrt->frames.get(), backtracePrt->max_frames, + backtracePrt->frame_size); } jstring java_stack; char *javaStack; - if(is_javastack_enabled) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -478,7 +493,7 @@ GL_APICALL void GL_APIENTRY my_glGenRenderbuffers(GLsizei n, GLuint *buffers) { j_thread_id, java_stack, (int64_t) backtracePrt); delete[] result; - if(is_javastack_enabled) { + if (is_javastack_enabled) { free(javaStack); } @@ -540,32 +555,38 @@ GL_APICALL int GL_APIENTRY my_glGetError() { return 0; } -GL_APICALL void GL_APIENTRY my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, - GLint border, GLenum format, GLenum type, const void *pixels) { - if(NULL != system_glTexImage2D) { - system_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); +GL_APICALL void GL_APIENTRY +my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const void *pixels) { + if (NULL != system_glTexImage2D) { + system_glTexImage2D(target, level, internalformat, width, height, border, format, type, + pixels); int pixel = Utils::getSizeOfPerPixel(internalformat, format, type); long size = width * height * pixel; JNIEnv *env = GET_ENV(); - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, size, internalformat, format, type); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, size, + internalformat, format, type); } } -GL_APICALL void GL_APIENTRY my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, - GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { - if(NULL != system_glTexImage3D) { - system_glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); +GL_APICALL void GL_APIENTRY +my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { + if (NULL != system_glTexImage3D) { + system_glTexImage3D(target, level, internalformat, width, height, depth, border, format, + type, pixels); int pixel = Utils::getSizeOfPerPixel(internalformat, format, type); long size = width * height * depth * pixel; JNIEnv *env = GET_ENV(); - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage3D, target, size, internalformat, format, type); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage3D, target, size, + internalformat, format, type); } } GL_APICALL void GL_APIENTRY my_glBindTexture(GLenum target, GLuint resourceId) { - if(NULL != system_glBindTexture) { + if (NULL != system_glBindTexture) { system_glBindTexture(target, resourceId); JNIEnv *env = GET_ENV(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindTexture, target, resourceId); @@ -573,7 +594,7 @@ GL_APICALL void GL_APIENTRY my_glBindTexture(GLenum target, GLuint resourceId) { } GL_APICALL void GL_APIENTRY my_glBindBuffer(GLenum target, GLuint resourceId) { - if(NULL != system_glBindTexture) { + if (NULL != system_glBindTexture) { system_glBindBuffer(target, resourceId); JNIEnv *env = GET_ENV(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindBuffer, target, resourceId); @@ -582,7 +603,7 @@ GL_APICALL void GL_APIENTRY my_glBindBuffer(GLenum target, GLuint resourceId) { } GL_APICALL void GL_APIENTRY my_glBindFramebuffer(GLenum target, GLuint resourceId) { - if(NULL != system_glBindTexture) { + if (NULL != system_glBindTexture) { system_glBindFramebuffer(target, resourceId); JNIEnv *env = GET_ENV(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindFramebuffer, target, resourceId); @@ -591,13 +612,33 @@ GL_APICALL void GL_APIENTRY my_glBindFramebuffer(GLenum target, GLuint resourceI } GL_APICALL void GL_APIENTRY my_glBindRenderbuffer(GLenum target, GLuint resourceId) { - if(NULL != system_glBindTexture) { + if (NULL != system_glBindTexture) { system_glBindRenderbuffer(target, resourceId); JNIEnv *env = GET_ENV(); - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindRenderbuffer, target, resourceId); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindRenderbuffer, target, + resourceId); } } +GL_APICALL void GL_APIENTRY +my_glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) { + if (NULL != system_glBindTexture) { + system_glBufferData(target, size, data, usage); + JNIEnv *env = GET_ENV(); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBufferData, target, size, usage); + } +} + +GL_APICALL void GL_APIENTRY +my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { + if (NULL != system_glBindTexture) { + system_glRenderbufferStorage(target, internalformat, width, height); + JNIEnv *env = GET_ENV(); + long size = Utils::getSizeByInternalFormat(internalformat) * max(width, height); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlRenderbufferStorage, target, size, + internalformat); + } +} #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.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp index 0dde4114a..b35b317e9 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp @@ -46,6 +46,50 @@ namespace Utils { /* * support by OpenGL ES Software Development Kit */ + + int getSizeByInternalFormat(GLint internalformat) { + + switch (internalformat) { + case GL_R8: return 1; + case GL_R8UI: return 1; + case GL_R8I: return 1; + case GL_R16UI: return 2; + case GL_R16I: return 2; + case GL_R32UI: return 4; + case GL_R32I: return 4; + case GL_RG8: return 1; + case GL_RG8UI: return 1; + case GL_RG8I: return 1; + case GL_RG16UI: return 2; + case GL_RG16I: return 2; + case GL_RG32UI: return 4; + case GL_RG32I: return 4; + case GL_RGB8: return 3; + case GL_RGB565: return 2; + case GL_RGBA8: return 4; + case GL_SRGB8_ALPHA8: return 4; + case GL_RGB5_A1: return 2; + case GL_RGBA4: return 2; + case GL_RGB10_A2: return 4; + case GL_RGBA8UI: return 4; + case GL_RGBA8I: return 4; + case GL_RGB10_A2UI: return 4; + case GL_RGBA16UI: return 8; + case GL_RGBA16I: return 8; + case GL_RGBA32I: return 16; + case GL_RGBA32UI: return 16; + case GL_DEPTH_COMPONENT16: return 2; + case GL_DEPTH_COMPONENT24: return 3; + case GL_DEPTH_COMPONENT32F: return 4; + case GL_DEPTH24_STENCIL8: return 4; + case GL_DEPTH32F_STENCIL8: return 5; + case GL_STENCIL_INDEX8: return 1; + default:return 0; + } + } + + + int getSizeOfPerPixel(GLint internalformat, GLenum format, GLenum type) { // GL_RED 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 bb6ad6427..63bd9ed5d 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 @@ -69,6 +69,8 @@ namespace Utils { int getSizeOfPerPixel(GLint internalformat, GLenum format, GLenum type); + int getSizeByInternalFormat(GLint internalformat); + } #endif //OPENGL_API_HOOK_TYPE_H \ No newline at end of file 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 608201767..5becb7d5c 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 @@ -81,7 +81,8 @@ private void executeHook(IBinder iBinder) { * map.get(FuncNameString.GL_GEN_RENDERBUFFERS) * map.get(FuncNameString.GL_DELETE_RENDERBUFFERS) * map.get(FuncNameString.GL_TEX_IMAGE_2D) * map.get(FuncNameString.GL_BIND_TEXTURE) * map.get(FuncNameString.GL_BIND_BUFFER) * map.get(FuncNameString.GL_BIND_FRAMEBUFFER) - * map.get(FuncNameString.GL_BIND_RENDERBUFFER); + * map.get(FuncNameString.GL_BIND_RENDERBUFFER) * map.get(FuncNameString.GL_TEX_IMAGE_3D) + * map.get(FuncNameString.GL_RENDER_BUFFER_STORAGE) * map.get(FuncNameString.GL_BUFFER_DATA); MatrixLog.e(TAG, "hookResult = " + hookResult); if (hookResult == 0) { if (OpenglLeakPlugin.sCallback != null) { @@ -106,8 +107,13 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_TEX_IMAGE_3D, map.get(FuncNameString.GL_TEX_IMAGE_3D)); OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_TEXTURE, map.get(FuncNameString.GL_BIND_TEXTURE)); OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_BUFFER, map.get(FuncNameString.GL_BIND_BUFFER)); - OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_FRAMEBUFFER, map.get(FuncNameString.GL_BIND_FRAMEBUFFER)); +// OpenGLHook.getInstance().hook(FuncNameString.GL_BIND_FRAMEBUFFER, map.get(FuncNameString.GL_BIND_FRAMEBUFFER)); 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)); + + EGLHelper.release(); + MatrixLog.e(TAG, "hook finish"); // 泄漏监控 diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java index a97238892..7bde78637 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java @@ -105,6 +105,8 @@ private Map seekOpenglFuncIndex() { out.put(FuncNameString.GL_BIND_BUFFER, glBindBufferIndex); out.put(FuncNameString.GL_BIND_FRAMEBUFFER, glBindFramebufferIndex); out.put(FuncNameString.GL_BIND_RENDERBUFFER, glBindRenderbufferIndex); + out.put(FuncNameString.GL_BUFFER_DATA, glBufferDataIndex); + out.put(FuncNameString.GL_RENDER_BUFFER_STORAGE, glRenderbufferStorageIndex); MatrixLog.i(TAG, "seek func index succ!"); 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 5d9f711eb..838ca619a 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 @@ -84,6 +84,10 @@ public boolean hook(String targetFuncName, int index) { return hookGlBindFramebuffer(index); case FuncNameString.GL_BIND_RENDERBUFFER: return hookGlBindRenderbuffer(index); + case FuncNameString.GL_BUFFER_DATA: + return hookGlBufferData(index); + case FuncNameString.GL_RENDER_BUFFER_STORAGE: + return hookGlRenderbufferStorage(index); } return false; @@ -125,6 +129,10 @@ public boolean hook(String targetFuncName, int index) { private static native boolean hookGlBindRenderbuffer(int index); + private static native boolean hookGlBufferData(int index); + + private static native boolean hookGlRenderbufferStorage(int index); + public static void onGlGenTextures(int[] ids, String threadId, String javaStack, long nativeStackPtr) { if (ids.length > 0) { AtomicInteger counter = new AtomicInteger(ids.length); @@ -333,6 +341,9 @@ public static void onGlBindRenderbuffer(int target, int id) { } public static void onGlTexImage2D(int target, long size, int internalFormat, int format, int type) { + if (Thread.currentThread().getName().equals("RenderThread")) { + return; + } long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); @@ -344,7 +355,7 @@ public static void onGlTexImage2D(int target, long size, int internalFormat, int } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); if (openGLInfo != null) { - openGLInfo.setSize(size); + openGLInfo.setSize(openGLInfo.getSize() + size); OpenGLResRecorder.getInstance().replace(openGLInfo); } @@ -366,7 +377,7 @@ public static void onGlTexImage3D(int target, long size, int internalFormat, int } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); if (openGLInfo != null) { - openGLInfo.setSize(size); + openGLInfo.setSize(openGLInfo.getSize() + size); OpenGLResRecorder.getInstance().replace(openGLInfo); } @@ -376,6 +387,54 @@ public static void onGlTexImage3D(int target, long size, int internalFormat, int } + public static void onGlBufferData(int target, long size, int usage) { + if (Thread.currentThread().getName().equals("RenderThread")) { + return; + } + MatrixLog.e("Backtrace.Benchmark", "onGlBufferData call, target = " + target + ", size = " + size + ", usage = " + usage); + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLInfo info = BindCenter.getInstance().getCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, eglContextId, target); + if (info == null) { + MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null"); + return; + } + OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); + if (openGLInfo != null) { + openGLInfo.setSize(openGLInfo.getSize() + size); + OpenGLResRecorder.getInstance().replace(openGLInfo); + } + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlBufferData(target, size, usage); + } + + } + + public static void onGlRenderbufferStorage(int target, long size, int internalformat) { + MatrixLog.e("Backtrace.Benchmark", "onGlRenderbufferStorage call, target = " + target + ", size = " + size + ", internalformat = " + internalformat); + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLInfo info = BindCenter.getInstance().getCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, target); + if (info == null) { + MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null"); + return; + } + OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); + if (openGLInfo != null) { + openGLInfo.setSize(openGLInfo.getSize() + size); + OpenGLResRecorder.getInstance().replace(openGLInfo); + } + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlRenderbufferStorage(target, size, internalformat); + } + } + public static void onGetError(int eid) { if (getInstance().mErrorListener != null) { getInstance().mErrorListener.onGlError(eid); @@ -407,6 +466,10 @@ public interface MemoryListener { void onGlTexImage3D(int target, long size, int internalFormat, int format, int type); + void onGlBufferData(int target, long size, int usage); + + void onGlRenderbufferStorage(int target, long size, int internalFormat); + } public interface ResourceListener { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java index bb405dd70..00d1be8e1 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java @@ -1,15 +1,29 @@ package com.tencent.matrix.openglleak.statistics; import com.tencent.matrix.openglleak.utils.ExecuteCenter; -import com.tencent.matrix.util.MatrixLog; import java.util.HashMap; import java.util.Map; +import static android.opengl.GLES20.GL_ARRAY_BUFFER; +import static android.opengl.GLES20.GL_ELEMENT_ARRAY_BUFFER; +import static android.opengl.GLES20.GL_RENDERBUFFER; import static android.opengl.GLES20.GL_TEXTURE_2D; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; +import static android.opengl.GLES30.GL_COPY_READ_BUFFER; +import static android.opengl.GLES30.GL_COPY_WRITE_BUFFER; +import static android.opengl.GLES30.GL_PIXEL_PACK_BUFFER; +import static android.opengl.GLES30.GL_PIXEL_UNPACK_BUFFER; import static android.opengl.GLES30.GL_TEXTURE_2D_ARRAY; import static android.opengl.GLES30.GL_TEXTURE_3D; +import static android.opengl.GLES30.GL_TRANSFORM_FEEDBACK_BUFFER; +import static android.opengl.GLES30.GL_UNIFORM_BUFFER; import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP; +import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; +import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; public class BindMap { @@ -19,7 +33,6 @@ public class BindMap { private final Map> bindTextureMap; private final Map> bindBufferMap; - private final Map> bindFramebufferMap; private final Map> bindRenderbufferMap; static BindMap getInstance() { @@ -29,61 +42,29 @@ static BindMap getInstance() { private BindMap() { bindTextureMap = new HashMap<>(); bindBufferMap = new HashMap<>(); - bindFramebufferMap = new HashMap<>(); bindRenderbufferMap = new HashMap<>(); } - private OpenGLInfo getBindTextureInfo(long eglContextId, int target) { - synchronized (bindTextureMap) { - Map subTextureMap = bindTextureMap.get(eglContextId); + private OpenGLInfo getBindMapInfo(final Map> bindMap, long eglContextId, int target) { + synchronized (bindMap) { + Map subTextureMap = bindMap.get(eglContextId); if (subTextureMap == null) { subTextureMap = new HashMap<>(); - bindTextureMap.put(eglContextId, subTextureMap); + bindMap.put(eglContextId, subTextureMap); } return subTextureMap.get(target); } } - private OpenGLInfo getBindBufferInfo(long eglContextId, int target) { - synchronized (bindBufferMap) { - Map subBufferMap = bindBufferMap.get(eglContextId); - if (subBufferMap == null) { - subBufferMap = new HashMap<>(); - } - return subBufferMap.get(target); - } - } - - private OpenGLInfo getBindFramebufferInfo(long eglContextId, int target) { - synchronized (bindFramebufferMap) { - Map subFramebufferMap = bindFramebufferMap.get(eglContextId); - if (subFramebufferMap == null) { - subFramebufferMap = new HashMap<>(); - } - return subFramebufferMap.get(target); - } - } - - private OpenGLInfo getBindRenderbufferInfo(long eglContextId, int target) { - synchronized (bindRenderbufferMap) { - Map subRenderbufferMap = bindRenderbufferMap.get(eglContextId); - if (subRenderbufferMap == null) { - subRenderbufferMap = new HashMap<>(); - } - return subRenderbufferMap.get(target); - } - } - - private void putInBindTextureMap(final long eglContext, final int target, final OpenGLInfo info) { - if (!isSupportTargetOfTexture(target)) { - MatrixLog.e(TAG, "putInBindTextureMap input un support target = %d", target); + private void putInBindMap(final Map> bindMap, final long eglContext, final int target, final OpenGLInfo info, OpenGLInfo.TYPE type) { + if (!isSupportTarget(type, target)) { return; } - synchronized (bindTextureMap) { - Map subTextureMap = bindTextureMap.get(eglContext); + synchronized (bindMap) { + Map subTextureMap = bindMap.get(eglContext); if (subTextureMap == null) { subTextureMap = new HashMap<>(); - bindTextureMap.put(eglContext, subTextureMap); + bindMap.put(eglContext, subTextureMap); } subTextureMap.put(target, info); } @@ -96,9 +77,6 @@ private boolean isSupportTarget(OpenGLInfo.TYPE type, int target) { if (type == OpenGLInfo.TYPE.BUFFER) { return isSupportTargetOfBuffer(target); } - if (type == OpenGLInfo.TYPE.FRAME_BUFFERS) { - return isSupportTargetOfFramebuffer(target); - } if (type == OpenGLInfo.TYPE.RENDER_BUFFERS) { return isSupportTargetOfRenderbuffer(target); } @@ -106,32 +84,30 @@ private boolean isSupportTarget(OpenGLInfo.TYPE type, int target) { } private boolean isSupportTargetOfTexture(int target) { - return target == GL_TEXTURE_2D || target == GL_TEXTURE_3D - || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_CUBE_MAP; + return target == GL_TEXTURE_2D || target == GL_TEXTURE_3D || target == GL_TEXTURE_CUBE_MAP_POSITIVE_X + || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X || target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y + || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z + || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_CUBE_MAP; } private boolean isSupportTargetOfBuffer(int target) { - return false; - } - - private boolean isSupportTargetOfFramebuffer(int target) { - return false; + return target == GL_ARRAY_BUFFER || target == GL_COPY_WRITE_BUFFER || target == GL_COPY_READ_BUFFER + || target == GL_ELEMENT_ARRAY_BUFFER || target == GL_PIXEL_PACK_BUFFER || target == GL_PIXEL_UNPACK_BUFFER + || target == GL_TRANSFORM_FEEDBACK_BUFFER || target == GL_UNIFORM_BUFFER; } private boolean isSupportTargetOfRenderbuffer(int target) { - return false; + return target == GL_RENDERBUFFER; } public OpenGLInfo getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int target) { switch (type) { case BUFFER: - return getBindBufferInfo(eglContextId, target); + return getBindMapInfo(bindBufferMap, eglContextId, target); case TEXTURE: - return getBindTextureInfo(eglContextId, target); - case FRAME_BUFFERS: - return getBindFramebufferInfo(eglContextId, target); + return getBindMapInfo(bindTextureMap, eglContextId, target); case RENDER_BUFFERS: - return getBindRenderbufferInfo(eglContextId, target); + return getBindMapInfo(bindRenderbufferMap, eglContextId, target); } return null; } @@ -143,32 +119,17 @@ public void putBindInfo(final OpenGLInfo.TYPE type, final long eglContextId, fin public void run() { switch (type) { case BUFFER: - putInBindBufferMap(eglContextId, target, info); + putInBindMap(bindBufferMap, eglContextId, target, info, OpenGLInfo.TYPE.BUFFER); break; case TEXTURE: - putInBindTextureMap(eglContextId, target, info); - break; - case FRAME_BUFFERS: - putInBindFramebufferMap(eglContextId, target, info); + putInBindMap(bindTextureMap, eglContextId, target, info, OpenGLInfo.TYPE.TEXTURE); break; case RENDER_BUFFERS: - putInBindRenderbufferMap(eglContextId, target, info); + putInBindMap(bindRenderbufferMap, eglContextId, target, info, OpenGLInfo.TYPE.RENDER_BUFFERS); break; } } }); } - private void putInBindRenderbufferMap(long eglContextId, int target, OpenGLInfo info) { - //todo - } - - private void putInBindFramebufferMap(long eglContextId, int target, OpenGLInfo info) { - //todo - } - - private void putInBindBufferMap(long eglContextId, int target, OpenGLInfo info) { - //todo - } - } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index fc273d950..97c809c7a 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -59,6 +59,7 @@ public OpenGLInfo(OpenGLInfo clone) { this.maybeLeak = clone.maybeLeak; this.activityName = clone.activityName; this.counter = clone.counter; + this.size = clone.size; } public OpenGLInfo(int error) { From 1407be76a2658629617d50c483b80ba45e38cf28 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 17 Sep 2021 17:50:56 +0800 Subject: [PATCH 038/163] pick 8f0fd8be --- .../src/main/cpp/my_functions.h | 5 +- .../matrix-opengl-leak/src/main/cpp/type.cpp | 153 +++++++++++++----- .../matrix-opengl-leak/src/main/cpp/type.h | 1 + 3 files changed, 120 insertions(+), 39 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 415327757..ecde85962 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 @@ -634,8 +634,9 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL if (NULL != system_glBindTexture) { system_glRenderbufferStorage(target, internalformat, width, height); JNIEnv *env = GET_ENV(); - long size = Utils::getSizeByInternalFormat(internalformat) * max(width, height); - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlRenderbufferStorage, target, size, + long size = Utils::getRenderbufferSizeByFormula(internalformat, width, height); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlRenderbufferStorage, target, + size, internalformat); } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp index b35b317e9..5a2562365 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp @@ -46,50 +46,83 @@ namespace Utils { /* * support by OpenGL ES Software Development Kit */ - int getSizeByInternalFormat(GLint internalformat) { switch (internalformat) { - case GL_R8: return 1; - case GL_R8UI: return 1; - case GL_R8I: return 1; - case GL_R16UI: return 2; - case GL_R16I: return 2; - case GL_R32UI: return 4; - case GL_R32I: return 4; - case GL_RG8: return 1; - case GL_RG8UI: return 1; - case GL_RG8I: return 1; - case GL_RG16UI: return 2; - case GL_RG16I: return 2; - case GL_RG32UI: return 4; - case GL_RG32I: return 4; - case GL_RGB8: return 3; - case GL_RGB565: return 2; - case GL_RGBA8: return 4; - case GL_SRGB8_ALPHA8: return 4; - case GL_RGB5_A1: return 2; - case GL_RGBA4: return 2; - case GL_RGB10_A2: return 4; - case GL_RGBA8UI: return 4; - case GL_RGBA8I: return 4; - case GL_RGB10_A2UI: return 4; - case GL_RGBA16UI: return 8; - case GL_RGBA16I: return 8; - case GL_RGBA32I: return 16; - case GL_RGBA32UI: return 16; - case GL_DEPTH_COMPONENT16: return 2; - case GL_DEPTH_COMPONENT24: return 3; - case GL_DEPTH_COMPONENT32F: return 4; - case GL_DEPTH24_STENCIL8: return 4; - case GL_DEPTH32F_STENCIL8: return 5; - case GL_STENCIL_INDEX8: return 1; - default:return 0; + case GL_R8: + return 1; + case GL_R8UI: + return 1; + case GL_R8I: + return 1; + case GL_R16UI: + return 2; + case GL_R16I: + return 2; + case GL_R32UI: + return 4; + case GL_R32I: + return 4; + case GL_RG8: + return 1; + case GL_RG8UI: + return 1; + case GL_RG8I: + return 1; + case GL_RG16UI: + return 2; + case GL_RG16I: + return 2; + case GL_RG32UI: + return 4; + case GL_RG32I: + return 4; + case GL_RGB8: + return 3; + case GL_RGB565: + return 2; + case GL_RGBA8: + return 4; + case GL_SRGB8_ALPHA8: + return 4; + case GL_RGB5_A1: + return 2; + case GL_RGBA4: + return 2; + case GL_RGB10_A2: + return 4; + case GL_RGBA8UI: + return 4; + case GL_RGBA8I: + return 4; + case GL_RGB10_A2UI: + return 4; + case GL_RGBA16UI: + return 8; + case GL_RGBA16I: + return 8; + case GL_RGBA32I: + return 16; + case GL_RGBA32UI: + return 16; + case GL_DEPTH_COMPONENT16: + return 2; + case GL_DEPTH_COMPONENT24: + return 3; + case GL_DEPTH_COMPONENT32F: + return 4; + case GL_DEPTH24_STENCIL8: + return 4; + case GL_DEPTH32F_STENCIL8: + return 5; + case GL_STENCIL_INDEX8: + return 1; + default: + return 0; } } - int getSizeOfPerPixel(GLint internalformat, GLenum format, GLenum type) { // GL_RED @@ -305,4 +338,50 @@ namespace Utils { return 0; } + + /* + * support by Local Experiment + */ + + long *interval_all = nullptr; + int interval_count = -1; + + void initRenderbufferSizeFormula(GLenum internalformat) { + int format_byte = Utils::getSizeByInternalFormat(internalformat); + int interval_double[] = {65536, 131072, 262144, 524288}; + const int biggest_size = + (GL_MAX_RENDERBUFFER_SIZE * GL_MAX_RENDERBUFFER_SIZE) / format_byte; + int double_count = sizeof(interval_double) / sizeof(interval_double[0]); + interval_count = double_count + + (biggest_size - interval_double[double_count - 1]) / interval_double[0] + + 1; + + interval_all = new long[interval_count]; + for (int i = 0; i < double_count; ++i) { + interval_all[i] = interval_double[i]; + } + for (int i = double_count - 1; i < interval_count; ++i) { + interval_all[i] = interval_all[i - 1] + interval_double[0]; + } + } + + long getRenderbufferSizeByFormula(GLenum internalformat, GLsizei width, GLsizei height) { + if (interval_all == nullptr) { + initRenderbufferSizeFormula(internalformat); + } + if (interval_all == nullptr || interval_count == -1) { + return 0; + } + long graphics_alloc_size = 0; + int calculate_size = (width * height) / (Utils::getSizeByInternalFormat(internalformat) * 8); + for (int i = 0; i < interval_count; ++i) { + int val = interval_all[i]; + if (calculate_size <= val) { + graphics_alloc_size = val; + break; + } + } + return graphics_alloc_size; + } + } \ 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 63bd9ed5d..3c34fa337 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 @@ -71,6 +71,7 @@ namespace Utils { int getSizeByInternalFormat(GLint internalformat); + long getRenderbufferSizeByFormula(GLenum internalformat, GLsizei width, GLsizei height); } #endif //OPENGL_API_HOOK_TYPE_H \ No newline at end of file From 1e0aa22bf66109994589fa2bba3219166160a3bd Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 17 Sep 2021 20:49:17 +0800 Subject: [PATCH 039/163] support unsized internal formats --- .../matrix-opengl-leak/src/main/cpp/type.cpp | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp index 5a2562365..0af28a3de 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/type.cpp @@ -247,9 +247,6 @@ namespace Utils { } // GL_RGBA - if (internalformat == GL_RGBA && format == GL_RGBA) { - return 4; - } if (internalformat == GL_RGBA8 && format == GL_RGBA && type == GL_UNSIGNED_BYTE) { return 4; } @@ -335,6 +332,30 @@ namespace Utils { return 1; } + // Unsized Internal Formats + if (internalformat == GL_RGB && format == GL_RGB && type == GL_UNSIGNED_BYTE) { + return 3; + } + if (internalformat == GL_RGB && format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5) { + return 2; + } + if (internalformat == GL_RGBA && format == GL_RGBA && type == GL_UNSIGNED_BYTE) { + return 4; + } + if (internalformat == GL_RGBA && format == GL_RGBA && type == GL_UNSIGNED_SHORT_4_4_4_4) { + return 2; + } + if (internalformat == GL_LUMINANCE_ALPHA && format == GL_LUMINANCE_ALPHA && + type == GL_UNSIGNED_BYTE) { + return 2; + } + if (internalformat == GL_LUMINANCE && format == GL_LUMINANCE && type == GL_UNSIGNED_BYTE) { + return 1; + } + if (internalformat == GL_ALPHA && format == GL_ALPHA && type == GL_UNSIGNED_BYTE) { + return 1; + } + return 0; } @@ -373,7 +394,8 @@ namespace Utils { return 0; } long graphics_alloc_size = 0; - int calculate_size = (width * height) / (Utils::getSizeByInternalFormat(internalformat) * 8); + int calculate_size = + (width * height) / (Utils::getSizeByInternalFormat(internalformat) * 8); for (int i = 0; i < interval_count; ++i) { int val = interval_all[i]; if (calculate_size <= val) { From 9eb9a00210170a0d5b9e9dd0472702c7108b6fd6 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 22 Sep 2021 15:41:38 +0800 Subject: [PATCH 040/163] add more info for gl callback --- .../matrix/openglleak/hook/OpenGLHook.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 838ca619a..ed183117a 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 @@ -360,7 +360,7 @@ public static void onGlTexImage2D(int target, long size, int internalFormat, int } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage2D(target, size, internalFormat, format, type); + getInstance().mMemoryListener.onGlTexImage2D(target, size, internalFormat, format, type, info.getId(), eglContextId); } } @@ -382,7 +382,7 @@ public static void onGlTexImage3D(int target, long size, int internalFormat, int } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage3D(target, size, internalFormat, format, type); + getInstance().mMemoryListener.onGlTexImage3D(target, size, internalFormat, format, type, info.getId(), eglContextId); } } @@ -408,7 +408,7 @@ public static void onGlBufferData(int target, long size, int usage) { } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlBufferData(target, size, usage); + getInstance().mMemoryListener.onGlBufferData(target, size, usage, info.getId(), eglContextId); } } @@ -431,7 +431,7 @@ public static void onGlRenderbufferStorage(int target, long size, int internalfo } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlRenderbufferStorage(target, size, internalformat); + getInstance().mMemoryListener.onGlRenderbufferStorage(target, size, internalformat, info.getId(), eglContextId); } } @@ -462,13 +462,13 @@ public interface BindListener { public interface MemoryListener { - void onGlTexImage2D(int target, long size, int internalFormat, int format, int type); + void onGlTexImage2D(int target, long size, int internalFormat, int format, int type, int id, long eglContextId); - void onGlTexImage3D(int target, long size, int internalFormat, int format, int type); + void onGlTexImage3D(int target, long size, int internalFormat, int format, int type, int id, long eglContextId); - void onGlBufferData(int target, long size, int usage); + void onGlBufferData(int target, long size, int usage, int id, long eglContextId); - void onGlRenderbufferStorage(int target, long size, int internalFormat); + void onGlRenderbufferStorage(int target, long size, int internalFormat, int id, long eglContextId); } From f393babc719e110ad3778d117473430fa2971115 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 23 Sep 2021 19:01:19 +0800 Subject: [PATCH 041/163] pick 0a189002 --- .../tencent/matrix/openglleak/hook/OpenGLHook.java | 8 ++++---- .../matrix/openglleak/statistics/OpenGLInfo.java | 14 +++++++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) 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 ed183117a..c1ef6d97b 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 @@ -355,7 +355,7 @@ public static void onGlTexImage2D(int target, long size, int internalFormat, int } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); if (openGLInfo != null) { - openGLInfo.setSize(openGLInfo.getSize() + size); + openGLInfo.setSize(size); OpenGLResRecorder.getInstance().replace(openGLInfo); } @@ -377,7 +377,7 @@ public static void onGlTexImage3D(int target, long size, int internalFormat, int } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); if (openGLInfo != null) { - openGLInfo.setSize(openGLInfo.getSize() + size); + openGLInfo.setSize(size); OpenGLResRecorder.getInstance().replace(openGLInfo); } @@ -403,7 +403,7 @@ public static void onGlBufferData(int target, long size, int usage) { } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); if (openGLInfo != null) { - openGLInfo.setSize(openGLInfo.getSize() + size); + openGLInfo.setSize(size); OpenGLResRecorder.getInstance().replace(openGLInfo); } @@ -426,7 +426,7 @@ public static void onGlRenderbufferStorage(int target, long size, int internalfo } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); if (openGLInfo != null) { - openGLInfo.setSize(openGLInfo.getSize() + size); + openGLInfo.setSize(size); OpenGLResRecorder.getInstance().replace(openGLInfo); } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index 97c809c7a..365aa764c 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -27,6 +27,7 @@ public class OpenGLInfo { // use to dump private int allocCount = 1; private List idList = new ArrayList<>(); + private List sizeList; private boolean isRelease; @@ -60,6 +61,7 @@ public OpenGLInfo(OpenGLInfo clone) { this.activityName = clone.activityName; this.counter = clone.counter; this.size = clone.size; + this.sizeList = clone.sizeList; } public OpenGLInfo(int error) { @@ -75,6 +77,7 @@ public OpenGLInfo(TYPE type, int id, long eglContextNativeHandle, int operate) { this.eglContextNativeHandle = eglContextNativeHandle; this.operate = operate; this.type = type; + this.sizeList = new ArrayList<>(); } public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, int operate) { @@ -83,6 +86,7 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.eglContextNativeHandle = eglContextNativeHandle; this.operate = operate; this.type = type; + this.sizeList = new ArrayList<>(); } public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, int operate, String activityName, AtomicInteger counter) { @@ -95,6 +99,7 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.type = type; this.activityName = activityName; this.counter = counter; + this.sizeList = new ArrayList<>(); } public int getId() { @@ -161,7 +166,14 @@ public long getSize() { } public void setSize(long size) { - this.size = size; + if (sizeList == null) { + this.sizeList = new ArrayList<>(); + } + if (sizeList.contains(size)) { + return; + } + sizeList.add(size); + this.size += size; } private String getOpStr() { From e3a157c820b3fafa21a442e082094c597306f499 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 14:30:58 +0800 Subject: [PATCH 042/163] remove unuse importy --- .../tencent/matrix/openglleak/statistics/OpenGLResRecorder.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 1a9e9bf40..49cf4756e 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -1,8 +1,6 @@ package com.tencent.matrix.openglleak.statistics; import android.annotation.SuppressLint; -import android.os.Handler; -import android.os.HandlerThread; import android.text.TextUtils; import android.util.Log; From d9abbcac8c4b8175233ba54f1e7e9e71e44a90b2 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 16:59:05 +0800 Subject: [PATCH 043/163] pick opengl get size() --- ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 6 +- .../src/main/cpp/my_functions.h | 51 +++- .../matrix/openglleak/hook/OpenGLHook.java | 27 +-- .../openglleak/statistics/OpenGLInfo.java | 16 +- .../utils/OpenGLLeakMonitorLog.java | 52 ---- .../wxperf/sample/OpenglLeakActivity.java | 147 ------------ .../tencent/wxperf/sample/OpenglRender.java | 222 ------------------ 7 files changed, 57 insertions(+), 464 deletions(-) delete mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakMonitorLog.java delete mode 100644 matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglLeakActivity.java delete mode 100644 matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglRender.java 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 b33af5ea7..9a1e9d53e 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 @@ -42,10 +42,10 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_onGlBindBuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindBuffer", "(II)V"); method_onGlBindFramebuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindFramebuffer", "(II)V"); method_onGlBindRenderbuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindRenderbuffer", "(II)V"); - method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IJIII)V"); - method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IJIII)V"); + method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IIIIIIIIJ)V"); + method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IIIIIIIIIJ)V"); method_onGlBufferData = env->GetStaticMethodID(class_OpenGLHook, "onGlBufferData", "(IJI)V"); - method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IJI)V"); + method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IIIJI)V"); return true; } 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 ecde85962..2e6ef7809 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 @@ -86,18 +86,18 @@ void thread_id_to_string(thread::id thread_id, char *&result) { strcpy(result, stream.str().c_str()); } -inline void get_thread_name(char * thread_name) { +inline void get_thread_name(char *thread_name) { prctl(PR_GET_NAME, (char *) (thread_name)); } inline bool is_render_thread() { bool result = false; - char* thread_name = static_cast(malloc(BUF_SIZE)); + char *thread_name = static_cast(malloc(BUF_SIZE)); get_thread_name(thread_name); - if(strcmp(RENDER_THREAD_NAME, thread_name) == 0) { + if (strcmp(RENDER_THREAD_NAME, thread_name) == 0) { result = true; } - if(thread_name != nullptr) { + if (thread_name != nullptr) { free(thread_name); } return result; @@ -561,11 +561,15 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, if (NULL != system_glTexImage2D) { system_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + + if (is_render_thread()) { + return; + } int pixel = Utils::getSizeOfPerPixel(internalformat, format, type); long size = width * height * pixel; JNIEnv *env = GET_ENV(); - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, size, - internalformat, format, type); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, level, + internalformat, width, height, border, format, type, size); } } @@ -576,11 +580,15 @@ my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, if (NULL != system_glTexImage3D) { system_glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); + + if (is_render_thread()) { + return; + } int pixel = Utils::getSizeOfPerPixel(internalformat, format, type); long size = width * height * depth * pixel; JNIEnv *env = GET_ENV(); - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage3D, target, size, - internalformat, format, type); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage3D, target, level, + internalformat, width, height, depth, border, format, type, size); } } @@ -588,6 +596,10 @@ my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GL_APICALL void GL_APIENTRY my_glBindTexture(GLenum target, GLuint resourceId) { if (NULL != system_glBindTexture) { system_glBindTexture(target, resourceId); + + if (is_render_thread()) { + return; + } JNIEnv *env = GET_ENV(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindTexture, target, resourceId); } @@ -596,6 +608,10 @@ GL_APICALL void GL_APIENTRY my_glBindTexture(GLenum target, GLuint resourceId) { GL_APICALL void GL_APIENTRY my_glBindBuffer(GLenum target, GLuint resourceId) { if (NULL != system_glBindTexture) { system_glBindBuffer(target, resourceId); + + if (is_render_thread()) { + return; + } JNIEnv *env = GET_ENV(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindBuffer, target, resourceId); @@ -605,6 +621,10 @@ GL_APICALL void GL_APIENTRY my_glBindBuffer(GLenum target, GLuint resourceId) { GL_APICALL void GL_APIENTRY my_glBindFramebuffer(GLenum target, GLuint resourceId) { if (NULL != system_glBindTexture) { system_glBindFramebuffer(target, resourceId); + + if (is_render_thread()) { + return; + } JNIEnv *env = GET_ENV(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindFramebuffer, target, resourceId); @@ -614,6 +634,10 @@ GL_APICALL void GL_APIENTRY my_glBindFramebuffer(GLenum target, GLuint resourceI GL_APICALL void GL_APIENTRY my_glBindRenderbuffer(GLenum target, GLuint resourceId) { if (NULL != system_glBindTexture) { system_glBindRenderbuffer(target, resourceId); + + if (is_render_thread()) { + return; + } JNIEnv *env = GET_ENV(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBindRenderbuffer, target, resourceId); @@ -624,6 +648,10 @@ GL_APICALL void GL_APIENTRY my_glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) { if (NULL != system_glBindTexture) { system_glBufferData(target, size, data, usage); + + if (is_render_thread()) { + return; + } JNIEnv *env = GET_ENV(); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBufferData, target, size, usage); } @@ -633,11 +661,14 @@ GL_APICALL void GL_APIENTRY my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { if (NULL != system_glBindTexture) { system_glRenderbufferStorage(target, internalformat, width, height); + + if (is_render_thread()) { + return; + } JNIEnv *env = GET_ENV(); long size = Utils::getRenderbufferSizeByFormula(internalformat, width, height); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlRenderbufferStorage, target, - size, - internalformat); + width, height, internalformat, size); } } 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 c1ef6d97b..7121b19e3 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 @@ -340,10 +340,7 @@ public static void onGlBindRenderbuffer(int target, int id) { } } - public static void onGlTexImage2D(int target, long size, int internalFormat, int format, int type) { - if (Thread.currentThread().getName().equals("RenderThread")) { - return; - } + public static void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, long size) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); @@ -360,12 +357,12 @@ public static void onGlTexImage2D(int target, long size, int internalFormat, int } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage2D(target, size, internalFormat, format, type, info.getId(), eglContextId); + getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, info.getId(), eglContextId, size); } } - public static void onGlTexImage3D(int target, long size, int internalFormat, int format, int type) { + public static void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, long size) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); @@ -382,7 +379,7 @@ public static void onGlTexImage3D(int target, long size, int internalFormat, int } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage3D(target, size, internalFormat, format, type, info.getId(), eglContextId); + getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size); } } @@ -391,7 +388,6 @@ public static void onGlBufferData(int target, long size, int usage) { if (Thread.currentThread().getName().equals("RenderThread")) { return; } - MatrixLog.e("Backtrace.Benchmark", "onGlBufferData call, target = " + target + ", size = " + size + ", usage = " + usage); long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); @@ -408,13 +404,12 @@ public static void onGlBufferData(int target, long size, int usage) { } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlBufferData(target, size, usage, info.getId(), eglContextId); + getInstance().mMemoryListener.onGlBufferData(target, usage, info.getId(), eglContextId, size); } } - public static void onGlRenderbufferStorage(int target, long size, int internalformat) { - MatrixLog.e("Backtrace.Benchmark", "onGlRenderbufferStorage call, target = " + target + ", size = " + size + ", internalformat = " + internalformat); + public static void onGlRenderbufferStorage(int target, int internalformat, int width, int height, long size) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); @@ -431,7 +426,7 @@ public static void onGlRenderbufferStorage(int target, long size, int internalfo } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlRenderbufferStorage(target, size, internalformat, info.getId(), eglContextId); + getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, info.getId(), eglContextId, size); } } @@ -462,13 +457,13 @@ public interface BindListener { public interface MemoryListener { - void onGlTexImage2D(int target, long size, int internalFormat, int format, int type, int id, long eglContextId); + void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, int id, long eglContextId, long size); - void onGlTexImage3D(int target, long size, int internalFormat, int format, int type, int id, long eglContextId); + void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size); - void onGlBufferData(int target, long size, int usage, int id, long eglContextId); + void onGlBufferData(int target, int usage, int id, long eglContextId, long size); - void onGlRenderbufferStorage(int target, long size, int internalFormat, int id, long eglContextId); + void onGlRenderbufferStorage(int target, int width, int height, int internalFormat, int id, long eglContextId, long size); } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index 365aa764c..6e97c05ee 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -27,7 +27,6 @@ public class OpenGLInfo { // use to dump private int allocCount = 1; private List idList = new ArrayList<>(); - private List sizeList; private boolean isRelease; @@ -61,7 +60,6 @@ public OpenGLInfo(OpenGLInfo clone) { this.activityName = clone.activityName; this.counter = clone.counter; this.size = clone.size; - this.sizeList = clone.sizeList; } public OpenGLInfo(int error) { @@ -77,7 +75,6 @@ public OpenGLInfo(TYPE type, int id, long eglContextNativeHandle, int operate) { this.eglContextNativeHandle = eglContextNativeHandle; this.operate = operate; this.type = type; - this.sizeList = new ArrayList<>(); } public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, int operate) { @@ -86,7 +83,6 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.eglContextNativeHandle = eglContextNativeHandle; this.operate = operate; this.type = type; - this.sizeList = new ArrayList<>(); } public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, int operate, String activityName, AtomicInteger counter) { @@ -99,7 +95,6 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.type = type; this.activityName = activityName; this.counter = counter; - this.sizeList = new ArrayList<>(); } public int getId() { @@ -166,14 +161,7 @@ public long getSize() { } public void setSize(long size) { - if (sizeList == null) { - this.sizeList = new ArrayList<>(); - } - if (sizeList.contains(size)) { - return; - } - sizeList.add(size); - this.size += size; + this.size = size; } private String getOpStr() { @@ -241,11 +229,11 @@ public void release() { public String toString() { return "OpenGLInfo{" + "id=" + id + + ", eglContextNativeHandle='" + eglContextNativeHandle + '\'' + ", activityName=" + activityName + ", type='" + type.toString() + '\'' + ", size='" + size + '\'' + ", threadId='" + threadId + '\'' + - ", eglContextNativeHandle='" + eglContextNativeHandle + '\'' + ", javaStack='" + javaStack + '\'' + ", nativeStack='" + nativeStack + '\'' + ", nativeStackPtr=" + nativeStackPtr + diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakMonitorLog.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakMonitorLog.java deleted file mode 100644 index adb73990b..000000000 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakMonitorLog.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.tencent.matrix.openglleak.utils; - -public class OpenGLLeakMonitorLog { - - private static LogStub stub = null; - - public static void setLogStub(LogStub ls) { - stub = ls; - } - - public static void i(String tag, String msg) { - if (stub != null) { - stub.i(tag, msg); - } else { - android.util.Log.i(tag, msg); - } - } - - public static void d(String tag, String msg) { - if (stub != null) { - stub.d(tag, msg); - } else { - android.util.Log.d(tag, msg); - } - } - - public static void e(String tag, String msg) { - if (stub != null) { - stub.e(tag, msg); - } else { - android.util.Log.e(tag, msg); - } - } - - public static void w(String tag, String msg) { - if (stub != null) { - stub.w(tag, msg); - } else { - android.util.Log.w(tag, msg); - } - } - - public interface LogStub { - void i(String tag, String msg); - - void w(String tag, String msg); - - void d(String tag, String msg); - - void e(String tag, String msg); - } -} diff --git a/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglLeakActivity.java b/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglLeakActivity.java deleted file mode 100644 index 8c0e13891..000000000 --- a/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglLeakActivity.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.tencent.wxperf.sample; - -import androidx.appcompat.app.AppCompatActivity; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.opengl.GLES10; -import android.opengl.GLES20; -import android.opengl.GLES32; -import android.opengl.GLSurfaceView; -import android.opengl.GLUtils; -import android.os.Bundle; -import android.os.Environment; -import android.os.Handler; -import android.os.Process; -import android.util.Log; -import android.view.View; -import android.widget.FrameLayout; - -import com.tencent.matrix.hook.HookManager; -import com.tencent.matrix.hook.memory.MemoryHook; -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.IntBuffer; - -public class OpenglLeakActivity extends AppCompatActivity { - - private static final String TAG = "Backtrace.Benchmark"; - - private int[] mTextures = new int[1]; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_opengl_leak); - Log.e(TAG, "OpenglLeakActivity onCreate success call"); - -// dump(); - - Log.e(TAG, "\n------------------------------------------------------------------------------------------------------------------------------------\n"); - - Log.e(TAG, "make openGL resource start"); - EGLHelper.initOpenGL(); - Log.e(TAG, "make openGL resource end"); - - Log.e(TAG, "\n------------------------------------------------------------------------------------------------------------------------------------\n"); - -// dump(); - - findViewById(R.id.button_finish_activity).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Log.e(TAG, "click button_finish_activity & do finish"); - finish(); - } - }); - -// OpenglRender render = new OpenglRender(this, mTextures[0]); -// render.loadTexture(); - - FrameLayout layout = findViewById(R.id.frame_layout_surface_view); - GLSurfaceView glView = new GLSurfaceView(this); - glView.setEGLContextClientVersion(2); - OpenglRender render = new OpenglRender(this, mTextures[0]); - glView.setRenderer(render); - layout.addView(glView); - -// HookManager.INSTANCE.dumpToLog(TAG); - - -// File fileDir = new File(LOG_FILE_DIR); -// fileDir.mkdir(); -// File logFile = new File(LOG_FILE_PATH); -// if (logFile.exists()) { -// logFile.delete(); -// } -// HookManager.INSTANCE.dumpToFile(logFile.getAbsolutePath()); -// -// readFile(logFile.getAbsolutePath()); - -// HookManager.INSTANCE.clearList(); - } - - @Override - protected void onResume() { - super.onResume(); - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - dump("test"); - } - }, 10000); - - } - - @Override - protected void onDestroy() { - dump("OpenglLeak"); - EGLHelper.release(); - super.onDestroy(); - } - - private void dump(String lifeCycle) { - - @SuppressLint("SdCardPath") final String logFilePath = - TestApp.getContext().getExternalCacheDir() + File.separator + Process.myPid() + "_" + lifeCycle + "_gpu_memory_hook.log"; - - @SuppressLint("SdCardPath") final String jsonFilePath = - TestApp.getContext().getExternalCacheDir() + File.separator + Process.myPid() + "_" + lifeCycle + "_gpu_memory_hook.json"; - - File logFile = new File(logFilePath); - File jsonFile = new File(jsonFilePath); - - if (logFile.exists()) { - boolean result = logFile.delete(); - Log.e(TAG, "delete logFile result = " + result); - } - try { - logFile.createNewFile(); - } catch (IOException e) { - Log.e(TAG, "logFile create fail"); - } - - if (jsonFile.exists()) { - boolean result = jsonFile.delete(); - Log.e(TAG, "delete jsonFile result = " + result); - } - try { - jsonFile.createNewFile(); - } catch (IOException e) { - Log.e(TAG, "jsonFile create fail"); - } - - MemoryHook.INSTANCE.dump(logFile.getAbsolutePath(), jsonFile.getAbsolutePath()); - Log.e(TAG, logFile.getAbsolutePath()); - } - - -} \ No newline at end of file diff --git a/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglRender.java b/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglRender.java deleted file mode 100644 index bf923d8d7..000000000 --- a/matrix/matrix-android/test/test-backtrace/src/main/java/com/tencent/wxperf/sample/OpenglRender.java +++ /dev/null @@ -1,222 +0,0 @@ -package com.tencent.wxperf.sample; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.opengl.GLES20; -import android.opengl.GLSurfaceView; -import android.opengl.GLUtils; -import android.os.Process; -import android.util.Log; - -import com.tencent.matrix.hook.memory.MemoryHook; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; - -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - -public class OpenglRender implements GLSurfaceView.Renderer { - - private static final String TAG = "Backtrace.Benchmark"; - - private static final String VERTEX_SHADER = "attribute vec4 vPosition;\n" - + "attribute vec2 vCoordinate;\n" - + "varying vec2 aCoordinate;\n" - + "void main() {\n" - + "gl_Position = vPosition;\n" - + "aCoordinate = vCoordinate;\n" - + "}"; - - private static final String FRAGMENT_SHADER = "precision mediump float;\n" - + "uniform sampler2D vTexture;\n" - + "varying vec2 aCoordinate;\n" - + "void main() {\n" - + "gl_FragColor = texture2D(vTexture,aCoordinate);\n" - + "}"; - - private float[] vertex = { - -1.0f, 1.0f, //左上角 - -1.0f, -1.0f, //左下角 - 1.0f, 1.0f, //右上角 - 1.0f, -1.0f //右下角 - }; - - private final float[] sCoord = { - 0f, 0f, //左上角 - 0f, 1f, //左下角 - 1f, 0f, //右上角 - 1f, 1f //右下角 - }; - - private FloatBuffer mVertexBuffer; - - private FloatBuffer mFragmentBuffer; - - private int mProgram; - - private int mVPosition; - - private int mVCoordinate; - - private int mVTexture; - - private Context mContext; - - private int mTextureid; - - private int[] textures = new int[1]; - - public OpenglRender(Context context, int textureid) { - mContext = context; - mTextureid = textureid; - mVertexBuffer = ByteBuffer.allocateDirect(vertex.length * 4) - .order(ByteOrder.nativeOrder()) - .asFloatBuffer().put(vertex); - mVertexBuffer.position(0); - - mFragmentBuffer = ByteBuffer.allocateDirect(sCoord.length * 4) - .order(ByteOrder.nativeOrder()) - .asFloatBuffer().put(sCoord); - mFragmentBuffer.position(0); - - Log.e("Backtrace.Benchmark", "OpenglRender = " + Thread.currentThread().getName()); - } - - - @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - int vertex_shader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER); - int fragment_shader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER); - - mProgram = GLES20.glCreateProgram(); - GLES20.glAttachShader(mProgram, vertex_shader); - GLES20.glAttachShader(mProgram, fragment_shader); - - GLES20.glLinkProgram(mProgram); - - int[] linkStatus = new int[1]; - GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0); - if (linkStatus[0] != GLES20.GL_TRUE) { - String info = GLES20.glGetProgramInfoLog(mProgram); - GLES20.glDeleteProgram(mProgram); - throw new RuntimeException("Could not link program: " + info); - } - - mVPosition = GLES20.glGetAttribLocation(mProgram, "vPosition"); - mVCoordinate = GLES20.glGetAttribLocation(mProgram, "vCoordinate"); - mVTexture = GLES20.glGetUniformLocation(mProgram, "vTexture"); - - Log.e("Backtrace.Benchmark", "onSurfaceCreated = " + Thread.currentThread().getName()); - loadTexture(); - dump("OpenglRender"); - - } - - private void dump(String lifeCycle) { - - @SuppressLint("SdCardPath") final String logFilePath = - TestApp.getContext().getExternalCacheDir() + File.separator + Process.myPid() + "_" + lifeCycle + "_gpu_memory_hook.log"; - - @SuppressLint("SdCardPath") final String jsonFilePath = - TestApp.getContext().getExternalCacheDir() + File.separator + Process.myPid() + "_" + lifeCycle + "_gpu_memory_hook.json"; - - File logFile = new File(logFilePath); - File jsonFile = new File(jsonFilePath); - - if (logFile.exists()) { - boolean result = logFile.delete(); - Log.e(TAG, "delete logFile result = " + result); - } - try { - logFile.createNewFile(); - } catch (IOException e) { - Log.e(TAG, "logFile create fail"); - } - - if (jsonFile.exists()) { - boolean result = jsonFile.delete(); - Log.e(TAG, "delete jsonFile result = " + result); - } - try { - jsonFile.createNewFile(); - } catch (IOException e) { - Log.e(TAG, "jsonFile create fail"); - } - - MemoryHook.INSTANCE.dump(logFile.getAbsolutePath(), jsonFile.getAbsolutePath()); - Log.e(TAG, logFile.getAbsolutePath()); - } - - - public void loadTexture() { - GLES20.glGenTextures(1, IntBuffer.wrap(textures)); -// GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureid); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); - //激活第0个纹理 - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glUniform1i(mVTexture, 0); - //设置环绕和过滤方式 - //环绕(超出纹理坐标范围):(s==x t==y GL_REPEAT 重复) - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT); - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); - //过滤(纹理像素映射到坐标点):(缩小、放大:GL_LINEAR线性) - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - - Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.test1); - //设置图片 - GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); - bitmap.recycle(); - //解绑纹理 - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); - } - - private int loadShader(int glVertexShader, String vertexShader) { - int glCreateShader = GLES20.glCreateShader(glVertexShader); - GLES20.glShaderSource(glCreateShader, vertexShader); - GLES20.glCompileShader(glCreateShader); - int[] compiled = new int[1]; - GLES20.glGetShaderiv(glCreateShader, GLES20.GL_COMPILE_STATUS, compiled, 0); - if (compiled[0] != GLES20.GL_TRUE) { - GLES20.glDeleteShader(glCreateShader); - return -1; - } - return glCreateShader; - } - - @Override - public void onSurfaceChanged(GL10 gl, int width, int height) { - GLES20.glViewport(0, 0, width, height); - } - - @Override - public void onDrawFrame(GL10 gl) { - - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - GLES20.glClearColor(1.0f, 0, 0, 1f); - //使用源程序 - GLES20.glUseProgram(mProgram); - //绑定绘制纹理 -// GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureid); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); - //使顶点属性数组有效 - GLES20.glEnableVertexAttribArray(mVPosition); - //为顶点属性赋值 - GLES20.glVertexAttribPointer(mVPosition, 2, GLES20.GL_FLOAT, false, 8, mVertexBuffer); - - GLES20.glEnableVertexAttribArray(mVCoordinate); - GLES20.glVertexAttribPointer(mVCoordinate, 2, GLES20.GL_FLOAT, false, 8, mFragmentBuffer); - //绘制图形 - GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); - //解绑纹理 - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); - - } -} From dacebf78497a8860385dbf3cce460a54266bc634 Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 1 Dec 2021 16:59:10 +0800 Subject: [PATCH 044/163] =?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=EF=BC=9A=E6=B7=BB=E5=8A=A0=E5=89=8D=E5=90=8E=E5=8F=B0=E6=B3=84?= =?UTF-8?q?=E6=BC=8F=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix-opengl-leak/CMakeLists.txt | 2 +- ..._statistics_resource_ResRecordManager.cpp} | 6 +- ...ak_statistics_resource_ResRecordManager.h} | 8 +- .../matrix/openglleak/OpenglLeakPlugin.java | 11 +- .../matrix/openglleak/hook/OpenGLHook.java | 14 +- .../statistics/CustomizeLeakMonitor.java | 8 +- .../statistics/LeakMonitorDefault.java | 153 +++++++++--- .../LeakMonitorForActivityLifecycle.java | 207 --------------- .../LeakMonitorForActivityLifecycle_Old.java | 235 ------------------ .../statistics/LeakMonitorForBackstage.java | 97 ++++++++ .../statistics/LeakMonitorForDoubleCheck.java | 131 ++++++++++ .../{source => resource}/OpenGLInfo.java | 80 ++---- .../ResRecordManager.java | 39 ++- .../ResRecorder.java} | 10 +- .../ResRecorderForActivityLifecycle.java | 188 -------------- .../openglleak/utils/ActivityRecorder.java | 107 ++++++++ .../openglleak/utils/OpenGLLeakLog.java | 52 ---- 17 files changed, 530 insertions(+), 818 deletions(-) rename matrix/matrix-android/matrix-opengl-leak/src/main/cpp/{com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp => com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp} (92%) rename matrix/matrix-android/matrix-opengl-leak/src/main/cpp/{com_tencent_matrix_openglleak_statistics_OpenGLInfo.h => com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h} (66%) delete mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java delete mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle_Old.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForBackstage.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForDoubleCheck.java rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/{source => resource}/OpenGLInfo.java (61%) rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/{source => resource}/ResRecordManager.java (69%) rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/{source/ResRecorderForCustomize.java => resource/ResRecorder.java} (81%) delete mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java delete mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakLog.java diff --git a/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt b/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt index e80e76944..82a8f8781 100644 --- a/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt +++ b/matrix/matrix-android/matrix-opengl-leak/CMakeLists.txt @@ -23,7 +23,7 @@ set( SOURCE_FILES ${SOURCE_DIR}/com_tencent_matrix_openglleak_detector_FuncSeeker.cpp ${SOURCE_DIR}/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp - ${SOURCE_DIR}/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp + ${SOURCE_DIR}/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp ${SOURCE_DIR}/type.cpp ${SOURCE_DIR}/get_tls.cpp ) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp similarity index 92% rename from matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp rename to matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp index 6efe732d0..af383042f 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp @@ -3,7 +3,7 @@ // #include -#include "com_tencent_matrix_openglleak_statistics_OpenGLInfo.h" +#include "com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h" #include #include #include "BacktraceDefine.h" @@ -59,7 +59,7 @@ void get_native_stack(wechat_backtrace::Backtrace* backtrace, char *&stack) { } -extern "C" JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_source_OpenGLInfo_releaseNative +extern "C" JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager_releaseNative (JNIEnv *env, jobject thiz, jlong jl) { int64_t addr = jl; @@ -67,7 +67,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_ delete ptr; } -extern "C" JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_source_OpenGLInfo_dumpNativeStack +extern "C" JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager_dumpNativeStack (JNIEnv *env, jobject thiz, jlong jl) { int64_t addr = jl; wechat_backtrace::Backtrace* ptr = (wechat_backtrace::Backtrace*)addr; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h similarity index 66% rename from matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.h rename to matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h index b99381591..fbcd6dea2 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h @@ -2,8 +2,8 @@ #include /* Header for class com_tencent_matrix_openglleak_statistics_OpenGLInfo */ -#ifndef _Included_com_tencent_matrix_openglleak_statistics_OpenGLInfo -#define _Included_com_tencent_matrix_openglleak_statistics_OpenGLInfo +#ifndef _Included_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager +#define _Included_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager #ifdef __cplusplus extern "C" { #endif @@ -13,10 +13,10 @@ extern "C" { * Method: init * Signature: ()Z */ -JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_OpenGLInfo_releaseNative +JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager_releaseNative (JNIEnv *, jobject thiz, jlong); -JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_OpenGLInfo_dumpNativeStack +JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager_dumpNativeStack (JNIEnv *, jobject thiz, jlong); #ifdef __cplusplus 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 6d03f701c..7c73869f6 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 @@ -12,7 +12,8 @@ import com.tencent.matrix.openglleak.detector.IOpenglIndexDetector; import com.tencent.matrix.openglleak.detector.OpenglIndexDetectorService; import com.tencent.matrix.openglleak.hook.OpenGLHook; -import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle_Old; +import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; +import com.tencent.matrix.openglleak.utils.ActivityRecorder; import com.tencent.matrix.openglleak.utils.EGLHelper; import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; import com.tencent.matrix.plugin.Plugin; @@ -45,6 +46,7 @@ public void registerReportCallback(OpenglReportCallback callback) { public void init(Application app, PluginListener listener) { super.init(app, listener); + ActivityRecorder.getInstance().start(app); GlLeakHandlerThread.getInstance().start(); } @@ -103,9 +105,6 @@ private void executeHook(IBinder iBinder) { OpenGLHook.getInstance().hook(FuncNameString.GL_GEN_RENDERBUFFERS, map.get(FuncNameString.GL_GEN_RENDERBUFFERS)); OpenGLHook.getInstance().hook(FuncNameString.GL_DELETE_RENDERBUFFERS, map.get(FuncNameString.GL_DELETE_RENDERBUFFERS)); MatrixLog.e(TAG, "hook finish"); - - // 泄漏监控 - LeakMonitorForActivityLifecycle_Old.getInstance().start((Application) context.getApplicationContext()); } catch (Throwable e) { e.printStackTrace(); } finally { @@ -174,4 +173,8 @@ public void setJavaStackDump(boolean open) { OpenGLHook.getInstance().setJavaStackDump(true); } + public void reset() { + ResRecordManager.getInstance().reset(); + } + } 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 305b63dbb..a3d594e7f 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 @@ -3,9 +3,9 @@ import android.opengl.EGL14; import com.tencent.matrix.openglleak.comm.FuncNameString; -import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle_Old; -import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; -import com.tencent.matrix.openglleak.statistics.source.ResRecordManager; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; +import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; +import com.tencent.matrix.openglleak.utils.ActivityRecorder; import java.util.concurrent.atomic.AtomicInteger; @@ -89,7 +89,7 @@ public static void onGlGenTextures(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle_Old.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -128,7 +128,7 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle_Old.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -167,7 +167,7 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle_Old.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { @@ -206,7 +206,7 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, LeakMonitorForActivityLifecycle_Old.getInstance().getCurrentActivityName(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mListener != null) { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java index d454d588c..7c2e5b1da 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java @@ -1,16 +1,16 @@ package com.tencent.matrix.openglleak.statistics; -import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; -import com.tencent.matrix.openglleak.statistics.source.ResRecorderForCustomize; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; +import com.tencent.matrix.openglleak.statistics.resource.ResRecorder; import java.util.List; public class CustomizeLeakMonitor { - private ResRecorderForCustomize mResRecorder; + private ResRecorder mResRecorder; public CustomizeLeakMonitor() { - mResRecorder = new ResRecorderForCustomize(); + mResRecorder = new ResRecorder(); } public void checkStart() { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java index bf37cfa5c..c2a998028 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java @@ -1,71 +1,142 @@ package com.tencent.matrix.openglleak.statistics; -import android.os.Handler; +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; -import com.tencent.matrix.AppActiveMatrixDelegate; -import com.tencent.matrix.listeners.IAppForeground; -import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; -import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import java.util.List; - -public class LeakMonitorDefault extends CustomizeLeakMonitor implements IAppForeground { +import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; +import com.tencent.matrix.util.MatrixLog; - private static final long CHECK_TIME = 1000L * 30; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; - private Handler mH; - private LeakListener mLeakListener; +public abstract class LeakMonitorDefault implements Application.ActivityLifecycleCallbacks { - private static LeakMonitorDefault mInstance = new LeakMonitorDefault(); + private static final String TAG = "matrix.LeakMonitorDefault"; + private List mActivityLeakMonitor; - private LeakMonitorDefault() { - mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); + protected LeakMonitorDefault() { + mActivityLeakMonitor = new LinkedList<>(); } - public void setLeakListener(LeakListener l) { - mLeakListener = l; + public void start(Application context) { + context.registerActivityLifecycleCallbacks(this); + MatrixLog.i(TAG, "start"); } - public void start() { - AppActiveMatrixDelegate.INSTANCE.addListener(this); + public void stop(Application context) { + context.unregisterActivityLifecycleCallbacks(this); + MatrixLog.i(TAG, "stop"); } + public abstract void onLeak(OpenGLInfo leak); + @Override - public void onForeground(boolean isForeground) { - if (isForeground) { - foreground(); - } else { - background(); + public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) { + ActivityLeakMonitor activityLeakMonitor = new ActivityLeakMonitor(activity.hashCode(), new CustomizeLeakMonitor()); + activityLeakMonitor.start(); + + MatrixLog.i(TAG, "onActivityCreated " + activityLeakMonitor); + + synchronized (mActivityLeakMonitor) { + mActivityLeakMonitor.add(activityLeakMonitor); } } - private Runnable mRunnable = new Runnable() { - @Override - public void run() { - List leaks = checkEnd(); + @Override + public void onActivityDestroyed(@NonNull Activity activity) { + Integer activityHashCode = activity.hashCode(); + MatrixLog.i(TAG, "onActivityDestroyed " + activityHashCode); + + synchronized (mActivityLeakMonitor) { + Iterator it = mActivityLeakMonitor.iterator(); + while (it.hasNext()) { + ActivityLeakMonitor item = it.next(); + if (null == item) { + continue; + } - if (null == mLeakListener) { - return; - } + if (item.getActivityHashCode() == activityHashCode) { + it.remove(); - for (OpenGLInfo item : leaks) { - if (null != item) { - mLeakListener.onLeak(item); + List leaks = item.end(); + for (OpenGLInfo leakItem : leaks) { + if (null != leakItem) { + onLeak(leakItem); + } + } + + break; } } } - }; + } + + @Override + public void onActivityStarted(@NonNull Activity activity) { + MatrixLog.i(TAG, "onActivityStarted " + activity.hashCode()); + } - public void foreground() { - checkStart(); - mH.removeCallbacks(mRunnable); + @Override + public void onActivityResumed(@NonNull Activity activity) { + MatrixLog.i(TAG, "onActivityResumed " + activity.hashCode()); } - public void background() { - mH.postDelayed(mRunnable, CHECK_TIME); + @Override + public void onActivityPaused(@NonNull Activity activity) { + MatrixLog.i(TAG, "onActivityPaused " + activity.hashCode()); } - public interface LeakListener { - void onLeak(OpenGLInfo info); + @Override + public void onActivityStopped(@NonNull Activity activity) { + MatrixLog.i(TAG, "onActivityStopped " + activity.hashCode()); } + + @Override + public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) { + + } + + class ActivityLeakMonitor { + private int mActivityHashCode; + private CustomizeLeakMonitor mMonitor; + + ActivityLeakMonitor(int hashcode, CustomizeLeakMonitor m) { + mActivityHashCode = hashcode; + mMonitor = m; + } + + void start() { + if (null != mMonitor) { + mMonitor.checkStart(); + } + } + + List end() { + List ret = new ArrayList<>(); + if (null == mMonitor) { + return ret; + } + + return mMonitor.checkEnd(); + } + + int getActivityHashCode() { + return mActivityHashCode; + } + + @Override + public String toString() { + return "ActivityLeakMonitor{" + + "mActivityHashCode=" + mActivityHashCode + + ", mMonitor=" + mMonitor + + '}'; + } + } + } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java deleted file mode 100644 index eaf537b41..000000000 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle.java +++ /dev/null @@ -1,207 +0,0 @@ -package com.tencent.matrix.openglleak.statistics; - -import android.app.Activity; -import android.app.Application; -import android.os.Bundle; -import android.os.Handler; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; -import com.tencent.matrix.openglleak.statistics.source.ResRecordManager; -import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; -import com.tencent.matrix.util.MatrixLog; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -public class LeakMonitorForActivityLifecycle implements Application.ActivityLifecycleCallbacks { - - private static final String TAG = "matrix.LeakMonitorForActivityLifecycle"; - - private Handler mH; - private List mActivityLeakMonitor; - private List mMaybeLeakList; - private LeakListener mLeakListener; - - private static final long DOUBLE_CHECK_TIME = 0L; - private static final long DOUBLE_CHECK_LOOPER = 1000L * 60 * 1; - - public LeakMonitorForActivityLifecycle() { - mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); - mActivityLeakMonitor = new LinkedList<>(); - mMaybeLeakList = new LinkedList<>(); - - mH.postDelayed(mDoubleCheck, DOUBLE_CHECK_LOOPER); - } - - public void start(Application context) { - MatrixLog.i(TAG, "start"); - context.registerActivityLifecycleCallbacks(this); - } - - public void stop(Application context) { - context.unregisterActivityLifecycleCallbacks(this); - } - - @Override - public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) { - ActivityLeakMonitor activityLeakMonitor = new ActivityLeakMonitor(activity.hashCode(), new CustomizeLeakMonitor()); - activityLeakMonitor.start(); - - synchronized (mActivityLeakMonitor) { - mActivityLeakMonitor.add(activityLeakMonitor); - } - } - - @Override - public void onActivityDestroyed(@NonNull Activity activity) { - Integer activityHashCode = activity.hashCode(); - - synchronized (mActivityLeakMonitor) { - Iterator it = mActivityLeakMonitor.iterator(); - while (it.hasNext()) { - ActivityLeakMonitor item = it.next(); - if (null == item) { - continue; - } - - if (item.getActivityHashCode() == activityHashCode) { - it.remove(); - - List leaks = item.end(); - if (null != mLeakListener) { - for (OpenGLInfo leakItem : leaks) { - if (null != leakItem) { - mLeakListener.onMaybeLeak(leakItem); - - synchronized (mMaybeLeakList) { - // 可能泄漏,需要做 double check - mMaybeLeakList.add(new MaybeLeakOpenGLInfo(leakItem)); - } - } - } - } - - break; - } - } - } - } - - public void setLeakListener(LeakMonitorForActivityLifecycle.LeakListener l) { - mLeakListener = l; - } - - private Runnable mDoubleCheck = new Runnable() { - @Override - public void run() { - long now = System.currentTimeMillis(); - - synchronized (mMaybeLeakList) { - Iterator it = mMaybeLeakList.iterator(); - while (it.hasNext()) { - MaybeLeakOpenGLInfo item = it.next(); - if (null == item) { - continue; - } - - if ((now - item.getMaybeLeakTime()) > DOUBLE_CHECK_TIME) { - it.remove(); - - if (null != mLeakListener) { - if (ResRecordManager.getInstance().isGLInfoRelease(item)) { - mLeakListener.onLeak(item); - } - } - } - } - } - - mH.postDelayed(mDoubleCheck, DOUBLE_CHECK_LOOPER); - } - }; - - @Override - public void onActivityStarted(@NonNull Activity activity) { - - } - - @Override - public void onActivityResumed(@NonNull Activity activity) { - - } - - @Override - public void onActivityPaused(@NonNull Activity activity) { - - } - - @Override - public void onActivityStopped(@NonNull Activity activity) { - - } - - @Override - public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) { - - } - - class ActivityLeakMonitor { - private int mActivityHashCode; - private CustomizeLeakMonitor mMonitor; - - ActivityLeakMonitor(int hashcode, CustomizeLeakMonitor m) { - mActivityHashCode = hashcode; - mMonitor = m; - } - - void start() { - if (null != mMonitor) { - mMonitor.checkStart(); - } - } - - List end() { - List ret = new ArrayList<>(); - if (null == mMonitor) { - return ret; - } - - ret.addAll(mMonitor.checkEnd()); - - return ret; - } - - int getActivityHashCode() { - return mActivityHashCode; - } - } - - class MaybeLeakOpenGLInfo extends OpenGLInfo { - - long mMaybeLeakTime; - - MaybeLeakOpenGLInfo(OpenGLInfo clone) { - super(clone); - } - - void setMaybeLeakTime(long t) { - mMaybeLeakTime = t; - } - - long getMaybeLeakTime(long t) { - return mMaybeLeakTime; - } - } - - public interface LeakListener { - void onMaybeLeak(OpenGLInfo info); - - void onLeak(OpenGLInfo info); - } - -} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle_Old.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle_Old.java deleted file mode 100644 index 6507007d8..000000000 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForActivityLifecycle_Old.java +++ /dev/null @@ -1,235 +0,0 @@ -package com.tencent.matrix.openglleak.statistics; - -import android.app.Activity; -import android.app.Application; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; - -import com.tencent.matrix.openglleak.statistics.source.OpenGLInfo; -import com.tencent.matrix.openglleak.statistics.source.ResRecorderForActivityLifecycle; -import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; -import com.tencent.matrix.util.MatrixLog; - -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -@Deprecated -public class LeakMonitorForActivityLifecycle_Old extends CustomizeLeakMonitor implements Application.ActivityLifecycleCallbacks { - - private static final String TAG = "matrix.GPU_LeakMonitor"; - private static LeakMonitorForActivityLifecycle_Old mInstance = new LeakMonitorForActivityLifecycle_Old(); - - private Handler mH; - - private Map, List> maps = new HashMap<>(); - private String currentActivityName = ""; - - private ResRecorderForActivityLifecycle mResRecorder = new ResRecorderForActivityLifecycle(); - - private long mDoubleCheckTime = 1000 * 60 * 30; - private final long mDoubleCheckLooper = 1000 * 60 * 1; - - protected LeakMonitorForActivityLifecycle_Old() { - mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); - mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); - } - - public static LeakMonitorForActivityLifecycle_Old getInstance() { - return mInstance; - } - - public void setDoubleCheckTime(long doubleCheckTime) { - mDoubleCheckTime = doubleCheckTime; - } - - public void setListener(LeakListener l) { - mResRecorder.setLeakListener(l); - } - - public void start(Application context) { - MatrixLog.i(TAG, "start"); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - (context).registerActivityLifecycleCallbacks(mInstance); - } - } - - public String getCurrentActivityName() { - return currentActivityName; - } - - @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - currentActivityName = activity.getLocalClassName(); - - MatrixLog.i(TAG, "activity oncreate:" + currentActivityName + " :" + activity.hashCode()); - - WeakReference weakReference = new WeakReference<>(activity); - List actvityList = mResRecorder.getAllHashCode(); - - maps.put(weakReference, actvityList); - } - - @Override - public void onActivityDestroyed(Activity activity) { - MatrixLog.i(TAG, - "activity ondestroy:" + activity.getLocalClassName() + " :" + activity.hashCode()); - - WeakReference target = null; - - Set mapSet = maps.keySet(); - Iterator it = mapSet.iterator(); - while (it.hasNext()) { - WeakReference weakReference = (WeakReference) it.next(); - - Activity a = (Activity) weakReference.get(); - if (a == null) { - // 空的话移除 - it.remove(); - continue; - } - - if ((a == activity)) { - target = weakReference; - break; - } - } - - // 找不到,跳过不处理 - if (target == null) { - return; - } - - String activityName = ""; - Activity aa = target.get(); - if (aa != null) { - activityName = aa.getLocalClassName(); - } - - final String activityStr = activityName; - final List createList = maps.get(target); - final List destroyList = mResRecorder.getAllHashCode(); - - mH.post(new Runnable() { - @Override - public void run() { - boolean result = findLeak(createList, destroyList); - if (result) { - MatrixLog.i(TAG, activityStr + " leak! "); - } - } - }); - - // clear - maps.remove(target); - } - - private boolean findLeak(List createList, List destroyList) { - if ((createList == null) || (destroyList == null)) { - return false; - } - - boolean hasLeak = false; - - for (Integer destroy : destroyList) { - if (destroy == null) { - continue; - } - - boolean isLeak; - int i = 0; - for (Integer create : createList) { - if (create == null) { - i = i + 1; - continue; - } - - if (create.intValue() == destroy.intValue()) { - break; - } - - i = i + 1; - } - - if (i == createList.size()) { - isLeak = true; - } else { - isLeak = false; - } - - if (isLeak) { - OpenGLInfo leakInfo = mResRecorder.getItemByHashCode(destroy); - - if ((leakInfo != null) && !leakInfo.getMaybeLeak()) { - mResRecorder.getNativeStack(leakInfo); - mResRecorder.setMaybeLeak(leakInfo); - - hasLeak = true; - } - } - } - - return hasLeak; - } - - @Override - public void onActivityStarted(Activity activity) { - - } - - @Override - public void onActivityResumed(Activity activity) { - currentActivityName = activity.getLocalClassName(); - } - - @Override - public void onActivityPaused(Activity activity) { - - } - - @Override - public void onActivityStopped(Activity activity) { - - } - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - - } - - public interface LeakListener { - void onMaybeLeak(OpenGLInfo info); - - void onLeak(OpenGLInfo info); - } - - private Runnable doubleCheckRunnable = new Runnable() { - @Override - public void run() { - long now = System.currentTimeMillis(); - - List copyList = mResRecorder.getCopyList(); - MatrixLog.i(TAG, "double check list size:" + copyList.size()); - - for (OpenGLInfo item : copyList) { - if (item == null) { - continue; - } - - if (item.getMaybeLeak()) { - if ((now - item.getMaybeLeakTime()) > mDoubleCheckTime) { - mResRecorder.setLeak(item); - mResRecorder.remove(item); - } - } - } - - mH.postDelayed(doubleCheckRunnable, mDoubleCheckLooper); - } - }; -} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForBackstage.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForBackstage.java new file mode 100644 index 000000000..c6a2768be --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForBackstage.java @@ -0,0 +1,97 @@ +package com.tencent.matrix.openglleak.statistics; + +import android.app.Application; +import android.os.Handler; + +import com.tencent.matrix.AppActiveMatrixDelegate; +import com.tencent.matrix.listeners.IAppForeground; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; +import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; +import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + + +public class LeakMonitorForBackstage extends LeakMonitorDefault implements IAppForeground { + + private final long mBackstageCheckTime; + + private Handler mH; + private LeakMonitorForBackstage.LeakListener mLeakListener; + + private List mLeaksList = new LinkedList<>(); + + public LeakMonitorForBackstage(long backstageCheckTime) { + mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); + mBackstageCheckTime = backstageCheckTime; + } + + @Override + public void onLeak(OpenGLInfo leak) { + synchronized (mLeaksList) { + mLeaksList.add(leak); + } + } + + public void setLeakListener(LeakListener l) { + mLeakListener = l; + } + + public void start(Application context) { + AppActiveMatrixDelegate.INSTANCE.addListener(this); + super.start(context); + } + + public void stop(Application context) { + AppActiveMatrixDelegate.INSTANCE.removeListener(this); + super.stop(context); + } + + @Override + public void onForeground(boolean isForeground) { + if (isForeground) { + foreground(); + } else { + background(); + } + } + + private Runnable mRunnable = new Runnable() { + @Override + public void run() { + synchronized (mLeaksList) { + Iterator it = mLeaksList.iterator(); + while (it.hasNext()) { + OpenGLInfo item = it.next(); + if (null != item) { + if (null != mLeakListener) { + if (!ResRecordManager.getInstance().isGLInfoRelease(item)) { + mLeakListener.onLeak(item); + } + } + + it.remove(); + } + } + } + + if (null == mLeakListener) { + return; + } + } + }; + + public void foreground() { + mH.removeCallbacks(mRunnable); + } + + public void background() { + mH.postDelayed(mRunnable, mBackstageCheckTime); + } + + public interface LeakListener { + void onLeak(OpenGLInfo info); + } +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForDoubleCheck.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForDoubleCheck.java new file mode 100644 index 000000000..f447dd703 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorForDoubleCheck.java @@ -0,0 +1,131 @@ +package com.tencent.matrix.openglleak.statistics; + +import android.app.Application; +import android.os.Handler; + +import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; +import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; +import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class LeakMonitorForDoubleCheck extends LeakMonitorDefault { + + private static final String TAG = "matrix.LeakMonitorForActivityLifecycle"; + + private Handler mH; + private List mMaybeLeakList; + private LeakMonitorForDoubleCheck.LeakListener mLeakListener; + + private static final long DOUBLE_CHECK_LOOPER = 1000L * 30; + private final long mDoubleCheckTime; + private long mLastDoubleCheckTime; + + private Runnable mDoubleCheck = new Runnable() { + @Override + public void run() { + doubleCheck(); + } + }; + + public LeakMonitorForDoubleCheck(long doubleCheckTime) { + super(); + + mDoubleCheckTime = doubleCheckTime; + + mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); + mMaybeLeakList = new LinkedList<>(); + } + + public void start(Application context) { + super.start(context); + } + + public void stop(Application context) { + mH.removeCallbacks(mDoubleCheck); + super.stop(context); + } + + @Override + public void onLeak(OpenGLInfo leak) { + long now = System.currentTimeMillis(); + MaybeLeakOpenGLInfo leakItem = new MaybeLeakOpenGLInfo(leak); + leakItem.setMaybeLeakTime(now); + + if (null != mLeakListener) { + mLeakListener.onMaybeLeak(leakItem); + } + + synchronized (mMaybeLeakList) { + // 可能泄漏,需要做 double check + mMaybeLeakList.add(leakItem); + + if ((now - mLastDoubleCheckTime) > DOUBLE_CHECK_LOOPER) { + mH.removeCallbacks(mDoubleCheck); + mH.post(mDoubleCheck); + } + } + } + + public void setLeakListener(LeakListener l) { + mLeakListener = l; + } + + private void doubleCheck() { + long now = System.currentTimeMillis(); + mLastDoubleCheckTime = now; + + synchronized (mMaybeLeakList) { + Iterator it = mMaybeLeakList.iterator(); + + while (it.hasNext()) { + MaybeLeakOpenGLInfo item = it.next(); + if (null == item) { + continue; + } + + if ((now - item.getMaybeLeakTime()) > mDoubleCheckTime) { + it.remove(); + + if (null != mLeakListener) { + if (!ResRecordManager.getInstance().isGLInfoRelease(item)) { + mLeakListener.onLeak(item); + } + } + } + } + + if (mMaybeLeakList.size() > 0) { + mH.removeCallbacks(mDoubleCheck); + mH.postDelayed(mDoubleCheck, DOUBLE_CHECK_LOOPER); + } + } + } + + class MaybeLeakOpenGLInfo extends OpenGLInfo { + + long mMaybeLeakTime; + + MaybeLeakOpenGLInfo(OpenGLInfo clone) { + super(clone); + } + + void setMaybeLeakTime(long t) { + mMaybeLeakTime = t; + } + + long getMaybeLeakTime() { + return mMaybeLeakTime; + } + } + + public interface LeakListener { + + void onMaybeLeak(OpenGLInfo info); + + void onLeak(OpenGLInfo info); + + } +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java similarity index 61% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java index a33db0c37..df23685c8 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLInfo.java @@ -1,29 +1,24 @@ -package com.tencent.matrix.openglleak.statistics.source; - -import android.text.TextUtils; +package com.tencent.matrix.openglleak.statistics.resource; +import com.tencent.matrix.openglleak.utils.ActivityRecorder; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; public class OpenGLInfo { - private static final String TAG = "OpenGLInfo.TAG"; - private int id; private int error; private String threadId = ""; private long eglContextNativeHandle; private String javaStack = ""; private String nativeStack = ""; - private long nativeStackPtr; + private long nativeStackPtr = 0L; private boolean genOrDelete; private TYPE type; - private boolean maybeLeak = false; - private long maybeLeakCheckTime = 0L; - private boolean isReported = false; + private ActivityRecorder.ActivityInfo activityInfo; - private String activityName; + private AtomicInteger counter; public enum TYPE { TEXTURE, BUFFER, FRAME_BUFFERS, RENDER_BUFFERS @@ -39,10 +34,7 @@ public OpenGLInfo(OpenGLInfo clone) { this.nativeStackPtr = clone.nativeStackPtr; this.genOrDelete = clone.genOrDelete; this.type = clone.type; - this.maybeLeakCheckTime = clone.maybeLeakCheckTime; - this.isReported = clone.isReported; - this.maybeLeak = clone.maybeLeak; - this.activityName = clone.activityName; + this.activityInfo = clone.activityInfo; } public OpenGLInfo(int error) { @@ -57,7 +49,7 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.type = type; } - public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, boolean genOrDelete, String activityName, AtomicInteger counter) { + public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, boolean genOrDelete, ActivityRecorder.ActivityInfo activityInfo, AtomicInteger counter) { this.id = id; this.threadId = threadId; this.eglContextNativeHandle = eglContextNativeHandle; @@ -65,7 +57,8 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.nativeStackPtr = nativeStackPtr; this.genOrDelete = genOrDelete; this.type = type; - this.activityName = activityName; + this.activityInfo = activityInfo; + this.counter = counter; } public int getId() { @@ -76,10 +69,6 @@ public int getError() { return error; } - protected void setActivityName(String name) { - this.activityName = name; - } - public String getThreadId() { return threadId; } @@ -97,64 +86,29 @@ public String getJavaStack() { } public String getNativeStack() { - if (TextUtils.isEmpty(nativeStack)) { - if (this.nativeStackPtr != 0) { - nativeStack = dumpNativeStack(this.nativeStackPtr); - } else { - nativeStack = ""; - } - } - return nativeStack; + return ResRecordManager.getInstance().getNativeStack(this); } - public boolean getMaybeLeak() { - return maybeLeak; + public AtomicInteger getCounter() { + return counter; } - public String getActivityName() { - return activityName; + public long getNativeStackPtr() { + return nativeStackPtr; } - public long getMaybeLeakTime() { - return maybeLeakCheckTime; - } - - public void setNativeStack(String nativeStack) { - this.nativeStack = nativeStack; - } - - public void setMaybeLeak(boolean b) { - this.maybeLeak = b; - } - - public void setMaybeLeakCheckTime(long time) { - this.maybeLeakCheckTime = time; - } - - protected void release() { - if (nativeStackPtr == 0) { - return; - } - - releaseNative(nativeStackPtr); - } - - private native void releaseNative(long nativeStackPtr); - - private native String dumpNativeStack(long nativeStackPtr); - @Override public String toString() { return "OpenGLInfo{" + "id=" + id + - ", activityName=" + activityName + + ", activityName=" + activityInfo + ", type='" + type.toString() + '\'' + ", error=" + error + ", isGen=" + genOrDelete + ", threadId='" + threadId + '\'' + ", eglContextNativeHandle='" + eglContextNativeHandle + '\'' + ", javaStack='" + javaStack + '\'' + - ", nativeStack='" + nativeStack + '\'' + + ", nativeStack='" + getNativeStack() + '\'' + ", nativeStackPtr=" + nativeStackPtr + '}'; } @@ -162,7 +116,7 @@ public String toString() { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (o == null || !(o instanceof OpenGLInfo)) return false; OpenGLInfo that = (OpenGLInfo) o; return id == that.id && eglContextNativeHandle == that.eglContextNativeHandle && diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java similarity index 69% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java index e1bfed0a5..c7c6db4fc 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecordManager.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecordManager.java @@ -1,4 +1,4 @@ -package com.tencent.matrix.openglleak.statistics.source; +package com.tencent.matrix.openglleak.statistics.resource; import android.os.Handler; @@ -6,6 +6,7 @@ import java.util.LinkedList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; public class ResRecordManager { @@ -65,7 +66,12 @@ public void run() { return; } - info.release(); + AtomicInteger counter = info.getCounter(); + counter.set(counter.get() - 1); + if (counter.get() == 0) { + releaseNative(info.getNativeStackPtr()); + } + mInfoList.remove(del); } @@ -78,6 +84,30 @@ public void run() { }); } + public String getNativeStack(OpenGLInfo item) { + synchronized (mInfoList) { + // 之前可能释放过 + int index = mInfoList.indexOf(item); + if (-1 == index) { + return "res already released, can not get native stack"; + } + + String ret = ""; + + OpenGLInfo info = mInfoList.get(index); + long nativeStackPtr = info.getNativeStackPtr(); + if ((null != info) && (nativeStackPtr != 0L)) { + ret = dumpNativeStack(nativeStackPtr); + } + + return ret; + } + } + + private native String dumpNativeStack(long nativeStackPtr); + + private native void releaseNative(long nativeStackPtr); + protected void registerCallback(Callback callback) { if (null == callback) { return; @@ -103,6 +133,11 @@ public boolean isGLInfoRelease(OpenGLInfo item) { } } + public void reset() { + mCallbackList.clear(); + mInfoList.clear(); + } + interface Callback { void gen(OpenGLInfo res); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java similarity index 81% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java index 27b43f84f..6d2957fc4 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForCustomize.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java @@ -1,16 +1,12 @@ -package com.tencent.matrix.openglleak.statistics.source; - -import android.os.Handler; - -import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; +package com.tencent.matrix.openglleak.statistics.resource; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -public class ResRecorderForCustomize implements ResRecordManager.Callback { +public class ResRecorder implements ResRecordManager.Callback { - public ResRecorderForCustomize() { + public ResRecorder() { } private List mList = new LinkedList<>(); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java deleted file mode 100644 index 533c39b46..000000000 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/source/ResRecorderForActivityLifecycle.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.tencent.matrix.openglleak.statistics.source; - -import android.os.Handler; - -import com.tencent.matrix.openglleak.statistics.LeakMonitorForActivityLifecycle_Old; -import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -@Deprecated -public class ResRecorderForActivityLifecycle implements ResRecordManager.Callback { - - private List infoList = new LinkedList<>(); - private Handler mH; - - private LeakMonitorForActivityLifecycle_Old.LeakListener mListener; - - public ResRecorderForActivityLifecycle() { - mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); - ResRecordManager.getInstance().registerCallback(this); - } - - public void setLeakListener(LeakMonitorForActivityLifecycle_Old.LeakListener mListener) { - this.mListener = mListener; - } - - @Override - public void gen(final OpenGLInfo oinfo) { - mH.post(new Runnable() { - @Override - public void run() { - if (oinfo == null) { - return; - } - - synchronized (infoList) { - infoList.add(oinfo); - } - } - }); - } - - @Override - public void delete(final OpenGLInfo del) { - mH.post(new Runnable() { - @Override - public void run() { - if (del == null) { - return; - } - - synchronized (infoList) { - infoList.remove(del); - } - } - }); - } - - public List getCopyList() { - List ll = new ArrayList<>(); - - synchronized (infoList) { - for (OpenGLInfo item : infoList) { - if (item == null) { - break; - } - - OpenGLInfo clone = new OpenGLInfo(item); - ll.add(clone); - } - } - - return ll; - } - - public void remove(OpenGLInfo info) { - if (infoList == null) { - return; - } - synchronized (infoList) { - infoList.remove(info); - } - } - - public List getAllHashCode() { - List ll = new ArrayList<>(); - - synchronized (infoList) { - for (OpenGLInfo item : infoList) { - if (item == null) { - break; - } - - ll.add(item.hashCode()); - } - } - - return ll; - } - - public void getNativeStack(OpenGLInfo info) { - synchronized (infoList) { - for (OpenGLInfo item : infoList) { - if (item == null) { - break; - } - - if (item.getType() == info.getType()) { - if (item.getThreadId().equals(info.getThreadId())) { - if (item.getId() == info.getId()) { - String stack = item.getNativeStack(); - info.setNativeStack(stack); - return; - } - } - } - } - } - } - - public void setLeak(OpenGLInfo info) { - synchronized (infoList) { - Iterator iterator = infoList.iterator(); - - while (iterator.hasNext()) { - OpenGLInfo item = iterator.next(); - if (item == null) { - break; - } - - if ((item.getType() == info.getType()) && (item.getThreadId().equals(info.getThreadId())) && (item.getId() == info.getId())) { - if (mListener != null) { - mListener.onLeak(item); - } - - item.release(); - iterator.remove(); - return; - } - } - } - } - - public void setMaybeLeak(OpenGLInfo info) { - synchronized (infoList) { - for (OpenGLInfo item : infoList) { - if (item == null) { - break; - } - - if ((item.getType() == info.getType()) && (item.getThreadId().equals(info.getThreadId())) && (item.getId() == info.getId())) { - item.setMaybeLeak(true); - info.setMaybeLeak(true); - - long now = System.currentTimeMillis(); - item.setMaybeLeakCheckTime(now); - info.setMaybeLeakCheckTime(now); - - if (mListener != null) { - mListener.onMaybeLeak(item); - } - - return; - } - } - } - } - - public OpenGLInfo getItemByHashCode(int hashCode) { - synchronized (infoList) { - for (OpenGLInfo item : infoList) { - if (item == null) { - break; - } - - if (item.hashCode() == hashCode) { - return item; - } - } - } - - return null; - } - -} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java new file mode 100644 index 000000000..26bb9af1d --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java @@ -0,0 +1,107 @@ +package com.tencent.matrix.openglleak.utils; + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +public class ActivityRecorder implements Application.ActivityLifecycleCallbacks { + + private static ActivityRecorder mInstance = new ActivityRecorder(); + private List mList = new LinkedList<>(); + + private ActivityRecorder() { + } + + public static ActivityRecorder getInstance() { + return mInstance; + } + + public void start(Application context) { + context.registerActivityLifecycleCallbacks(this); + } + + public void stop(Application context) { + context.unregisterActivityLifecycleCallbacks(this); + } + + private ActivityInfo currentActivityInfo = null; + + public ActivityInfo getCurrentActivityInfo() { + return currentActivityInfo; + } + + @Override + public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) { + currentActivityInfo = new ActivityInfo(activity.hashCode(), activity.getLocalClassName()); + mList.add(currentActivityInfo); + } + + @Override + public void onActivityStarted(@NonNull Activity activity) { + + } + + @Override + public void onActivityResumed(@NonNull Activity activity) { + currentActivityInfo = new ActivityInfo(activity.hashCode(), activity.getLocalClassName()); + } + + @Override + public void onActivityPaused(@NonNull Activity activity) { + + } + + @Override + public void onActivityStopped(@NonNull Activity activity) { + + } + + @Override + public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) { + + } + + @Override + public void onActivityDestroyed(@NonNull Activity activity) { + mList.remove(new ActivityInfo(activity.hashCode(), activity.getLocalClassName())); + } + + public class ActivityInfo { + int hashcode; + String name = ""; + + ActivityInfo(int code, String n) { + hashcode = code; + name = n; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ActivityInfo that = (ActivityInfo) o; + return hashcode == that.hashcode && + Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(hashcode, name); + } + + @Override + public String toString() { + return "ActivityInfo{" + + "hashcode=" + hashcode + + ", name='" + name + '\'' + + '}'; + } + } +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakLog.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakLog.java deleted file mode 100644 index 5e187a1e3..000000000 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/OpenGLLeakLog.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.tencent.matrix.openglleak.utils; - -public class OpenGLLeakLog { - - private static LogStub stub = null; - - public static void setLogStub(LogStub ls) { - stub = ls; - } - - public static void i(String tag, String msg) { - if (stub != null) { - stub.i(tag, msg); - } else { - android.util.Log.i(tag, msg); - } - } - - public static void d(String tag, String msg) { - if (stub != null) { - stub.d(tag, msg); - } else { - android.util.Log.d(tag, msg); - } - } - - public static void e(String tag, String msg) { - if (stub != null) { - stub.e(tag, msg); - } else { - android.util.Log.e(tag, msg); - } - } - - public static void w(String tag, String msg) { - if (stub != null) { - stub.w(tag, msg); - } else { - android.util.Log.w(tag, msg); - } - } - - public interface LogStub { - void i(String tag, String msg); - - void w(String tag, String msg); - - void d(String tag, String msg); - - void e(String tag, String msg); - } -} From 59a6aa9b9a4bdb5d1890f01b0dcd9d3b0e237e11 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 17:04:15 +0800 Subject: [PATCH 045/163] fix jni bug --- .../main/cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp | 2 +- 1 file changed, 1 insertion(+), 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 9a1e9d53e..2a9ab2d50 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 @@ -45,7 +45,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IIIIIIIIJ)V"); method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IIIIIIIIIJ)V"); method_onGlBufferData = env->GetStaticMethodID(class_OpenGLHook, "onGlBufferData", "(IJI)V"); - method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IIIJI)V"); + method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IIIIJ)V"); return true; } From 27d839c69fbedbd75d279fd82b5bfe1973bc7180 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 17:40:43 +0800 Subject: [PATCH 046/163] add java stack & native stack --- ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 8 +- ...atrix_openglleak_statistics_OpenGLInfo.cpp | 2 +- ..._matrix_openglleak_statistics_OpenGLInfo.h | 2 +- .../src/main/cpp/my_functions.h | 104 +++++++++++++++++- .../matrix/openglleak/hook/OpenGLHook.java | 24 ++-- .../openglleak/statistics/OpenGLInfo.java | 2 +- 6 files changed, 119 insertions(+), 23 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 2a9ab2d50..0e6d4951c 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 @@ -42,10 +42,10 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_onGlBindBuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindBuffer", "(II)V"); method_onGlBindFramebuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindFramebuffer", "(II)V"); method_onGlBindRenderbuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindRenderbuffer", "(II)V"); - method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IIIIIIIIJ)V"); - method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IIIIIIIIIJ)V"); - method_onGlBufferData = env->GetStaticMethodID(class_OpenGLHook, "onGlBufferData", "(IJI)V"); - method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IIIIJ)V"); + method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IIIIIIIIJLjava/lang/String;Ljava/lang/String;J)V"); + method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IIIIIIIIIJLjava/lang/String;Ljava/lang/String;J)V"); + method_onGlBufferData = env->GetStaticMethodID(class_OpenGLHook, "onGlBufferData", "(IJILjava/lang/String;Ljava/lang/String;J)V"); + method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IIIIJLjava/lang/String;Ljava/lang/String;J)V"); return true; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp index f2ee50de2..62e4c0147 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.cpp @@ -68,7 +68,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_ } extern "C" JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_OpenGLInfo_dumpNativeStack - (JNIEnv *env, jobject thiz, jlong jl) { + (JNIEnv *env, jclass thiz, jlong jl) { int64_t addr = jl; wechat_backtrace::Backtrace* ptr = (wechat_backtrace::Backtrace*)addr; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.h index b99381591..1cb563025 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_OpenGLInfo.h @@ -17,7 +17,7 @@ JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_OpenGLInfo_ (JNIEnv *, jobject thiz, jlong); JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_OpenGLInfo_dumpNativeStack - (JNIEnv *, jobject thiz, jlong); + (JNIEnv *, jclass thiz, jlong); #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 2e6ef7809..3cf5f45d7 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 @@ -568,8 +568,32 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, int pixel = Utils::getSizeOfPerPixel(internalformat, format, type); long size = width * height * pixel; JNIEnv *env = GET_ENV(); + + wechat_backtrace::Backtrace *backtracePrt = 0; + if (is_stacktrace_enabled) { + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( + MEMHOOK_BACKTRACE_MAX_FRAMES); + + 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); + } + + jstring java_stack; + char *javaStack; + if (is_javastack_enabled) { + javaStack = get_java_stack(); + java_stack = env->NewStringUTF(javaStack); + } else { + java_stack = env->NewStringUTF(""); + } + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, level, - internalformat, width, height, border, format, type, size); + internalformat, width, height, border, format, type, size, java_stack, (int64_t) backtracePrt); } } @@ -587,8 +611,32 @@ my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, int pixel = Utils::getSizeOfPerPixel(internalformat, format, type); long size = width * height * depth * pixel; JNIEnv *env = GET_ENV(); + + wechat_backtrace::Backtrace *backtracePrt = 0; + if (is_stacktrace_enabled) { + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( + MEMHOOK_BACKTRACE_MAX_FRAMES); + + 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); + } + + jstring java_stack; + char *javaStack; + if (is_javastack_enabled) { + javaStack = get_java_stack(); + java_stack = env->NewStringUTF(javaStack); + } else { + java_stack = env->NewStringUTF(""); + } + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage3D, target, level, - internalformat, width, height, depth, border, format, type, size); + internalformat, width, height, depth, border, format, type, size, java_stack, (int64_t) backtracePrt); } } @@ -653,7 +701,31 @@ my_glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage return; } JNIEnv *env = GET_ENV(); - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBufferData, target, size, usage); + + wechat_backtrace::Backtrace *backtracePrt = 0; + if (is_stacktrace_enabled) { + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( + MEMHOOK_BACKTRACE_MAX_FRAMES); + + 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); + } + + jstring java_stack; + char *javaStack; + if (is_javastack_enabled) { + javaStack = get_java_stack(); + java_stack = env->NewStringUTF(javaStack); + } else { + java_stack = env->NewStringUTF(""); + } + + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBufferData, target, size, usage, java_stack, (int64_t) backtracePrt); } } @@ -666,9 +738,33 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL return; } JNIEnv *env = GET_ENV(); + + wechat_backtrace::Backtrace *backtracePrt = 0; + if (is_stacktrace_enabled) { + wechat_backtrace::Backtrace backtrace_zero = BACKTRACE_INITIALIZER( + MEMHOOK_BACKTRACE_MAX_FRAMES); + + 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); + } + + jstring java_stack; + char *javaStack; + if (is_javastack_enabled) { + javaStack = get_java_stack(); + java_stack = env->NewStringUTF(javaStack); + } else { + java_stack = env->NewStringUTF(""); + } + long size = Utils::getRenderbufferSizeByFormula(internalformat, width, height); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlRenderbufferStorage, target, - width, height, internalformat, size); + width, height, internalformat, size, java_stack, (int64_t) backtracePrt); } } 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 7121b19e3..c3ec765c2 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 @@ -340,7 +340,7 @@ public static void onGlBindRenderbuffer(int target, int id) { } } - public static void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, long size) { + public static void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, long size, String javaStack, long nativeStack) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); @@ -357,12 +357,12 @@ public static void onGlTexImage2D(int target, int level, int internalFormat, int } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, info.getId(), eglContextId, size); + getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, info.getId(), eglContextId, size, javaStack, OpenGLInfo.dumpNativeStack(nativeStack)); } } - public static void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, long size) { + public static void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, long size, String javaStack, long nativeStack) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); @@ -379,12 +379,12 @@ public static void onGlTexImage3D(int target, int level, int internalFormat, int } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size); + getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size, javaStack, OpenGLInfo.dumpNativeStack(nativeStack)); } } - public static void onGlBufferData(int target, long size, int usage) { + public static void onGlBufferData(int target, long size, int usage, String javaStack, long nativeStack) { if (Thread.currentThread().getName().equals("RenderThread")) { return; } @@ -404,12 +404,12 @@ public static void onGlBufferData(int target, long size, int usage) { } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlBufferData(target, usage, info.getId(), eglContextId, size); + getInstance().mMemoryListener.onGlBufferData(target, usage, info.getId(), eglContextId, size, javaStack, OpenGLInfo.dumpNativeStack(nativeStack)); } } - public static void onGlRenderbufferStorage(int target, int internalformat, int width, int height, long size) { + public static void onGlRenderbufferStorage(int target, int internalformat, int width, int height, long size, String javaStack, long nativeStack) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); @@ -426,7 +426,7 @@ public static void onGlRenderbufferStorage(int target, int internalformat, int w } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, info.getId(), eglContextId, size); + getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, info.getId(), eglContextId, size, javaStack, OpenGLInfo.dumpNativeStack(nativeStack)); } } @@ -457,13 +457,13 @@ public interface BindListener { public interface MemoryListener { - void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, int id, long eglContextId, long size); + void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, int id, long eglContextId, long size, String javaStack, String nativeStack); - void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size); + void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size, String javaStack, String nativeStack); - void onGlBufferData(int target, int usage, int id, long eglContextId, long size); + void onGlBufferData(int target, int usage, int id, long eglContextId, long size, String javaStack, String nativeStack); - void onGlRenderbufferStorage(int target, int width, int height, int internalFormat, int id, long eglContextId, long size); + void onGlRenderbufferStorage(int target, int width, int height, int internalFormat, int id, long eglContextId, long size, String javaStack, String nativeStack); } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index 6e97c05ee..22a5a07d2 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -223,7 +223,7 @@ public void release() { private native void releaseNative(long nativeStackPtr); - private native String dumpNativeStack(long nativeStackPtr); + public static native String dumpNativeStack(long nativeStackPtr); @Override public String toString() { From 2dd8831edaa18cab1d83c37bedb8f8bb84d0145e Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 1 Dec 2021 17:45:53 +0800 Subject: [PATCH 047/163] =?UTF-8?q?OpenGlInfo=20=E6=8F=90=E4=BE=9B=20getAc?= =?UTF-8?q?tivityInfo=20=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix/openglleak/statistics/resource/OpenGLInfo.java | 4 ++++ 1 file changed, 4 insertions(+) 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 df23685c8..15c652436 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 @@ -97,6 +97,10 @@ public long getNativeStackPtr() { return nativeStackPtr; } + public ActivityRecorder.ActivityInfo getActivityInfo(){ + return activityInfo; + } + @Override public String toString() { return "OpenGLInfo{" + From 86e713d37ab853e312be29c863222ff1ceca50da Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 17:52:15 +0800 Subject: [PATCH 048/163] fix crash --- .../cpp/com_tencent_matrix_openglleak_hook_OpenGLHook.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 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 0e6d4951c..930fcae8a 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 @@ -42,10 +42,10 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_onGlBindBuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindBuffer", "(II)V"); method_onGlBindFramebuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindFramebuffer", "(II)V"); method_onGlBindRenderbuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindRenderbuffer", "(II)V"); - method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IIIIIIIIJLjava/lang/String;Ljava/lang/String;J)V"); - method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IIIIIIIIIJLjava/lang/String;Ljava/lang/String;J)V"); - method_onGlBufferData = env->GetStaticMethodID(class_OpenGLHook, "onGlBufferData", "(IJILjava/lang/String;Ljava/lang/String;J)V"); - method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IIIIJLjava/lang/String;Ljava/lang/String;J)V"); + method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IIIIIIIIJLjava/lang/String;J)V"); + method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IIIIIIIIIJLjava/lang/String;J)V"); + method_onGlBufferData = env->GetStaticMethodID(class_OpenGLHook, "onGlBufferData", "(IJILjava/lang/String;J)V"); + method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IIIIJLjava/lang/String;J)V"); return true; } From 3bfb2533cd9fda05cd91b84d61d6b40e74ca4e3b Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 1 Dec 2021 18:04:32 +0800 Subject: [PATCH 049/163] fix checkstyle error --- .../matrix/openglleak/statistics/resource/OpenGLInfo.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 15c652436..b08059ba3 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 @@ -1,6 +1,7 @@ package com.tencent.matrix.openglleak.statistics.resource; import com.tencent.matrix.openglleak.utils.ActivityRecorder; + import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; @@ -97,7 +98,7 @@ public long getNativeStackPtr() { return nativeStackPtr; } - public ActivityRecorder.ActivityInfo getActivityInfo(){ + public ActivityRecorder.ActivityInfo getActivityInfo() { return activityInfo; } From e996916e97effe73d5c7444f2800b5b0c925807a Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 1 Dec 2021 18:13:50 +0800 Subject: [PATCH 050/163] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B8=85=E7=90=86?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java | 4 ++-- .../openglleak/statistics/resource/ResRecordManager.java | 3 +-- 2 files changed, 3 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 7c73869f6..8e77b56bc 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 @@ -173,8 +173,8 @@ public void setJavaStackDump(boolean open) { OpenGLHook.getInstance().setJavaStackDump(true); } - public void reset() { - ResRecordManager.getInstance().reset(); + public void clear() { + ResRecordManager.getInstance().clear(); } } 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 c7c6db4fc..8f5b273be 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 @@ -133,8 +133,7 @@ public boolean isGLInfoRelease(OpenGLInfo item) { } } - public void reset() { - mCallbackList.clear(); + public void clear() { mInfoList.clear(); } From 71228bc6693f0e22da037470df6e2edae52d54d8 Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 1 Dec 2021 18:17:39 +0800 Subject: [PATCH 051/163] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20activityInfo=20?= =?UTF-8?q?=E8=AE=BF=E9=97=AE=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tencent/matrix/openglleak/utils/ActivityRecorder.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/utils/ActivityRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java index 26bb9af1d..8f9d5b34b 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java @@ -74,8 +74,8 @@ public void onActivityDestroyed(@NonNull Activity activity) { } public class ActivityInfo { - int hashcode; - String name = ""; + public int hashcode; + public String name; ActivityInfo(int code, String n) { hashcode = code; From 7d17c9e0d962b3dc58c8bb298b5d030dee54ac0f Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 20:58:37 +0800 Subject: [PATCH 052/163] add meminfo --- .../matrix/openglleak/hook/OpenGLHook.java | 29 ++-- .../openglleak/statistics/MemoryInfo.java | 128 ++++++++++++++++++ .../openglleak/statistics/OpenGLInfo.java | 15 +- 3 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java 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 c3ec765c2..a3db08813 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 @@ -5,6 +5,7 @@ import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.BindCenter; import com.tencent.matrix.openglleak.statistics.LeakMonitor; +import com.tencent.matrix.openglleak.statistics.MemoryInfo; import com.tencent.matrix.openglleak.statistics.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.OpenGLResRecorder; import com.tencent.matrix.util.MatrixLog; @@ -351,13 +352,16 @@ public static void onGlTexImage2D(int target, int level, int internalFormat, int return; } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); + String nativeStackString = OpenGLInfo.dumpNativeStack(nativeStack); if (openGLInfo != null) { - openGLInfo.setSize(size); + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStackString); + openGLInfo.setMemoryInfo(memoryInfo); OpenGLResRecorder.getInstance().replace(openGLInfo); } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, info.getId(), eglContextId, size, javaStack, OpenGLInfo.dumpNativeStack(nativeStack)); + getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStackString); } } @@ -373,13 +377,16 @@ public static void onGlTexImage3D(int target, int level, int internalFormat, int return; } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); + String nativeStackString = OpenGLInfo.dumpNativeStack(nativeStack); if (openGLInfo != null) { - openGLInfo.setSize(size); + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStackString); + openGLInfo.setMemoryInfo(memoryInfo); OpenGLResRecorder.getInstance().replace(openGLInfo); } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size, javaStack, OpenGLInfo.dumpNativeStack(nativeStack)); + getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStackString); } } @@ -398,13 +405,16 @@ public static void onGlBufferData(int target, long size, int usage, String javaS return; } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); + String nativeStackString = OpenGLInfo.dumpNativeStack(nativeStack); if (openGLInfo != null) { - openGLInfo.setSize(size); + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setBufferInfo(target, usage, info.getId(), eglContextId, size, javaStack, nativeStackString); + openGLInfo.setMemoryInfo(memoryInfo); OpenGLResRecorder.getInstance().replace(openGLInfo); } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlBufferData(target, usage, info.getId(), eglContextId, size, javaStack, OpenGLInfo.dumpNativeStack(nativeStack)); + getInstance().mMemoryListener.onGlBufferData(target, usage, info.getId(), eglContextId, size, javaStack, nativeStackString); } } @@ -420,13 +430,16 @@ public static void onGlRenderbufferStorage(int target, int internalformat, int w return; } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); + String nativeStackString = OpenGLInfo.dumpNativeStack(nativeStack); if (openGLInfo != null) { - openGLInfo.setSize(size); + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setRenderbufferInfo(target, width, height, internalformat, info.getId(), eglContextId, size, javaStack, nativeStackString); + openGLInfo.setMemoryInfo(memoryInfo); OpenGLResRecorder.getInstance().replace(openGLInfo); } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, info.getId(), eglContextId, size, javaStack, OpenGLInfo.dumpNativeStack(nativeStack)); + getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, info.getId(), eglContextId, size, javaStack, nativeStackString); } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java new file mode 100644 index 000000000..c58980b12 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java @@ -0,0 +1,128 @@ +package com.tencent.matrix.openglleak.statistics; + +public class MemoryInfo { + + private int target; + + private int level; + + private int internalFormat; + + private int width; + + private int height; + + private int depth; + + private int border; + + private int format; + + private int type; + + private int id; + + private long size; + + private long eglContextId; + + private int usage; + + private String javaStack; + + private String nativeStack; + + private OpenGLInfo.TYPE resType; + + public MemoryInfo() { + + } + + public void setTexturesInfo(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size, String javaStack, String nativeStack) { + this.target = target; + this.level = level; + this.internalFormat = internalFormat; + this.width = width; + this.height = height; + this.depth = depth; + this.border = border; + this.format = format; + this.type = type; + this.id = id; + this.eglContextId = eglContextId; + this.size = size; + this.javaStack = javaStack; + this.nativeStack = nativeStack; + resType = OpenGLInfo.TYPE.TEXTURE; + } + + public void setBufferInfo(int target, int usage, int id, long eglContextId, long size, String javaStack, String nativeStack) { + this.target = target; + this.usage = usage; + this.id = id; + this.eglContextId = eglContextId; + this.size = size; + this.javaStack = javaStack; + this.nativeStack = nativeStack; + resType = OpenGLInfo.TYPE.BUFFER; + } + + public void setRenderbufferInfo(int target, int width, int height, int internalFormat, int id, long eglContextId, long size, String javaStack, String nativeStack) { + this.target = target; + this.width = width; + this.height = height; + this.internalFormat = internalFormat; + this.id = id; + this.eglContextId = eglContextId; + this.size = size; + this.javaStack = javaStack; + this.nativeStack = nativeStack; + resType = OpenGLInfo.TYPE.RENDER_BUFFERS; + } + + @Override + public String toString() { + if (resType == OpenGLInfo.TYPE.TEXTURE) { + return "MemoryInfo{" + + "id=" + id + + ", eglContextId=" + eglContextId + + ", target=" + target + + ", level=" + level + + ", internalFormat=" + internalFormat + + ", width=" + width + + ", height=" + height + + ", depth=" + depth + + ", border=" + border + + ", format=" + format + + ", type=" + type + + ", size=" + size + + ", javaStack='" + javaStack + '\'' + + ", nativeStack='" + nativeStack + '\'' + + '}'; + } else if (resType == OpenGLInfo.TYPE.BUFFER) { + return "MemoryInfo{" + + "id=" + id + + ", eglContextId=" + eglContextId + + ", size=" + size + + ", target=" + target + + ", usage=" + usage + + ", javaStack='" + javaStack + '\'' + + ", nativeStack='" + nativeStack + '\'' + + '}'; + } else if (resType == OpenGLInfo.TYPE.RENDER_BUFFERS) { + return "MemoryInfo{" + + "id=" + id + + ", eglContextId=" + eglContextId + + ", target=" + target + + ", internalFormat=" + internalFormat + + ", width=" + width + + ", height=" + height + + ", size=" + size + + ", javaStack='" + javaStack + '\'' + + ", nativeStack='" + nativeStack + '\'' + + '}'; + } else { + return ""; + } + } +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index 22a5a07d2..16102189e 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -22,7 +22,6 @@ public class OpenGLInfo { private String nativeStack = ""; private long nativeStackPtr; private int operate; - private long size; private TYPE type; // use to dump private int allocCount = 1; @@ -36,6 +35,8 @@ public class OpenGLInfo { private String activityName; + private MemoryInfo memoryInfo; + private AtomicInteger counter; public enum TYPE { @@ -59,7 +60,7 @@ public OpenGLInfo(OpenGLInfo clone) { this.maybeLeak = clone.maybeLeak; this.activityName = clone.activityName; this.counter = clone.counter; - this.size = clone.size; + this.memoryInfo = clone.memoryInfo; } public OpenGLInfo(int error) { @@ -156,12 +157,12 @@ public void incAllocRecord(int id) { this.idList.add(id); } - public long getSize() { - return size; + public MemoryInfo getMemoryInfo() { + return memoryInfo; } - public void setSize(long size) { - this.size = size; + public void setMemoryInfo(MemoryInfo memoryInfo) { + this.memoryInfo = memoryInfo; } private String getOpStr() { @@ -232,11 +233,11 @@ public String toString() { ", eglContextNativeHandle='" + eglContextNativeHandle + '\'' + ", activityName=" + activityName + ", type='" + type.toString() + '\'' + - ", size='" + size + '\'' + ", threadId='" + threadId + '\'' + ", javaStack='" + javaStack + '\'' + ", nativeStack='" + nativeStack + '\'' + ", nativeStackPtr=" + nativeStackPtr + + ", memoryInfo=" + memoryInfo + '}'; } From e2fd9b2c7174c74bdd0ccc4dfd6b11d26abf7e5a Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 21:09:06 +0800 Subject: [PATCH 053/163] add dump change --- .../matrix/openglleak/statistics/MemoryInfo.java | 14 ++++---------- .../matrix/openglleak/statistics/OpenGLInfo.java | 2 +- .../openglleak/statistics/OpenGLResRecorder.java | 7 ++++++- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java index c58980b12..b85ccf2cd 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java @@ -84,9 +84,7 @@ public void setRenderbufferInfo(int target, int width, int height, int internalF public String toString() { if (resType == OpenGLInfo.TYPE.TEXTURE) { return "MemoryInfo{" + - "id=" + id + - ", eglContextId=" + eglContextId + - ", target=" + target + + "target=" + target + ", level=" + level + ", internalFormat=" + internalFormat + ", width=" + width + @@ -101,19 +99,15 @@ public String toString() { '}'; } else if (resType == OpenGLInfo.TYPE.BUFFER) { return "MemoryInfo{" + - "id=" + id + - ", eglContextId=" + eglContextId + - ", size=" + size + - ", target=" + target + + "target=" + target + ", usage=" + usage + + ", size=" + size + ", javaStack='" + javaStack + '\'' + ", nativeStack='" + nativeStack + '\'' + '}'; } else if (resType == OpenGLInfo.TYPE.RENDER_BUFFERS) { return "MemoryInfo{" + - "id=" + id + - ", eglContextId=" + eglContextId + - ", target=" + target + + "target=" + target + ", internalFormat=" + internalFormat + ", width=" + width + ", height=" + height + diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index 16102189e..d5d115637 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -237,7 +237,7 @@ public String toString() { ", javaStack='" + javaStack + '\'' + ", nativeStack='" + nativeStack + '\'' + ", nativeStackPtr=" + nativeStackPtr + - ", memoryInfo=" + memoryInfo + + "\n memoryInfo=" + memoryInfo + '}'; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 49cf4756e..2c6973b96 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -197,7 +197,10 @@ public String dumpToString() { int javaHash = info.getJavaStack().hashCode(); int nativeHash = info.getNativeStack().hashCode(); - long infoHash = javaHash + nativeHash; + int memoryJavaHash = info.getJavaStack().hashCode(); + int memoryNativeHash = info.getNativeStack().hashCode(); + + long infoHash = javaHash + nativeHash + memoryNativeHash + memoryJavaHash; OpenGLInfo oldInfo = infoMap.get(infoHash); if (oldInfo == null) { @@ -306,6 +309,8 @@ private String getResListString(List resList) { .append(String.format(" java stack = %s", res.getJavaStack())) .append("\n") .append(String.format(" native stack = %s", res.getNativeStack())) + .append("\n") + .append(String.format(" memory info = %s", res.getMemoryInfo().toString())) .append("\n"); } return result.toString(); From c85e6aa7ddaec5c4b31fa27eb9a2c45721bff916 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 21:11:22 +0800 Subject: [PATCH 054/163] reduce toString();l --- .../com/tencent/matrix/openglleak/statistics/OpenGLInfo.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index d5d115637..5cb93ecda 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -236,8 +236,6 @@ public String toString() { ", threadId='" + threadId + '\'' + ", javaStack='" + javaStack + '\'' + ", nativeStack='" + nativeStack + '\'' + - ", nativeStackPtr=" + nativeStackPtr + - "\n memoryInfo=" + memoryInfo + '}'; } From e5e527bba6b0117c6e41acfea0329aa193b40e73 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 21:19:47 +0800 Subject: [PATCH 055/163] fix null point --- .../matrix/openglleak/statistics/OpenGLResRecorder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 2c6973b96..ce94026ff 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -11,6 +11,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; + import com.tencent.matrix.openglleak.utils.ExecuteCenter; import java.util.ArrayList; @@ -310,7 +311,7 @@ private String getResListString(List resList) { .append("\n") .append(String.format(" native stack = %s", res.getNativeStack())) .append("\n") - .append(String.format(" memory info = %s", res.getMemoryInfo().toString())) + .append(String.format(" memory info = %s", res.getMemoryInfo() == null ? "" : res.getMemoryInfo().toString())) .append("\n"); } return result.toString(); From 251589e7e8898d8b5529a4458f345f55e49c00a5 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 21:46:51 +0800 Subject: [PATCH 056/163] fix dump format --- .../statistics/OpenGLResRecorder.java | 132 +++++++++--------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index ce94026ff..915736289 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -217,75 +217,77 @@ public String dumpToString() { infoMap.put(infoHash, oldInfo); } } + } - List textureList = new ArrayList<>(); - List bufferList = new ArrayList<>(); - List framebufferList = new ArrayList<>(); - List renderbufferList = new ArrayList<>(); + List textureList = new ArrayList<>(); + List bufferList = new ArrayList<>(); + List framebufferList = new ArrayList<>(); + List renderbufferList = new ArrayList<>(); - for (OpenGLInfo openGLInfo : infoMap.values()) { - if (openGLInfo.getType() == OpenGLInfo.TYPE.TEXTURE) { - textureList.add(openGLInfo); - } - if (openGLInfo.getType() == OpenGLInfo.TYPE.BUFFER) { - bufferList.add(openGLInfo); - } - if (openGLInfo.getType() == OpenGLInfo.TYPE.FRAME_BUFFERS) { - framebufferList.add(openGLInfo); - } - if (openGLInfo.getType() == OpenGLInfo.TYPE.RENDER_BUFFERS) { - renderbufferList.add(openGLInfo); - } + for (OpenGLInfo openGLInfo : infoMap.values()) { + if (openGLInfo.getType() == OpenGLInfo.TYPE.TEXTURE) { + textureList.add(openGLInfo); + } + if (openGLInfo.getType() == OpenGLInfo.TYPE.BUFFER) { + bufferList.add(openGLInfo); + } + if (openGLInfo.getType() == OpenGLInfo.TYPE.FRAME_BUFFERS) { + framebufferList.add(openGLInfo); + } + if (openGLInfo.getType() == OpenGLInfo.TYPE.RENDER_BUFFERS) { + renderbufferList.add(openGLInfo); } - - Comparator comparator = new Comparator() { - @Override - public int compare(OpenGLInfo o1, OpenGLInfo o2) { - return o1.getAllocCount() - o2.getAllocCount(); - } - }; - - Collections.sort(textureList, comparator); - Collections.sort(bufferList, comparator); - Collections.sort(framebufferList, comparator); - Collections.sort(renderbufferList, comparator); - - final String dottedLine = "-------------------------------------------------------------------------"; - final String waveLine = "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"; - - result.append(dottedLine) - .append(String.format("\t\t\ttextures Count = %d", textureList.size())) - .append(String.format("\t\t\tbuffer Count = %d", bufferList.size())) - .append(String.format("\t\t\tframebuffer Count = %d", framebufferList.size())) - .append(String.format("\t\t\trenderbuffer Count = %d", renderbufferList.size())) - .append(dottedLine) - .append("\n") - .append(waveLine) - .append("\n") - .append("\t\t\ttexture part :") - .append(waveLine) - .append("\n") - .append(getResListString(textureList)) - .append('\n') - .append(waveLine) - .append("\t\t\tbuffers part :") - .append(waveLine) - .append("\n") - .append(getResListString(bufferList)) - .append("\n") - .append(waveLine) - .append("\n") - .append("\t\t\tframebuffers part :") - .append(waveLine) - .append("\n") - .append(getResListString(framebufferList)) - .append("\n") - .append(waveLine) - .append("\n") - .append("\t\t\trenderbuffer part :") - .append(waveLine) - .append("\n"); } + + Comparator comparator = new Comparator() { + @Override + public int compare(OpenGLInfo o1, OpenGLInfo o2) { + return o1.getAllocCount() - o2.getAllocCount(); + } + }; + + Collections.sort(textureList, comparator); + Collections.sort(bufferList, comparator); + Collections.sort(framebufferList, comparator); + Collections.sort(renderbufferList, comparator); + + final String dottedLine = "-------------------------------------------------------------------------"; + final String waveLine = "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"; + + result.append(dottedLine) + .append("\n") + .append(String.format("\t\t\ttextures Count = %d\n", textureList.size())) + .append(String.format("\t\t\tbuffer Count = %d\n", bufferList.size())) + .append(String.format("\t\t\tframebuffer Count = %d\n", framebufferList.size())) + .append(String.format("\t\t\trenderbuffer Count = %d\n", renderbufferList.size())) + .append(dottedLine) + .append("\n") + .append(waveLine) + .append("\n") + .append("\t\t\ttexture part :\n") + .append(waveLine) + .append("\n") + .append(getResListString(textureList)) + .append('\n') + .append(waveLine) + .append("\t\t\tbuffers part :\n") + .append(waveLine) + .append("\n") + .append(getResListString(bufferList)) + .append("\n") + .append(waveLine) + .append("\n") + .append("\t\t\tframebuffers part :\n") + .append(waveLine) + .append("\n") + .append(getResListString(framebufferList)) + .append("\n") + .append(waveLine) + .append("\n") + .append("\t\t\trenderbuffer part :\n") + .append(waveLine) + .append("\n"); + return result.toString(); } From 7737c454849f5182e3e4dd0ff39c137b8aa9c0e1 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 22:01:18 +0800 Subject: [PATCH 057/163] fix dump formate --- .../openglleak/statistics/OpenGLResRecorder.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 915736289..dff1e034e 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -270,6 +270,7 @@ public int compare(OpenGLInfo o1, OpenGLInfo o2) { .append(getResListString(textureList)) .append('\n') .append(waveLine) + .append("\n") .append("\t\t\tbuffers part :\n") .append(waveLine) .append("\n") @@ -277,14 +278,9 @@ public int compare(OpenGLInfo o1, OpenGLInfo o2) { .append("\n") .append(waveLine) .append("\n") - .append("\t\t\tframebuffers part :\n") - .append(waveLine) - .append("\n") - .append(getResListString(framebufferList)) - .append("\n") - .append(waveLine) - .append("\n") .append("\t\t\trenderbuffer part :\n") + .append(getResListString(renderbufferList)) + .append("\n") .append(waveLine) .append("\n"); @@ -314,7 +310,7 @@ private String getResListString(List resList) { .append(String.format(" native stack = %s", res.getNativeStack())) .append("\n") .append(String.format(" memory info = %s", res.getMemoryInfo() == null ? "" : res.getMemoryInfo().toString())) - .append("\n"); + .append("\n\n\n"); } return result.toString(); } From b886722270d787215bb8b431ab177584c0eccc1c Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 22:07:17 +0800 Subject: [PATCH 058/163] change dump format --- .../matrix/openglleak/statistics/OpenGLResRecorder.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/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index dff1e034e..2be1e06aa 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -279,9 +279,9 @@ public int compare(OpenGLInfo o1, OpenGLInfo o2) { .append(waveLine) .append("\n") .append("\t\t\trenderbuffer part :\n") - .append(getResListString(renderbufferList)) - .append("\n") .append(waveLine) + .append("\n") + .append(getResListString(renderbufferList)) .append("\n"); return result.toString(); From 7353366b140cda11cd1dbeda3b1754ccb62d651a Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 1 Dec 2021 22:35:22 +0800 Subject: [PATCH 059/163] fix collect stack bug --- .../matrix/openglleak/statistics/MemoryInfo.java | 12 ++++++++++-- .../matrix/openglleak/statistics/OpenGLInfo.java | 12 ++++-------- .../openglleak/statistics/OpenGLResRecorder.java | 5 +++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java index b85ccf2cd..0fd18ee38 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java @@ -28,9 +28,9 @@ public class MemoryInfo { private int usage; - private String javaStack; + private String javaStack = ""; - private String nativeStack; + private String nativeStack = ""; private OpenGLInfo.TYPE resType; @@ -56,6 +56,14 @@ public void setTexturesInfo(int target, int level, int internalFormat, int width resType = OpenGLInfo.TYPE.TEXTURE; } + public String getJavaStack() { + return javaStack; + } + + public String getNativeStack() { + return nativeStack; + } + public void setBufferInfo(int target, int usage, int id, long eglContextId, long size, String javaStack, String nativeStack) { this.target = target; this.usage = usage; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java index 5cb93ecda..0b05b76ab 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLInfo.java @@ -61,14 +61,7 @@ public OpenGLInfo(OpenGLInfo clone) { this.activityName = clone.activityName; this.counter = clone.counter; this.memoryInfo = clone.memoryInfo; - } - - public OpenGLInfo(int error) { - this.error = error; - } - - public OpenGLInfo(TYPE type) { - this.type = type; + this.idList = clone.idList; } public OpenGLInfo(TYPE type, int id, long eglContextNativeHandle, int operate) { @@ -76,6 +69,7 @@ public OpenGLInfo(TYPE type, int id, long eglContextNativeHandle, int operate) { this.eglContextNativeHandle = eglContextNativeHandle; this.operate = operate; this.type = type; + idList.add(id); } public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, int operate) { @@ -84,6 +78,7 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.eglContextNativeHandle = eglContextNativeHandle; this.operate = operate; this.type = type; + idList.add(id); } public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, int operate, String activityName, AtomicInteger counter) { @@ -96,6 +91,7 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.type = type; this.activityName = activityName; this.counter = counter; + idList.add(id); } public int getId() { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 2be1e06aa..c9b1c2aef 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -198,8 +198,9 @@ public String dumpToString() { int javaHash = info.getJavaStack().hashCode(); int nativeHash = info.getNativeStack().hashCode(); - int memoryJavaHash = info.getJavaStack().hashCode(); - int memoryNativeHash = info.getNativeStack().hashCode(); + MemoryInfo memoryInfo = info.getMemoryInfo(); + int memoryJavaHash = memoryInfo == null ? 0 : memoryInfo.getJavaStack().hashCode(); + int memoryNativeHash = memoryInfo == null ? 0 : info.getNativeStack().hashCode(); long infoHash = javaHash + nativeHash + memoryNativeHash + memoryJavaHash; From ae753ec2052f4811b11d570e2b41fe2c0d126dcf Mon Sep 17 00:00:00 2001 From: opdeng Date: Thu, 2 Dec 2021 11:24:32 +0800 Subject: [PATCH 060/163] =?UTF-8?q?fix=20=E8=8E=B7=E5=8F=96=E4=B8=8D?= =?UTF-8?q?=E4=BA=86=E9=A6=96=E5=B1=8F=20Activity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../statistics/LeakMonitorDefault.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java index c2a998028..f0c5f81b0 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java @@ -10,10 +10,12 @@ import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.util.MatrixLog; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; public abstract class LeakMonitorDefault implements Application.ActivityLifecycleCallbacks { @@ -27,6 +29,16 @@ protected LeakMonitorDefault() { public void start(Application context) { context.registerActivityLifecycleCallbacks(this); MatrixLog.i(TAG, "start"); + + Activity currentActivity = getActivity(); + if (null != currentActivity) { + ActivityLeakMonitor activityLeakMonitor = new ActivityLeakMonitor(currentActivity.hashCode(), new CustomizeLeakMonitor()); + activityLeakMonitor.start(); + + synchronized (mActivityLeakMonitor) { + mActivityLeakMonitor.add(activityLeakMonitor); + } + } } public void stop(Application context) { @@ -102,6 +114,31 @@ public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bun } + public static Activity getActivity() { + Class activityThreadClass = null; + try { + activityThreadClass = Class.forName("android.app.ActivityThread"); + Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null); + Field activitiesField = activityThreadClass.getDeclaredField("mActivities"); + activitiesField.setAccessible(true); + Map activities = (Map) activitiesField.get(activityThread); + for (Object activityRecord : activities.values()) { + Class activityRecordClass = activityRecord.getClass(); + Field pausedField = activityRecordClass.getDeclaredField("paused"); + pausedField.setAccessible(true); + if (!pausedField.getBoolean(activityRecord)) { + Field activityField = activityRecordClass.getDeclaredField("activity"); + activityField.setAccessible(true); + Activity activity = (Activity) activityField.get(activityRecord); + return activity; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + class ActivityLeakMonitor { private int mActivityHashCode; private CustomizeLeakMonitor mMonitor; From 5ecefe285c398def9ad35302a425efe3510ab95b Mon Sep 17 00:00:00 2001 From: aurorani Date: Fri, 19 Nov 2021 16:16:56 +0800 Subject: [PATCH 061/163] feat: Disable dump if SDK version of current device is unsupported. --- .../main/java/com/tencent/matrix/memorydump/MemoryDump.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt b/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt index 583032da9..0df138849 100644 --- a/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt +++ b/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt @@ -242,7 +242,13 @@ class DumpHandler internal constructor( Native Function Handlers. */ +private const val SUPPORTED_API_GUARD = 31 // Now is Android 12 (S). + private fun initialize(): Boolean { + if (Build.VERSION.SDK_INT > SUPPORTED_API_GUARD) { + MatrixLog.e(TAG, "Unsupported API version. Stop initialization.") + return false + } System.loadLibrary("matrix-memorydump") val success = initializeNative() if (!success) { From 3dd7a3aae5b1197d0a9d074b5f3652ba45e12d1c Mon Sep 17 00:00:00 2001 From: aurorani Date: Fri, 19 Nov 2021 16:54:10 +0800 Subject: [PATCH 062/163] Revert "feat: Disable dump if SDK version of current device is unsupported." This reverts commit 62853653fd7fdd50ab6c1795f1e05149ca5ae6ae. --- .../main/java/com/tencent/matrix/memorydump/MemoryDump.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt b/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt index 0df138849..583032da9 100644 --- a/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt +++ b/matrix/matrix-android/matrix-memory-dump/src/main/java/com/tencent/matrix/memorydump/MemoryDump.kt @@ -242,13 +242,7 @@ class DumpHandler internal constructor( Native Function Handlers. */ -private const val SUPPORTED_API_GUARD = 31 // Now is Android 12 (S). - private fun initialize(): Boolean { - if (Build.VERSION.SDK_INT > SUPPORTED_API_GUARD) { - MatrixLog.e(TAG, "Unsupported API version. Stop initialization.") - return false - } System.loadLibrary("matrix-memorydump") val success = initializeNative() if (!success) { From a13439b607e3d521ae6fe73fb1776a8e166a8c06 Mon Sep 17 00:00:00 2001 From: aurorani Date: Fri, 19 Nov 2021 17:02:03 +0800 Subject: [PATCH 063/163] feat: Disable dump if SDK version of current device is unsupported. --- .../matrix/resource/config/ResourceConfig.java | 2 ++ .../matrix/resource/config/SharePluginInfo.java | 7 ++++--- .../resource/processor/ForkAnalyseProcessor.java | 12 ++++++++++++ .../matrix/resource/processor/ForkDumpProcessor.java | 8 ++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/ResourceConfig.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/ResourceConfig.java index ba9836095..e768e2c84 100644 --- a/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/ResourceConfig.java +++ b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/config/ResourceConfig.java @@ -27,6 +27,8 @@ public final class ResourceConfig { public static final String TAG = "Matrix.ResourceConfig"; + public static final int FORK_DUMP_SUPPORTED_API_GUARD = 31; // Now is Android 12 (S). + public enum DumpMode { NO_DUMP, // report only AUTO_DUMP, // auto dump hprof 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 38047e822..a5f7e6a67 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 @@ -35,8 +35,9 @@ public class SharePluginInfo { public static final String ISSUE_NOTIFICATION_ID = "notification_id"; public static final class IssueType { - public static final int LEAK_FOUND = 0; - public static final int ERR_FILE_NOT_FOUND = 2; - public static final int ERR_ANALYSE_OOM = 3; + public static final int LEAK_FOUND = 0; + public static final int ERR_FILE_NOT_FOUND = 2; + public static final int ERR_ANALYSE_OOM = 3; + public static final int ERR_UNSUPPORTED_API = 4; } } 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 657fddb34..eb53b4598 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 @@ -1,5 +1,7 @@ package com.tencent.matrix.resource.processor; +import android.os.Build; + import com.tencent.matrix.memorydump.MemoryDumpManager; import com.tencent.matrix.resource.analyzer.model.ActivityLeakResult; import com.tencent.matrix.resource.analyzer.model.DestroyedActivityInfo; @@ -26,6 +28,16 @@ public ForkAnalyseProcessor(ActivityRefWatcher watcher) { @Override public boolean process(DestroyedActivityInfo destroyedActivityInfo) { + 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( + SharePluginInfo.IssueType.ERR_UNSUPPORTED_API, + ResourceConfig.DumpMode.FORK_ANALYSE, + destroyedActivityInfo.mActivityName, destroyedActivityInfo.mKey, + "Unsupported API", "0"); + return false; + } + getWatcher().triggerGc(); if (dumpAndAnalyse( 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 1d2f1a929..27d62e231 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 @@ -1,8 +1,11 @@ package com.tencent.matrix.resource.processor; +import android.os.Build; + import com.tencent.matrix.memorydump.MemoryDumpManager; 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.watcher.ActivityRefWatcher; import com.tencent.matrix.util.MatrixLog; @@ -24,6 +27,11 @@ public ForkDumpProcessor(ActivityRefWatcher watcher) { @Override public boolean process(DestroyedActivityInfo destroyedActivityInfo) { + if (Build.VERSION.SDK_INT > ResourceConfig.FORK_DUMP_SUPPORTED_API_GUARD) { + MatrixLog.e(TAG, "unsupported API version " + Build.VERSION.SDK_INT); + return false; + } + final long dumpStart = System.currentTimeMillis(); final File hprof = getDumpStorageManager().newHprofFile(); From 7d29406d98f2177d3cd89e5ca7d5489b5e33feff Mon Sep 17 00:00:00 2001 From: opdeng Date: Thu, 2 Dec 2021 11:35:14 +0800 Subject: [PATCH 064/163] fix ConcurrentModificationException crash --- .../statistics/resource/ResRecordManager.java | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 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 8f5b273be..f46451a23 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 @@ -37,9 +37,11 @@ public void run() { mInfoList.add(gen); } - for (Callback cb : mCallbackList) { - if (null != cb) { - cb.gen(gen); + synchronized (mCallbackList) { + for (Callback cb : mCallbackList) { + if (null != cb) { + cb.gen(gen); + } } } } @@ -75,9 +77,11 @@ public void run() { mInfoList.remove(del); } - for (Callback cb : mCallbackList) { - if (null != cb) { - cb.delete(del); + synchronized (mCallbackList) { + for (Callback cb : mCallbackList) { + if (null != cb) { + cb.delete(del); + } } } } @@ -113,18 +117,22 @@ protected void registerCallback(Callback callback) { return; } - if (mCallbackList.contains(callback)) { - return; - } + synchronized (mCallbackList) { + if (mCallbackList.contains(callback)) { + return; + } - mCallbackList.add(callback); + mCallbackList.add(callback); + } } protected void unregisterCallback(Callback callback) { if (null == callback) { return; } - mCallbackList.remove(callback); + synchronized (mCallbackList) { + mCallbackList.remove(callback); + } } public boolean isGLInfoRelease(OpenGLInfo item) { @@ -134,7 +142,9 @@ public boolean isGLInfoRelease(OpenGLInfo item) { } public void clear() { - mInfoList.clear(); + synchronized (mInfoList) { + mInfoList.clear(); + } } interface Callback { From 60606168b21cb5dc51263c8ed4abc14df062bdac Mon Sep 17 00:00:00 2001 From: opdeng Date: Thu, 2 Dec 2021 14:41:19 +0800 Subject: [PATCH 065/163] =?UTF-8?q?fix=20=E8=B7=A8=20activity=20=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E4=B8=8A=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../openglleak/statistics/LeakMonitorDefault.java | 14 +++++++++----- .../matrix/openglleak/utils/ActivityRecorder.java | 10 +++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java index f0c5f81b0..a9283637c 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java @@ -66,20 +66,24 @@ public void onActivityDestroyed(@NonNull Activity activity) { MatrixLog.i(TAG, "onActivityDestroyed " + activityHashCode); synchronized (mActivityLeakMonitor) { + List leaks = null; + Iterator it = mActivityLeakMonitor.iterator(); while (it.hasNext()) { - ActivityLeakMonitor item = it.next(); - if (null == item) { + ActivityLeakMonitor activityLeakMonitor = it.next(); + if (null == activityLeakMonitor) { continue; } - if (item.getActivityHashCode() == activityHashCode) { + if (activityLeakMonitor.getActivityHashCode() == activityHashCode) { it.remove(); - List leaks = item.end(); + leaks = activityLeakMonitor.end(); for (OpenGLInfo leakItem : leaks) { if (null != leakItem) { - onLeak(leakItem); + if (leakItem.getActivityInfo().activityHashcode == activityLeakMonitor.mActivityHashCode) { + onLeak(leakItem); + } } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java index 8f9d5b34b..f4b4edbe9 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java @@ -74,11 +74,11 @@ public void onActivityDestroyed(@NonNull Activity activity) { } public class ActivityInfo { - public int hashcode; + public int activityHashcode; public String name; ActivityInfo(int code, String n) { - hashcode = code; + activityHashcode = code; name = n; } @@ -87,19 +87,19 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ActivityInfo that = (ActivityInfo) o; - return hashcode == that.hashcode && + return activityHashcode == that.activityHashcode && Objects.equals(name, that.name); } @Override public int hashCode() { - return Objects.hash(hashcode, name); + return Objects.hash(activityHashcode, name); } @Override public String toString() { return "ActivityInfo{" + - "hashcode=" + hashcode + + "activityHashcode=" + activityHashcode + ", name='" + name + '\'' + '}'; } From 26c915542da63fbcc43a289dabb2c48ee250a570 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 2 Dec 2021 14:58:35 +0800 Subject: [PATCH 066/163] fix dump logic --- .../matrix/openglleak/hook/OpenGLHook.java | 28 ++- .../openglleak/statistics/MemoryInfo.java | 172 +++++++++++++----- .../statistics/OpenGLResRecorder.java | 13 +- 3 files changed, 151 insertions(+), 62 deletions(-) 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 a3db08813..cc89a01d3 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 @@ -352,16 +352,15 @@ public static void onGlTexImage2D(int target, int level, int internalFormat, int return; } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); - String nativeStackString = OpenGLInfo.dumpNativeStack(nativeStack); if (openGLInfo != null) { MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStackString); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); OpenGLResRecorder.getInstance().replace(openGLInfo); } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStackString); + getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, info.getId(), eglContextId, size); } } @@ -377,16 +376,15 @@ public static void onGlTexImage3D(int target, int level, int internalFormat, int return; } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); - String nativeStackString = OpenGLInfo.dumpNativeStack(nativeStack); if (openGLInfo != null) { MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStackString); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); OpenGLResRecorder.getInstance().replace(openGLInfo); } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size, javaStack, nativeStackString); + getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, info.getId(), eglContextId, size); } } @@ -405,16 +403,15 @@ public static void onGlBufferData(int target, long size, int usage, String javaS return; } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); - String nativeStackString = OpenGLInfo.dumpNativeStack(nativeStack); if (openGLInfo != null) { MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setBufferInfo(target, usage, info.getId(), eglContextId, size, javaStack, nativeStackString); + memoryInfo.setBufferInfo(target, usage, info.getId(), eglContextId, size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); OpenGLResRecorder.getInstance().replace(openGLInfo); } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlBufferData(target, usage, info.getId(), eglContextId, size, javaStack, nativeStackString); + getInstance().mMemoryListener.onGlBufferData(target, usage, info.getId(), eglContextId, size); } } @@ -430,16 +427,15 @@ public static void onGlRenderbufferStorage(int target, int internalformat, int w return; } OpenGLInfo openGLInfo = OpenGLResRecorder.getInstance().getItemByEGLContextAndId(info.getType(), info.getEglContextNativeHandle(), info.getId()); - String nativeStackString = OpenGLInfo.dumpNativeStack(nativeStack); if (openGLInfo != null) { MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setRenderbufferInfo(target, width, height, internalformat, info.getId(), eglContextId, size, javaStack, nativeStackString); + memoryInfo.setRenderbufferInfo(target, width, height, internalformat, info.getId(), eglContextId, size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); OpenGLResRecorder.getInstance().replace(openGLInfo); } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, info.getId(), eglContextId, size, javaStack, nativeStackString); + getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, info.getId(), eglContextId, size); } } @@ -470,13 +466,13 @@ public interface BindListener { public interface MemoryListener { - void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, int id, long eglContextId, long size, String javaStack, String nativeStack); + void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, int id, long eglContextId, long size); - void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size, String javaStack, String nativeStack); + void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size); - void onGlBufferData(int target, int usage, int id, long eglContextId, long size, String javaStack, String nativeStack); + void onGlBufferData(int target, int usage, int id, long eglContextId, long size); - void onGlRenderbufferStorage(int target, int width, int height, int internalFormat, int id, long eglContextId, long size, String javaStack, String nativeStack); + void onGlRenderbufferStorage(int target, int width, int height, int internalFormat, int id, long eglContextId, long size); } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java index 0fd18ee38..857f55a27 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java @@ -1,5 +1,8 @@ package com.tencent.matrix.openglleak.statistics; +import java.util.ArrayList; +import java.util.List; + public class MemoryInfo { private int target; @@ -32,13 +35,17 @@ public class MemoryInfo { private String nativeStack = ""; + private long nativeStackPtr; + private OpenGLInfo.TYPE resType; + private final List paramsList = new ArrayList<>(); + public MemoryInfo() { } - public void setTexturesInfo(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size, String javaStack, String nativeStack) { + public void setTexturesInfo(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { this.target = target; this.level = level; this.internalFormat = internalFormat; @@ -52,8 +59,13 @@ public void setTexturesInfo(int target, int level, int internalFormat, int width this.eglContextId = eglContextId; this.size = size; this.javaStack = javaStack; - this.nativeStack = nativeStack; + this.nativeStackPtr = nativeStackPtr; resType = OpenGLInfo.TYPE.TEXTURE; + appendParamsInfos(this); + } + + public OpenGLInfo.TYPE getResType() { + return resType; } public String getJavaStack() { @@ -61,21 +73,128 @@ public String getJavaStack() { } public String getNativeStack() { + if (nativeStack.isEmpty() && nativeStackPtr != 0) { + nativeStack = OpenGLInfo.dumpNativeStack(nativeStackPtr); + } return nativeStack; } - public void setBufferInfo(int target, int usage, int id, long eglContextId, long size, String javaStack, String nativeStack) { + public int getTarget() { + return target; + } + + public int getLevel() { + return level; + } + + public int getInternalFormat() { + return internalFormat; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getDepth() { + return depth; + } + + public int getBorder() { + return border; + } + + public int getFormat() { + return format; + } + + public int getType() { + return type; + } + + public int getId() { + return id; + } + + public long getSize() { + return size; + } + + public long getEglContextId() { + return eglContextId; + } + + public int getUsage() { + return usage; + } + + public void appendParamsInfos(MemoryInfo memoryInfo) { + if (memoryInfo == null) { + return; + } + OpenGLInfo.TYPE resType = memoryInfo.getResType(); + if (resType == OpenGLInfo.TYPE.TEXTURE) { + paramsList.add("MemoryInfo{" + + "target=" + memoryInfo.getTarget() + + ", id=" + memoryInfo.getId() + + ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + + ", level=" + memoryInfo.getLevel() + + ", internalFormat=" + memoryInfo.getInternalFormat() + + ", width=" + memoryInfo.getWidth() + + ", height=" + memoryInfo.getHeight() + + ", depth=" + memoryInfo.getDepth() + + ", border=" + memoryInfo.getBorder() + + ", format=" + memoryInfo.getFormat() + + ", type=" + memoryInfo.getType() + + ", size=" + memoryInfo.getSize() + + '}'); + } else if (resType == OpenGLInfo.TYPE.BUFFER) { + paramsList.add("MemoryInfo{" + + "target=" + memoryInfo.getTarget() + + ", id=" + memoryInfo.getId() + + ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + + ", usage=" + memoryInfo.getUsage() + + ", size=" + memoryInfo.getSize() + + '}'); + } else if (resType == OpenGLInfo.TYPE.RENDER_BUFFERS) { + paramsList.add("MemoryInfo{" + + "target=" + memoryInfo.getTarget() + + ", id=" + memoryInfo.getId() + + ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + + ", internalFormat=" + memoryInfo.getInternalFormat() + + ", width=" + memoryInfo.getWidth() + + ", height=" + memoryInfo.getHeight() + + ", size=" + memoryInfo.getSize() + + '}'); + } + + } + + public String getParamsInfos() { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < paramsList.size(); i++) { + result.append(paramsList.get(i)) + .append("\n"); + } + return result.toString(); + } + + public void setBufferInfo(int target, int usage, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { this.target = target; this.usage = usage; this.id = id; this.eglContextId = eglContextId; this.size = size; this.javaStack = javaStack; - this.nativeStack = nativeStack; + this.nativeStackPtr = nativeStackPtr; resType = OpenGLInfo.TYPE.BUFFER; + appendParamsInfos(this); } - public void setRenderbufferInfo(int target, int width, int height, int internalFormat, int id, long eglContextId, long size, String javaStack, String nativeStack) { + public void setRenderbufferInfo(int target, int width, int height, int internalFormat, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { this.target = target; this.width = width; this.height = height; @@ -84,47 +203,10 @@ public void setRenderbufferInfo(int target, int width, int height, int internalF this.eglContextId = eglContextId; this.size = size; this.javaStack = javaStack; - this.nativeStack = nativeStack; + this.nativeStackPtr = nativeStackPtr; resType = OpenGLInfo.TYPE.RENDER_BUFFERS; + appendParamsInfos(this); } - @Override - public String toString() { - if (resType == OpenGLInfo.TYPE.TEXTURE) { - return "MemoryInfo{" + - "target=" + target + - ", level=" + level + - ", internalFormat=" + internalFormat + - ", width=" + width + - ", height=" + height + - ", depth=" + depth + - ", border=" + border + - ", format=" + format + - ", type=" + type + - ", size=" + size + - ", javaStack='" + javaStack + '\'' + - ", nativeStack='" + nativeStack + '\'' + - '}'; - } else if (resType == OpenGLInfo.TYPE.BUFFER) { - return "MemoryInfo{" + - "target=" + target + - ", usage=" + usage + - ", size=" + size + - ", javaStack='" + javaStack + '\'' + - ", nativeStack='" + nativeStack + '\'' + - '}'; - } else if (resType == OpenGLInfo.TYPE.RENDER_BUFFERS) { - return "MemoryInfo{" + - "target=" + target + - ", internalFormat=" + internalFormat + - ", width=" + width + - ", height=" + height + - ", size=" + size + - ", javaStack='" + javaStack + '\'' + - ", nativeStack='" + nativeStack + '\'' + - '}'; - } else { - return ""; - } - } + } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index c9b1c2aef..2583105ed 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -208,6 +208,7 @@ public String dumpToString() { if (oldInfo == null) { infoMap.put(infoHash, info); } else { + // resource part boolean isSameType = info.getType() == oldInfo.getType(); boolean isSameThread = info.getThreadId().equals(oldInfo.getThreadId()); boolean isSameEglContext = info.getEglContextNativeHandle() == oldInfo.getEglContextNativeHandle(); @@ -215,6 +216,8 @@ public String dumpToString() { if (isSameType && isSameThread && isSameEglContext && isSameActivity) { oldInfo.incAllocRecord(info.getId()); + MemoryInfo oldMemory = oldInfo.getMemoryInfo(); + oldMemory.appendParamsInfos(info.getMemoryInfo()); infoMap.put(infoHash, oldInfo); } } @@ -310,12 +313,20 @@ private String getResListString(List resList) { .append("\n") .append(String.format(" native stack = %s", res.getNativeStack())) .append("\n") - .append(String.format(" memory info = %s", res.getMemoryInfo() == null ? "" : res.getMemoryInfo().toString())) + .append(String.format(" memory info = %s", res.getMemoryInfo() == null ? "" : getMemoryInfoStr(res.getMemoryInfo()))) .append("\n\n\n"); } return result.toString(); } + private String getMemoryInfoStr(MemoryInfo memory) { + return memory.getParamsInfos() + + "\n" + + String.format(" memory java stack = %s", memory.getJavaStack()) + + "\n" + + String.format(" memory native stack = %s", memory.getNativeStack()); + } + public void getNativeStack(OpenGLInfo info) { synchronized (infoList) { for (OpenGLInfo item : infoList) { From 3aa1ec16ed5b9843c69f4af5abddbeb6b15a64cc Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 2 Dec 2021 15:05:17 +0800 Subject: [PATCH 067/163] add null safety --- .../matrix/openglleak/statistics/OpenGLResRecorder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 2583105ed..132a4d841 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -217,7 +217,9 @@ public String dumpToString() { if (isSameType && isSameThread && isSameEglContext && isSameActivity) { oldInfo.incAllocRecord(info.getId()); MemoryInfo oldMemory = oldInfo.getMemoryInfo(); - oldMemory.appendParamsInfos(info.getMemoryInfo()); + if (oldMemory != null) { + oldMemory.appendParamsInfos(info.getMemoryInfo()); + } infoMap.put(infoHash, oldInfo); } } From 29199dee542c2bede397d354a1cb25abe8e12a46 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 2 Dec 2021 15:28:59 +0800 Subject: [PATCH 068/163] add empty --- .../com/tencent/matrix/openglleak/statistics/MemoryInfo.java | 3 ++- .../matrix/openglleak/statistics/OpenGLResRecorder.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java index 857f55a27..813cf5dde 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java @@ -176,7 +176,8 @@ public void appendParamsInfos(MemoryInfo memoryInfo) { public String getParamsInfos() { StringBuilder result = new StringBuilder(); for (int i = 0; i < paramsList.size(); i++) { - result.append(paramsList.get(i)) + result.append(" ") + .append(paramsList.get(i)) .append("\n"); } return result.toString(); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 132a4d841..105bcce55 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -315,14 +315,14 @@ private String getResListString(List resList) { .append("\n") .append(String.format(" native stack = %s", res.getNativeStack())) .append("\n") - .append(String.format(" memory info = %s", res.getMemoryInfo() == null ? "" : getMemoryInfoStr(res.getMemoryInfo()))) + .append(res.getMemoryInfo() == null ? "" : getMemoryInfoStr(res.getMemoryInfo())) .append("\n\n\n"); } return result.toString(); } private String getMemoryInfoStr(MemoryInfo memory) { - return memory.getParamsInfos() + + return " " + memory.getParamsInfos() + "\n" + String.format(" memory java stack = %s", memory.getJavaStack()) + "\n" + From 2202a487969e5a94246cdfb2bb55bc58da89fbe8 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 2 Dec 2021 15:32:10 +0800 Subject: [PATCH 069/163] recovery empty --- .../tencent/matrix/openglleak/statistics/OpenGLResRecorder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index 105bcce55..e52b474cd 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -322,7 +322,7 @@ private String getResListString(List resList) { } private String getMemoryInfoStr(MemoryInfo memory) { - return " " + memory.getParamsInfos() + + return memory.getParamsInfos() + "\n" + String.format(" memory java stack = %s", memory.getJavaStack()) + "\n" + From 480389913d6341573bac35b777c17ba6c156e620 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 2 Dec 2021 16:10:59 +0800 Subject: [PATCH 070/163] change sort --- .../tencent/matrix/openglleak/statistics/OpenGLResRecorder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java index e52b474cd..d053d5bb9 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/OpenGLResRecorder.java @@ -248,7 +248,7 @@ public String dumpToString() { Comparator comparator = new Comparator() { @Override public int compare(OpenGLInfo o1, OpenGLInfo o2) { - return o1.getAllocCount() - o2.getAllocCount(); + return o2.getAllocCount() - o1.getAllocCount(); } }; From 34dc57c7f72ebd03faed41ef380dd1d34b9630a9 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 2 Dec 2021 21:04:41 +0800 Subject: [PATCH 071/163] add openGL Resource size getter --- ...encent_matrix_openglleak_hook_OpenGLHook.h | 24 ++ .../matrix/openglleak/hook/OpenGLHook.java | 310 +++++++++++++++--- .../openglleak/statistics/BindCenter.java | 13 +- .../matrix/openglleak/statistics/BindMap.java | 32 +- .../statistics/resource/OpenGLID.java | 45 +++ .../statistics/resource/OpenGLInfo.java | 60 ++-- .../statistics/resource/OpenGLReportInfo.java | 32 ++ .../statistics/resource/ResRecordManager.java | 181 +++++++++- .../openglleak/utils/AutoWrapBuilder.java | 53 +++ 9 files changed, 651 insertions(+), 99 deletions(-) create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLID.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/AutoWrapBuilder.java 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 05f98976c..882001273 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 @@ -113,6 +113,30 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlTexImage3D(JNIEnv *env, jclass clazz, jint index); +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindTexture(JNIEnv *env, jclass clazz, jint index); + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindBuffer(JNIEnv *env, jclass clazz, jint index); + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindFramebuffer(JNIEnv *env, jclass clazz, jint index); + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBindRenderbuffer(JNIEnv *env, jclass clazz, jint index); + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlBufferData(JNIEnv *env, jclass clazz, jint index); + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_tencent_matrix_openglleak_hook_OpenGLHook_hookGlRenderbufferStorage(JNIEnv *env, jclass clazz, jint index); + #ifdef __cplusplus } #endif 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 a3d594e7f..9abf2cf42 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 @@ -3,9 +3,13 @@ import android.opengl.EGL14; import com.tencent.matrix.openglleak.comm.FuncNameString; +import com.tencent.matrix.openglleak.statistics.BindCenter; +import com.tencent.matrix.openglleak.statistics.MemoryInfo; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLID; import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; import com.tencent.matrix.openglleak.utils.ActivityRecorder; +import com.tencent.matrix.util.MatrixLog; import java.util.concurrent.atomic.AtomicInteger; @@ -18,7 +22,10 @@ public class OpenGLHook { private static final String TAG = "MicroMsg.OpenGLHook"; private static OpenGLHook mInstance = new OpenGLHook(); - private Listener mListener; + private ResourceListener mResourceListener; + private ErrorListener mErrorListener; + private BindListener mBindListener; + private MemoryListener mMemoryListener; private OpenGLHook() { } @@ -27,29 +34,58 @@ public static OpenGLHook getInstance() { return mInstance; } - public void setListener(Listener l) { - mListener = l; + public void setResourceListener(ResourceListener listener) { + mResourceListener = listener; + } + + public void setErrorListener(ErrorListener listener) { + mErrorListener = listener; + } + + public void setBindListener(BindListener listener) { + mBindListener = listener; + } + + public void setMemoryListener(MemoryListener listener) { + mMemoryListener = listener; } public boolean hook(String targetFuncName, int index) { - if (targetFuncName.equals(FuncNameString.GL_GET_ERROR)) { - return hookGlGetError(index); - } else if (targetFuncName.equals(FuncNameString.GL_GEN_TEXTURES)) { - return hookGlGenTextures(index); - } else if (targetFuncName.equals(FuncNameString.GL_DELETE_TEXTURES)) { - return hookGlDeleteTextures(index); - } else if (targetFuncName.equals(FuncNameString.GL_GEN_BUFFERS)) { - return hookGlGenBuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_DELETE_BUFFERS)) { - return hookGlDeleteBuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_GEN_FRAMEBUFFERS)) { - return hookGlGenFramebuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_DELETE_FRAMEBUFFERS)) { - return hookGlDeleteFramebuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_GEN_RENDERBUFFERS)) { - return hookGlGenRenderbuffers(index); - } else if (targetFuncName.equals(FuncNameString.GL_DELETE_RENDERBUFFERS)) { - return hookGlDeleteRenderbuffers(index); + switch (targetFuncName) { + case FuncNameString.GL_GET_ERROR: + return hookGlGetError(index); + case FuncNameString.GL_GEN_TEXTURES: + return hookGlGenTextures(index); + case FuncNameString.GL_DELETE_TEXTURES: + return hookGlDeleteTextures(index); + case FuncNameString.GL_GEN_BUFFERS: + return hookGlGenBuffers(index); + case FuncNameString.GL_DELETE_BUFFERS: + return hookGlDeleteBuffers(index); + case FuncNameString.GL_GEN_FRAMEBUFFERS: + return hookGlGenFramebuffers(index); + case FuncNameString.GL_DELETE_FRAMEBUFFERS: + return hookGlDeleteFramebuffers(index); + case FuncNameString.GL_GEN_RENDERBUFFERS: + return hookGlGenRenderbuffers(index); + case FuncNameString.GL_DELETE_RENDERBUFFERS: + return hookGlDeleteRenderbuffers(index); + case FuncNameString.GL_TEX_IMAGE_2D: + return hookGlTexImage2D(index); + case FuncNameString.GL_TEX_IMAGE_3D: + return hookGlTexImage3D(index); + case FuncNameString.GL_BIND_TEXTURE: + return hookGlBindTexture(index); + case FuncNameString.GL_BIND_BUFFER: + return hookGlBindBuffer(index); + case FuncNameString.GL_BIND_FRAMEBUFFER: + return hookGlBindFramebuffer(index); + case FuncNameString.GL_BIND_RENDERBUFFER: + return hookGlBindRenderbuffer(index); + case FuncNameString.GL_BUFFER_DATA: + return hookGlBufferData(index); + case FuncNameString.GL_RENDER_BUFFER_STORAGE: + return hookGlRenderbufferStorage(index); } return false; @@ -79,6 +115,22 @@ public boolean hook(String targetFuncName, int index) { private static native boolean hookGlGetError(int index); + private static native boolean hookGlTexImage2D(int index); + + private static native boolean hookGlTexImage3D(int index); + + private static native boolean hookGlBindTexture(int index); + + private static native boolean hookGlBindBuffer(int index); + + private static native boolean hookGlBindFramebuffer(int index); + + private static native boolean hookGlBindRenderbuffer(int index); + + private static native boolean hookGlBufferData(int index); + + private static native boolean hookGlRenderbufferStorage(int index); + public static void onGlGenTextures(int[] ids, String threadId, String javaStack, long nativeStackPtr) { if (ids.length > 0) { AtomicInteger counter = new AtomicInteger(ids.length); @@ -92,8 +144,8 @@ public static void onGlGenTextures(int[] ids, String threadId, String javaStack, OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlGenTextures(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlGenTextures(openGLInfo); } } } @@ -111,8 +163,8 @@ public static void onGlDeleteTextures(int[] ids, String threadId) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, false); ResRecordManager.getInstance().delete(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlDeleteTextures(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlDeleteTextures(openGLInfo); } } } @@ -131,8 +183,8 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlGenBuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlGenBuffers(openGLInfo); } } } @@ -150,8 +202,8 @@ public static void onGlDeleteBuffers(int[] ids, String threadId) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, false); ResRecordManager.getInstance().delete(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlDeleteBuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlDeleteBuffers(openGLInfo); } } } @@ -170,8 +222,8 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlGenFramebuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlGenFramebuffers(openGLInfo); } } } @@ -189,8 +241,8 @@ public static void onGlDeleteFramebuffers(int[] ids, String threadId) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, false); ResRecordManager.getInstance().delete(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlDeleteFramebuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlDeleteFramebuffers(openGLInfo); } } } @@ -209,8 +261,8 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlGenRenderbuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlGenRenderbuffers(openGLInfo); } } } @@ -228,21 +280,197 @@ public static void onGlDeleteRenderbuffers(int[] ids, String threadId) { OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, false); ResRecordManager.getInstance().delete(openGLInfo); - if (getInstance().mListener != null) { - getInstance().mListener.onGlDeleteRenderbuffers(openGLInfo); + if (getInstance().mResourceListener != null) { + getInstance().mResourceListener.onGlDeleteRenderbuffers(openGLInfo); } } } } public static void onGetError(int eid) { - if (getInstance().mListener != null) { - getInstance().mListener.onGetError(new OpenGLInfo(eid)); + if (getInstance().mErrorListener != null) { + getInstance().mErrorListener.onGlError(eid); } } - public interface Listener { - void onGetError(OpenGLInfo info); + + public static void onGlBindTexture(int target, int id) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLID openGLID = new OpenGLID(eglContextId, id); + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.TEXTURE, target, openGLID); + + if (getInstance().mBindListener != null) { + getInstance().mBindListener.onGlBindTexture(target, eglContextId, id); + } + } + + public static void onGlBindBuffer(int target, int id) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLID openGLID = new OpenGLID(eglContextId, id); + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.BUFFER, target, openGLID); + + if (getInstance().mBindListener != null) { + getInstance().mBindListener.onGlBindBuffer(target, eglContextId, id); + } + } + + public static void onGlBindFramebuffer(int target, int id) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLID openGLID = new OpenGLID(eglContextId, id); + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.FRAME_BUFFERS, target, openGLID); + + if (getInstance().mBindListener != null) { + getInstance().mBindListener.onGlBindFramebuffer(target, eglContextId, id); + } + } + + public static void onGlBindRenderbuffer(int target, int id) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLID openGLID = new OpenGLID(eglContextId, id); + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.RENDER_BUFFERS, target, openGLID); + + if (getInstance().mBindListener != null) { + getInstance().mBindListener.onGlBindRenderbuffer(target, eglContextId, id); + } + } + + public static void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, long size, String javaStack, long nativeStack) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLID openGLID = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + if (openGLID == null) { + MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null"); + return; + } + OpenGLInfo openGLInfo = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.TEXTURE, openGLID.getEglContextNativeHandle(), openGLID.getId()); + if (openGLInfo != null) { + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, openGLID.getId(), openGLID.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); + } + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, openGLID.getId(), openGLID.getEglContextNativeHandle(), size); + } + + } + + public static void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, long size, String javaStack, long nativeStack) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLID openGLID = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + if (openGLID == null) { + MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null"); + return; + } + OpenGLInfo openGLInfo = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.TEXTURE, openGLID.getEglContextNativeHandle(), openGLID.getId()); + if (openGLInfo != null) { + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, openGLID.getId(), openGLID.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); + } + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, openGLID.getId(), openGLID.getEglContextNativeHandle(), size); + } + + } + + public static void onGlBufferData(int target, long size, int usage, String javaStack, long nativeStack) { + if (Thread.currentThread().getName().equals("RenderThread")) { + return; + } + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLID openGLID = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, eglContextId, target); + if (openGLID == null) { + MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null"); + return; + } + OpenGLInfo openGLInfo = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.BUFFER, openGLID.getEglContextNativeHandle(), openGLID.getId()); + if (openGLInfo != null) { + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setBufferInfo(target, usage, openGLID.getId(), openGLID.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); + } + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlBufferData(target, usage, openGLID.getId(), openGLID.getEglContextNativeHandle(), size); + } + + } + + public static void onGlRenderbufferStorage(int target, int internalformat, int width, int height, long size, String javaStack, long nativeStack) { + long eglContextId = 0L; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); + } + OpenGLID openGLID = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, target); + if (openGLID == null) { + MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null"); + return; + } + OpenGLInfo openGLInfo = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, openGLID.getEglContextNativeHandle(), openGLID.getId()); + if (openGLInfo != null) { + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setRenderbufferInfo(target, width, height, internalformat, openGLID.getId(), openGLID.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); + } + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, openGLID.getId(), openGLID.getEglContextNativeHandle(), size); + } + } + + public interface ErrorListener { + + void onGlError(int eid); + + } + + public interface BindListener { + + void onGlBindTexture(int target, long eglContextId, int id); + + void onGlBindBuffer(int target, long eglContextId, int id); + + void onGlBindRenderbuffer(int target, long eglContextId, int id); + + void onGlBindFramebuffer(int target, long eglContextId, int id); + + } + + public interface MemoryListener { + + void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, int id, long eglContextId, long size); + + void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size); + + void onGlBufferData(int target, int usage, int id, long eglContextId, long size); + + void onGlRenderbufferStorage(int target, int width, int height, int internalFormat, int id, long eglContextId, long size); + + } + + public interface ResourceListener { void onGlGenTextures(OpenGLInfo info); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java index d1047f88a..4e989ef3f 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java @@ -1,5 +1,8 @@ package com.tencent.matrix.openglleak.statistics; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLID; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; + public class BindCenter { private static final String TAG = "matrix.BindCenter"; @@ -13,11 +16,15 @@ public static BindCenter getInstance() { private BindCenter() { } - public void glBindResource(OpenGLInfo.TYPE type, int target, long eglContextId, OpenGLInfo info) { - BindMap.getInstance().putBindInfo(type, eglContextId, target, info); + public void glBindResource(OpenGLInfo.TYPE type, int target, long eglContextId, int id) { + BindMap.getInstance().putBindInfo(type, target, new OpenGLID(eglContextId, id)); + } + + public void glBindResource(OpenGLInfo.TYPE type, int target, OpenGLID openGLID) { + BindMap.getInstance().putBindInfo(type, target, openGLID); } - public OpenGLInfo getCurrentResourceIdByTarget(OpenGLInfo.TYPE type, long eglContextId, int target) { + public OpenGLID findCurrentResourceIdByTarget(OpenGLInfo.TYPE type, long eglContextId, int target) { return BindMap.getInstance().getBindInfo(type, eglContextId, target); } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java index 00d1be8e1..f9661ab5b 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java @@ -1,5 +1,7 @@ package com.tencent.matrix.openglleak.statistics; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLID; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.openglleak.utils.ExecuteCenter; import java.util.HashMap; @@ -27,13 +29,11 @@ public class BindMap { - private static final String TAG = "matrix.BindMap"; - private static final BindMap mInstance = new BindMap(); - private final Map> bindTextureMap; - private final Map> bindBufferMap; - private final Map> bindRenderbufferMap; + private final Map> bindTextureMap; + private final Map> bindBufferMap; + private final Map> bindRenderbufferMap; static BindMap getInstance() { return mInstance; @@ -45,9 +45,9 @@ private BindMap() { bindRenderbufferMap = new HashMap<>(); } - private OpenGLInfo getBindMapInfo(final Map> bindMap, long eglContextId, int target) { + private OpenGLID getBindMapInfo(final Map> bindMap, long eglContextId, int target) { synchronized (bindMap) { - Map subTextureMap = bindMap.get(eglContextId); + Map subTextureMap = bindMap.get(eglContextId); if (subTextureMap == null) { subTextureMap = new HashMap<>(); bindMap.put(eglContextId, subTextureMap); @@ -56,17 +56,17 @@ private OpenGLInfo getBindMapInfo(final Map> bind } } - private void putInBindMap(final Map> bindMap, final long eglContext, final int target, final OpenGLInfo info, OpenGLInfo.TYPE type) { + private void putInBindMap(final Map> bindMap, final int target, final OpenGLID openGLID, OpenGLInfo.TYPE type) { if (!isSupportTarget(type, target)) { return; } synchronized (bindMap) { - Map subTextureMap = bindMap.get(eglContext); + Map subTextureMap = bindMap.get(openGLID.getEglContextNativeHandle()); if (subTextureMap == null) { subTextureMap = new HashMap<>(); - bindMap.put(eglContext, subTextureMap); + bindMap.put(openGLID.getEglContextNativeHandle(), subTextureMap); } - subTextureMap.put(target, info); + subTextureMap.put(target, openGLID); } } @@ -100,7 +100,7 @@ private boolean isSupportTargetOfRenderbuffer(int target) { return target == GL_RENDERBUFFER; } - public OpenGLInfo getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int target) { + public OpenGLID getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int target) { switch (type) { case BUFFER: return getBindMapInfo(bindBufferMap, eglContextId, target); @@ -113,19 +113,19 @@ public OpenGLInfo getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int targe } - public void putBindInfo(final OpenGLInfo.TYPE type, final long eglContextId, final int target, final OpenGLInfo info) { + public void putBindInfo(final OpenGLInfo.TYPE type, final int target, final OpenGLID openGLID) { ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { switch (type) { case BUFFER: - putInBindMap(bindBufferMap, eglContextId, target, info, OpenGLInfo.TYPE.BUFFER); + putInBindMap(bindBufferMap, target, openGLID, OpenGLInfo.TYPE.BUFFER); break; case TEXTURE: - putInBindMap(bindTextureMap, eglContextId, target, info, OpenGLInfo.TYPE.TEXTURE); + putInBindMap(bindTextureMap, target, openGLID, OpenGLInfo.TYPE.TEXTURE); break; case RENDER_BUFFERS: - putInBindMap(bindRenderbufferMap, eglContextId, target, info, OpenGLInfo.TYPE.RENDER_BUFFERS); + putInBindMap(bindRenderbufferMap, target, openGLID, OpenGLInfo.TYPE.RENDER_BUFFERS); break; } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLID.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLID.java new file mode 100644 index 000000000..e3478ebb1 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLID.java @@ -0,0 +1,45 @@ +package com.tencent.matrix.openglleak.statistics.resource; + +import java.util.Objects; + +public class OpenGLID { + + private final int id; + + private final long eglContextNativeHandle; + + public OpenGLID(long eglContextNativeHandle, int id) { + this.id = id; + this.eglContextNativeHandle = eglContextNativeHandle; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OpenGLID openGLID = (OpenGLID) o; + return id == openGLID.id && eglContextNativeHandle == openGLID.eglContextNativeHandle; + } + + @Override + public int hashCode() { + return Objects.hash(id, eglContextNativeHandle); + } + + public int getId() { + return id; + } + + public long getEglContextNativeHandle() { + return eglContextNativeHandle; + } + + @Override + public String toString() { + return "OpenGLID{" + + "id=" + id + + ", eglContextNativeHandle=" + eglContextNativeHandle + + '}'; + } + +} 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 b08059ba3..1ca6eab02 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 @@ -1,5 +1,6 @@ package com.tencent.matrix.openglleak.statistics.resource; +import com.tencent.matrix.openglleak.statistics.MemoryInfo; import com.tencent.matrix.openglleak.utils.ActivityRecorder; import java.util.Objects; @@ -7,15 +8,13 @@ public class OpenGLInfo { - private int id; - private int error; private String threadId = ""; - private long eglContextNativeHandle; + private final OpenGLID openGLID; private String javaStack = ""; private String nativeStack = ""; private long nativeStackPtr = 0L; - private boolean genOrDelete; - private TYPE type; + private final TYPE type; + private MemoryInfo memoryInfo; private ActivityRecorder.ActivityInfo activityInfo; @@ -26,56 +25,54 @@ public enum TYPE { } public OpenGLInfo(OpenGLInfo clone) { - this.id = clone.id; - this.error = clone.error; this.threadId = clone.threadId; - this.eglContextNativeHandle = clone.eglContextNativeHandle; + this.openGLID = clone.openGLID; this.javaStack = clone.javaStack; this.nativeStack = clone.nativeStack; this.nativeStackPtr = clone.nativeStackPtr; - this.genOrDelete = clone.genOrDelete; this.type = clone.type; this.activityInfo = clone.activityInfo; } - public OpenGLInfo(int error) { - this.error = error; - } public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, boolean genOrDelete) { - this.id = id; this.threadId = threadId; - this.eglContextNativeHandle = eglContextNativeHandle; - this.genOrDelete = genOrDelete; + this.openGLID = new OpenGLID(eglContextNativeHandle, id); this.type = type; } public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, boolean genOrDelete, ActivityRecorder.ActivityInfo activityInfo, AtomicInteger counter) { - this.id = id; this.threadId = threadId; - this.eglContextNativeHandle = eglContextNativeHandle; this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; - this.genOrDelete = genOrDelete; this.type = type; this.activityInfo = activityInfo; this.counter = counter; + this.openGLID = new OpenGLID(eglContextNativeHandle, id); } - public int getId() { - return id; + public OpenGLID getOpenGLID() { + return openGLID; } - public int getError() { - return error; + public MemoryInfo getMemoryInfo() { + return memoryInfo; } - public String getThreadId() { - return threadId; + public long getEglContextNativeHandle() { + return openGLID.getEglContextNativeHandle(); } - public long getEglContextNativeHandle() { - return eglContextNativeHandle; + public void setMemoryInfo(MemoryInfo memoryInfo) { + this.memoryInfo = memoryInfo; + } + + public int getId() { + return openGLID.getId(); + } + + public String getThreadId() { + return threadId; } public TYPE getType() { @@ -105,13 +102,11 @@ public ActivityRecorder.ActivityInfo getActivityInfo() { @Override public String toString() { return "OpenGLInfo{" + - "id=" + id + + "id=" + openGLID.getId() + ", activityName=" + activityInfo + ", type='" + type.toString() + '\'' + - ", error=" + error + - ", isGen=" + genOrDelete + ", threadId='" + threadId + '\'' + - ", eglContextNativeHandle='" + eglContextNativeHandle + '\'' + + ", eglContextNativeHandle='" + openGLID.getEglContextNativeHandle() + '\'' + ", javaStack='" + javaStack + '\'' + ", nativeStack='" + getNativeStack() + '\'' + ", nativeStackPtr=" + nativeStackPtr + @@ -123,15 +118,14 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || !(o instanceof OpenGLInfo)) return false; OpenGLInfo that = (OpenGLInfo) o; - return id == that.id && - eglContextNativeHandle == that.eglContextNativeHandle && + return openGLID.equals(that.openGLID) && threadId.equals(that.threadId) && type == that.type; } @Override public int hashCode() { - return Objects.hash(id, threadId, eglContextNativeHandle, type); + return Objects.hash(openGLID.hashCode(), threadId, type); } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java new file mode 100644 index 000000000..f32b85387 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java @@ -0,0 +1,32 @@ +package com.tencent.matrix.openglleak.statistics.resource; + +import java.util.ArrayList; +import java.util.List; + +public class OpenGLReportInfo { + + public final OpenGLInfo innerInfo; + + private final List idList = new ArrayList<>(); + + private int allocCount; + + public OpenGLReportInfo(OpenGLInfo innerInfo) { + this.innerInfo = innerInfo; + idList.add(innerInfo.getId()); + } + + public void incAllocRecord(int id) { + this.allocCount++; + idList.add(id); + } + + public String getAllocIdList() { + return idList.toString(); + } + + public int getAllocCount() { + return allocCount; + } + +} 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 f46451a23..8a0a88b4e 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 @@ -1,21 +1,36 @@ package com.tencent.matrix.openglleak.statistics.resource; +import android.annotation.SuppressLint; import android.os.Handler; +import android.util.Log; +import com.tencent.matrix.openglleak.statistics.MemoryInfo; +import com.tencent.matrix.openglleak.utils.AutoWrapBuilder; import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; - +import com.tencent.matrix.util.MatrixLog; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; public class ResRecordManager { - private static ResRecordManager mInstance = new ResRecordManager(); + private static final ResRecordManager mInstance = new ResRecordManager(); - private Handler mH; + private final Handler mH; - private List mCallbackList = new LinkedList<>(); - private List mInfoList = new LinkedList<>(); + private final List mCallbackList = new LinkedList<>(); + private final List mInfoList = new LinkedList<>(); private ResRecordManager() { mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); @@ -88,6 +103,21 @@ public void run() { }); } + public OpenGLInfo findOpenGLInfo(OpenGLInfo.TYPE type, long eglContextId, int openGLInfoId) { + synchronized (mInfoList) { + for (OpenGLInfo item : mInfoList) { + if (item == null) { + break; + } + + if (type == item.getType() && item.getEglContextNativeHandle() == eglContextId && item.getId() == openGLInfoId) { + return item; + } + } + } + return null; + } + public String getNativeStack(OpenGLInfo item) { synchronized (mInfoList) { // 之前可能释放过 @@ -99,8 +129,11 @@ public String getNativeStack(OpenGLInfo item) { String ret = ""; OpenGLInfo info = mInfoList.get(index); + if (info == null) { + return ret; + } long nativeStackPtr = info.getNativeStackPtr(); - if ((null != info) && (nativeStackPtr != 0L)) { + if (nativeStackPtr != 0L) { ret = dumpNativeStack(nativeStackPtr); } @@ -147,6 +180,142 @@ public void clear() { } } + public void dumpGLToFile(String filePath) { + File targetFile = new File(filePath); + + if (targetFile.exists()) { + targetFile.delete(); + } + + try { + targetFile.createNewFile(); + } catch (IOException ignored) { + } + + try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile)))) { + writer.write(dumpGLToString()); + } catch (IOException ignored) { + } + } + + @SuppressLint("DefaultLocale") + private String getResListString(List resList) { + AutoWrapBuilder result = new AutoWrapBuilder(); + for (OpenGLReportInfo report : resList) { + result.append(String.format(" alloc count = %d", report.getAllocCount())) + .append(String.format(" id = %s", report.getAllocIdList())) + .append(String.format(" activity = %s", report.innerInfo.getActivityInfo().name)) + .append(String.format(" type = %s", report.innerInfo.getType())) + .append(String.format(" eglContext = %s", report.innerInfo.getEglContextNativeHandle())) + .append(String.format(" java stack = %s", report.innerInfo.getJavaStack())) + .append(String.format(" native stack = %s", report.innerInfo.getNativeStack())) + .append(report.innerInfo.getMemoryInfo() == null ? "" : getMemoryInfoStr(report.innerInfo.getMemoryInfo())) + .wrap(); + } + return result.toString(); + } + + private String getMemoryInfoStr(MemoryInfo memory) { + return memory.getParamsInfos() + + "\n" + + String.format(" memory java stack = %s", memory.getJavaStack()) + + "\n" + + String.format(" memory native stack = %s", memory.getNativeStack()); + } + + @SuppressLint("DefaultLocale") + public String dumpGLToString() { + Map infoMap = new HashMap<>(); + for (int i = 0; i < mInfoList.size(); i++) { + + OpenGLInfo info = mInfoList.get(i); + int javaHash = info.getJavaStack().hashCode(); + int nativeHash = info.getNativeStack().hashCode(); + + MemoryInfo memoryInfo = info.getMemoryInfo(); + int memoryJavaHash = memoryInfo == null ? 0 : memoryInfo.getJavaStack().hashCode(); + int memoryNativeHash = memoryInfo == null ? 0 : info.getNativeStack().hashCode(); + + long infoHash = javaHash + nativeHash + memoryNativeHash + memoryJavaHash; + + OpenGLReportInfo oldInfo = infoMap.get(infoHash); + if (oldInfo == null) { + OpenGLReportInfo openGLReportInfo = new OpenGLReportInfo(info); + infoMap.put(infoHash, openGLReportInfo); + } else { + // resource part + boolean isSameType = info.getType() == oldInfo.innerInfo.getType(); + boolean isSameThread = info.getThreadId().equals(oldInfo.innerInfo.getThreadId()); + boolean isSameEglContext = info.getEglContextNativeHandle() == oldInfo.innerInfo.getEglContextNativeHandle(); + boolean isSameActivity = info.getActivityInfo().equals(oldInfo.innerInfo.getActivityInfo()); + + if (isSameType && isSameThread && isSameEglContext && isSameActivity) { + oldInfo.incAllocRecord(info.getId()); + MemoryInfo oldMemoryInfo = oldInfo.innerInfo.getMemoryInfo(); + if (oldMemoryInfo != null) { + oldMemoryInfo.appendParamsInfos(info.getMemoryInfo()); + } + infoMap.put(infoHash, oldInfo); + } + } + } + + List textureList = new ArrayList<>(); + List bufferList = new ArrayList<>(); + List framebufferList = new ArrayList<>(); + List renderbufferList = new ArrayList<>(); + + for (OpenGLReportInfo reportInfo : infoMap.values()) { + if (reportInfo.innerInfo.getType() == OpenGLInfo.TYPE.TEXTURE) { + textureList.add(reportInfo); + } + if (reportInfo.innerInfo.getType() == OpenGLInfo.TYPE.BUFFER) { + bufferList.add(reportInfo); + } + if (reportInfo.innerInfo.getType() == OpenGLInfo.TYPE.FRAME_BUFFERS) { + framebufferList.add(reportInfo); + } + if (reportInfo.innerInfo.getType() == OpenGLInfo.TYPE.RENDER_BUFFERS) { + renderbufferList.add(reportInfo); + } + } + + Comparator comparator = new Comparator() { + @Override + public int compare(OpenGLReportInfo o1, OpenGLReportInfo o2) { + return o2.getAllocCount() - o1.getAllocCount(); + } + }; + + Collections.sort(textureList, comparator); + Collections.sort(bufferList, comparator); + Collections.sort(framebufferList, comparator); + Collections.sort(renderbufferList, comparator); + + AutoWrapBuilder builder = new AutoWrapBuilder(); + builder.appendDotted() + .appendWithSpace(String.format("textures Count = %d", textureList.size()), 3) + .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) + .appendDotted() + .appendWave() + .appendWithSpace("texture part :", 3) + .appendWave() + .append(getResListString(textureList)) + .appendWave() + .appendWithSpace("buffers part :", 3) + .appendWave() + .append(getResListString(bufferList)) + .appendWave() + .appendWithSpace("renderbuffer part :", 3) + .appendWave() + .append(getResListString(renderbufferList)) + .wrap(); + + return builder.toString(); + } + interface Callback { void gen(OpenGLInfo res); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/AutoWrapBuilder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/AutoWrapBuilder.java new file mode 100644 index 000000000..66608786d --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/AutoWrapBuilder.java @@ -0,0 +1,53 @@ +package com.tencent.matrix.openglleak.utils; + +public class AutoWrapBuilder { + + private final StringBuilder stringBuilder; + + private static final String dottedLine = "-------------------------------------------------------------------------"; + private static final String waveLine = "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"; + + public AutoWrapBuilder() { + stringBuilder = new StringBuilder(); + } + + public AutoWrapBuilder append(String content) { + stringBuilder.append(content) + .append("\n"); + return this; + } + + @Override + public String toString() { + return stringBuilder.toString(); + } + + public AutoWrapBuilder appendDotted() { + stringBuilder.append(dottedLine) + .append("\n"); + return this; + } + + public AutoWrapBuilder appendWave() { + stringBuilder.append(waveLine) + .append("\n"); + return this; + } + + public AutoWrapBuilder wrap() { + stringBuilder.append("\n"); + return this; + } + + public AutoWrapBuilder appendWithSpace(String content, int count) { + if (count > 0) { + for (int i = 0; i < count; i++) { + stringBuilder.append("\t"); + } + } + stringBuilder.append(content) + .append("\n"); + return this; + } + +} From eef63cbaeb05c69f8910334730f6fcdbb4aee2ba Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 2 Dec 2021 21:17:39 +0800 Subject: [PATCH 072/163] remove use import --- .../matrix/openglleak/statistics/resource/ResRecordManager.java | 2 -- 1 file changed, 2 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 8a0a88b4e..8fe82aca4 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 @@ -2,12 +2,10 @@ import android.annotation.SuppressLint; import android.os.Handler; -import android.util.Log; import com.tencent.matrix.openglleak.statistics.MemoryInfo; import com.tencent.matrix.openglleak.utils.AutoWrapBuilder; import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; -import com.tencent.matrix.util.MatrixLog; import java.io.BufferedWriter; import java.io.File; From ef2f0895a304fb743befe030d642ca9d4923b0d0 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 2 Dec 2021 21:23:37 +0800 Subject: [PATCH 073/163] fix compile wrong --- ...atrix_openglleak_statistics_resource_ResRecordManager.cpp | 2 +- ..._matrix_openglleak_statistics_resource_ResRecordManager.h | 2 +- .../com/tencent/matrix/openglleak/statistics/MemoryInfo.java | 5 ++++- .../openglleak/statistics/resource/ResRecordManager.java | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp index af383042f..e1e0d8b13 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp @@ -68,7 +68,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_ } extern "C" JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager_dumpNativeStack - (JNIEnv *env, jobject thiz, jlong jl) { + (JNIEnv *env, jclass thiz, jlong jl) { int64_t addr = jl; wechat_backtrace::Backtrace* ptr = (wechat_backtrace::Backtrace*)addr; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h index fbcd6dea2..55c6e09f1 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h @@ -17,7 +17,7 @@ JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_Re (JNIEnv *, jobject thiz, jlong); JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager_dumpNativeStack - (JNIEnv *, jobject thiz, jlong); + (JNIEnv *, jclass thiz, jlong); #ifdef __cplusplus } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java index 813cf5dde..3e4034427 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java @@ -1,5 +1,8 @@ package com.tencent.matrix.openglleak.statistics; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; +import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; + import java.util.ArrayList; import java.util.List; @@ -74,7 +77,7 @@ public String getJavaStack() { public String getNativeStack() { if (nativeStack.isEmpty() && nativeStackPtr != 0) { - nativeStack = OpenGLInfo.dumpNativeStack(nativeStackPtr); + nativeStack = ResRecordManager.dumpNativeStack(nativeStackPtr); } return nativeStack; } 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 8fe82aca4..10af408d9 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 @@ -139,7 +139,7 @@ public String getNativeStack(OpenGLInfo item) { } } - private native String dumpNativeStack(long nativeStackPtr); + public static native String dumpNativeStack(long nativeStackPtr); private native void releaseNative(long nativeStackPtr); From 50d3afba9660e32c26b6ea1834c43a184f167818 Mon Sep 17 00:00:00 2001 From: opdeng Date: Fri, 3 Dec 2021 15:14:26 +0800 Subject: [PATCH 074/163] add memory info --- .../com/tencent/matrix/openglleak/hook/OpenGLHook.java | 2 +- .../statistics/{ => resource}/MemoryInfo.java | 9 +++++---- .../openglleak/statistics/resource/OpenGLInfo.java | 1 - .../statistics/resource/ResRecordManager.java | 10 +++++++++- 4 files changed, 15 insertions(+), 7 deletions(-) rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/{ => resource}/MemoryInfo.java (96%) 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 9abf2cf42..7b5ee84ee 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 @@ -4,7 +4,7 @@ import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.BindCenter; -import com.tencent.matrix.openglleak.statistics.MemoryInfo; +import com.tencent.matrix.openglleak.statistics.resource.MemoryInfo; import com.tencent.matrix.openglleak.statistics.resource.OpenGLID; import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java similarity index 96% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 3e4034427..130cf4c2c 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -1,7 +1,4 @@ -package com.tencent.matrix.openglleak.statistics; - -import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; -import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; +package com.tencent.matrix.openglleak.statistics.resource; import java.util.ArrayList; import java.util.List; @@ -82,6 +79,10 @@ public String getNativeStack() { return nativeStack; } + public long getNativeStackPtr() { + return nativeStackPtr; + } + public int getTarget() { return target; } 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 1ca6eab02..d2f536b9b 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 @@ -1,6 +1,5 @@ package com.tencent.matrix.openglleak.statistics.resource; -import com.tencent.matrix.openglleak.statistics.MemoryInfo; import com.tencent.matrix.openglleak.utils.ActivityRecorder; import java.util.Objects; 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 10af408d9..a6ec25610 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 @@ -3,7 +3,6 @@ import android.annotation.SuppressLint; import android.os.Handler; -import com.tencent.matrix.openglleak.statistics.MemoryInfo; import com.tencent.matrix.openglleak.utils.AutoWrapBuilder; import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; @@ -85,6 +84,15 @@ public void run() { counter.set(counter.get() - 1); if (counter.get() == 0) { releaseNative(info.getNativeStackPtr()); + + // 释放 memory info + MemoryInfo memoryInfo = info.getMemoryInfo(); + if (null != memoryInfo) { + long memNativePtr = memoryInfo.getNativeStackPtr(); + if (memNativePtr != 0) { + releaseNative(memNativePtr); + } + } } mInfoList.remove(del); From 14dd3e34b089fd487a2a6865d35824c77348000d Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 3 Dec 2021 15:28:40 +0800 Subject: [PATCH 075/163] style memory info struct --- .../matrix/openglleak/hook/OpenGLHook.java | 2 +- .../statistics/{ => resource}/MemoryInfo.java | 63 +------------------ .../statistics/resource/OpenGLInfo.java | 1 - .../statistics/resource/OpenGLReportInfo.java | 55 ++++++++++++++++ .../statistics/resource/ResRecordManager.java | 18 +++--- 5 files changed, 65 insertions(+), 74 deletions(-) rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/{ => resource}/MemoryInfo.java (54%) 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 9abf2cf42..7b5ee84ee 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 @@ -4,7 +4,7 @@ import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.BindCenter; -import com.tencent.matrix.openglleak.statistics.MemoryInfo; +import com.tencent.matrix.openglleak.statistics.resource.MemoryInfo; import com.tencent.matrix.openglleak.statistics.resource.OpenGLID; import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java similarity index 54% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 3e4034427..1bfe11db3 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -1,10 +1,4 @@ -package com.tencent.matrix.openglleak.statistics; - -import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; -import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; - -import java.util.ArrayList; -import java.util.List; +package com.tencent.matrix.openglleak.statistics.resource; public class MemoryInfo { @@ -42,8 +36,6 @@ public class MemoryInfo { private OpenGLInfo.TYPE resType; - private final List paramsList = new ArrayList<>(); - public MemoryInfo() { } @@ -64,7 +56,6 @@ public void setTexturesInfo(int target, int level, int internalFormat, int width this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; resType = OpenGLInfo.TYPE.TEXTURE; - appendParamsInfos(this); } public OpenGLInfo.TYPE getResType() { @@ -134,57 +125,7 @@ public int getUsage() { return usage; } - public void appendParamsInfos(MemoryInfo memoryInfo) { - if (memoryInfo == null) { - return; - } - OpenGLInfo.TYPE resType = memoryInfo.getResType(); - if (resType == OpenGLInfo.TYPE.TEXTURE) { - paramsList.add("MemoryInfo{" + - "target=" + memoryInfo.getTarget() + - ", id=" + memoryInfo.getId() + - ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + - ", level=" + memoryInfo.getLevel() + - ", internalFormat=" + memoryInfo.getInternalFormat() + - ", width=" + memoryInfo.getWidth() + - ", height=" + memoryInfo.getHeight() + - ", depth=" + memoryInfo.getDepth() + - ", border=" + memoryInfo.getBorder() + - ", format=" + memoryInfo.getFormat() + - ", type=" + memoryInfo.getType() + - ", size=" + memoryInfo.getSize() + - '}'); - } else if (resType == OpenGLInfo.TYPE.BUFFER) { - paramsList.add("MemoryInfo{" + - "target=" + memoryInfo.getTarget() + - ", id=" + memoryInfo.getId() + - ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + - ", usage=" + memoryInfo.getUsage() + - ", size=" + memoryInfo.getSize() + - '}'); - } else if (resType == OpenGLInfo.TYPE.RENDER_BUFFERS) { - paramsList.add("MemoryInfo{" + - "target=" + memoryInfo.getTarget() + - ", id=" + memoryInfo.getId() + - ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + - ", internalFormat=" + memoryInfo.getInternalFormat() + - ", width=" + memoryInfo.getWidth() + - ", height=" + memoryInfo.getHeight() + - ", size=" + memoryInfo.getSize() + - '}'); - } - } - - public String getParamsInfos() { - StringBuilder result = new StringBuilder(); - for (int i = 0; i < paramsList.size(); i++) { - result.append(" ") - .append(paramsList.get(i)) - .append("\n"); - } - return result.toString(); - } public void setBufferInfo(int target, int usage, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { this.target = target; @@ -195,7 +136,6 @@ public void setBufferInfo(int target, int usage, int id, long eglContextId, long this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; resType = OpenGLInfo.TYPE.BUFFER; - appendParamsInfos(this); } public void setRenderbufferInfo(int target, int width, int height, int internalFormat, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { @@ -209,7 +149,6 @@ public void setRenderbufferInfo(int target, int width, int height, int internalF this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; resType = OpenGLInfo.TYPE.RENDER_BUFFERS; - appendParamsInfos(this); } 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 1ca6eab02..d2f536b9b 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 @@ -1,6 +1,5 @@ package com.tencent.matrix.openglleak.statistics.resource; -import com.tencent.matrix.openglleak.statistics.MemoryInfo; import com.tencent.matrix.openglleak.utils.ActivityRecorder; import java.util.Objects; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java index f32b85387..c17e58b69 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java @@ -9,11 +9,66 @@ public class OpenGLReportInfo { private final List idList = new ArrayList<>(); + private final List paramsList = new ArrayList<>(); + private int allocCount; public OpenGLReportInfo(OpenGLInfo innerInfo) { this.innerInfo = innerInfo; idList.add(innerInfo.getId()); + appendParamsInfos(innerInfo.getMemoryInfo()); + } + + public void appendParamsInfos(MemoryInfo memoryInfo) { + if (memoryInfo == null) { + return; + } + OpenGLInfo.TYPE resType = memoryInfo.getResType(); + if (resType == OpenGLInfo.TYPE.TEXTURE) { + paramsList.add("MemoryInfo{" + + "target=" + memoryInfo.getTarget() + + ", id=" + memoryInfo.getId() + + ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + + ", level=" + memoryInfo.getLevel() + + ", internalFormat=" + memoryInfo.getInternalFormat() + + ", width=" + memoryInfo.getWidth() + + ", height=" + memoryInfo.getHeight() + + ", depth=" + memoryInfo.getDepth() + + ", border=" + memoryInfo.getBorder() + + ", format=" + memoryInfo.getFormat() + + ", type=" + memoryInfo.getType() + + ", size=" + memoryInfo.getSize() + + '}'); + } else if (resType == OpenGLInfo.TYPE.BUFFER) { + paramsList.add("MemoryInfo{" + + "target=" + memoryInfo.getTarget() + + ", id=" + memoryInfo.getId() + + ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + + ", usage=" + memoryInfo.getUsage() + + ", size=" + memoryInfo.getSize() + + '}'); + } else if (resType == OpenGLInfo.TYPE.RENDER_BUFFERS) { + paramsList.add("MemoryInfo{" + + "target=" + memoryInfo.getTarget() + + ", id=" + memoryInfo.getId() + + ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + + ", internalFormat=" + memoryInfo.getInternalFormat() + + ", width=" + memoryInfo.getWidth() + + ", height=" + memoryInfo.getHeight() + + ", size=" + memoryInfo.getSize() + + '}'); + } + + } + + public String getParamsInfos() { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < paramsList.size(); i++) { + result.append(" ") + .append(paramsList.get(i)) + .append("\n"); + } + return result.toString(); } public void incAllocRecord(int id) { 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 10af408d9..276099c60 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 @@ -3,7 +3,6 @@ import android.annotation.SuppressLint; import android.os.Handler; -import com.tencent.matrix.openglleak.statistics.MemoryInfo; import com.tencent.matrix.openglleak.utils.AutoWrapBuilder; import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; @@ -207,18 +206,18 @@ private String getResListString(List resList) { .append(String.format(" eglContext = %s", report.innerInfo.getEglContextNativeHandle())) .append(String.format(" java stack = %s", report.innerInfo.getJavaStack())) .append(String.format(" native stack = %s", report.innerInfo.getNativeStack())) - .append(report.innerInfo.getMemoryInfo() == null ? "" : getMemoryInfoStr(report.innerInfo.getMemoryInfo())) + .append(report.innerInfo.getMemoryInfo() == null ? "" : getMemoryInfoStr(report)) .wrap(); } return result.toString(); } - private String getMemoryInfoStr(MemoryInfo memory) { - return memory.getParamsInfos() + + private String getMemoryInfoStr(OpenGLReportInfo reportInfo) { + return reportInfo.getParamsInfos() + "\n" + - String.format(" memory java stack = %s", memory.getJavaStack()) + + String.format(" memory java stack = %s", reportInfo.innerInfo.getMemoryInfo().getJavaStack()) + "\n" + - String.format(" memory native stack = %s", memory.getNativeStack()); + String.format(" memory native stack = %s", reportInfo.innerInfo.getMemoryInfo().getNativeStack()); } @SuppressLint("DefaultLocale") @@ -232,7 +231,7 @@ public String dumpGLToString() { MemoryInfo memoryInfo = info.getMemoryInfo(); int memoryJavaHash = memoryInfo == null ? 0 : memoryInfo.getJavaStack().hashCode(); - int memoryNativeHash = memoryInfo == null ? 0 : info.getNativeStack().hashCode(); + int memoryNativeHash = memoryInfo == null ? 0 : memoryInfo.getNativeStack().hashCode(); long infoHash = javaHash + nativeHash + memoryNativeHash + memoryJavaHash; @@ -249,9 +248,8 @@ public String dumpGLToString() { if (isSameType && isSameThread && isSameEglContext && isSameActivity) { oldInfo.incAllocRecord(info.getId()); - MemoryInfo oldMemoryInfo = oldInfo.innerInfo.getMemoryInfo(); - if (oldMemoryInfo != null) { - oldMemoryInfo.appendParamsInfos(info.getMemoryInfo()); + if (oldInfo.innerInfo.getMemoryInfo() != null) { + oldInfo.appendParamsInfos(info.getMemoryInfo()); } infoMap.put(infoHash, oldInfo); } From 49387267a0ee4cb14bab488d83c69c0eabcf5e15 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 3 Dec 2021 16:23:24 +0800 Subject: [PATCH 076/163] remove openGLID & change bind map storage --- .../matrix/openglleak/hook/OpenGLHook.java | 111 +++++++++--------- .../openglleak/statistics/BindCenter.java | 10 +- .../matrix/openglleak/statistics/BindMap.java | 31 +++-- .../statistics/resource/OpenGLID.java | 45 ------- .../statistics/resource/OpenGLInfo.java | 33 +++--- 5 files changed, 93 insertions(+), 137 deletions(-) delete mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLID.java 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 7b5ee84ee..617620ce8 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 @@ -5,7 +5,6 @@ import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.BindCenter; import com.tencent.matrix.openglleak.statistics.resource.MemoryInfo; -import com.tencent.matrix.openglleak.statistics.resource.OpenGLID; import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; import com.tencent.matrix.openglleak.utils.ActivityRecorder; @@ -141,7 +140,7 @@ public static void onGlGenTextures(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mResourceListener != null) { @@ -160,7 +159,7 @@ public static void onGlDeleteTextures(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, false); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId); ResRecordManager.getInstance().delete(openGLInfo); if (getInstance().mResourceListener != null) { @@ -180,7 +179,7 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mResourceListener != null) { @@ -199,7 +198,7 @@ public static void onGlDeleteBuffers(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, false); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId); ResRecordManager.getInstance().delete(openGLInfo); if (getInstance().mResourceListener != null) { @@ -219,7 +218,7 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mResourceListener != null) { @@ -238,7 +237,7 @@ public static void onGlDeleteFramebuffers(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, false); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId); ResRecordManager.getInstance().delete(openGLInfo); if (getInstance().mResourceListener != null) { @@ -258,7 +257,7 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, true, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ResRecordManager.getInstance().gen(openGLInfo); if (getInstance().mResourceListener != null) { @@ -277,7 +276,7 @@ public static void onGlDeleteRenderbuffers(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, false); + OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId); ResRecordManager.getInstance().delete(openGLInfo); if (getInstance().mResourceListener != null) { @@ -299,8 +298,12 @@ public static void onGlBindTexture(int target, int id) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLID openGLID = new OpenGLID(eglContextId, id); - BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.TEXTURE, target, openGLID); + + OpenGLInfo info = null; + if (id != 0) { + info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.TEXTURE, eglContextId, id); + } + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.TEXTURE, target, eglContextId, info); if (getInstance().mBindListener != null) { getInstance().mBindListener.onGlBindTexture(target, eglContextId, id); @@ -312,8 +315,12 @@ public static void onGlBindBuffer(int target, int id) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLID openGLID = new OpenGLID(eglContextId, id); - BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.BUFFER, target, openGLID); + + OpenGLInfo info = null; + if (id != 0) { + info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.BUFFER, eglContextId, id); + } + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.BUFFER, target, eglContextId, info); if (getInstance().mBindListener != null) { getInstance().mBindListener.onGlBindBuffer(target, eglContextId, id); @@ -325,8 +332,12 @@ public static void onGlBindFramebuffer(int target, int id) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLID openGLID = new OpenGLID(eglContextId, id); - BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.FRAME_BUFFERS, target, openGLID); + + OpenGLInfo info = null; + if (id != 0) { + info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, eglContextId, id); + } + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.FRAME_BUFFERS, target, eglContextId, info); if (getInstance().mBindListener != null) { getInstance().mBindListener.onGlBindFramebuffer(target, eglContextId, id); @@ -338,8 +349,12 @@ public static void onGlBindRenderbuffer(int target, int id) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLID openGLID = new OpenGLID(eglContextId, id); - BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.RENDER_BUFFERS, target, openGLID); + + OpenGLInfo info = null; + if (id != 0) { + info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, id); + } + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.RENDER_BUFFERS, target, eglContextId, info); if (getInstance().mBindListener != null) { getInstance().mBindListener.onGlBindRenderbuffer(target, eglContextId, id); @@ -351,20 +366,17 @@ public static void onGlTexImage2D(int target, int level, int internalFormat, int if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLID openGLID = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); - if (openGLID == null) { - MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null"); + OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe undo glBindTextures()"); return; } - OpenGLInfo openGLInfo = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.TEXTURE, openGLID.getEglContextNativeHandle(), openGLID.getId()); - if (openGLInfo != null) { - MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, openGLID.getId(), openGLID.getEglContextNativeHandle(), size, javaStack, nativeStack); - openGLInfo.setMemoryInfo(memoryInfo); - } + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, openGLID.getId(), openGLID.getEglContextNativeHandle(), size); + getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); } } @@ -374,20 +386,17 @@ public static void onGlTexImage3D(int target, int level, int internalFormat, int if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLID openGLID = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); - if (openGLID == null) { - MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null"); + OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe undo glBindTextures()"); return; } - OpenGLInfo openGLInfo = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.TEXTURE, openGLID.getEglContextNativeHandle(), openGLID.getId()); - if (openGLInfo != null) { - MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, openGLID.getId(), openGLID.getEglContextNativeHandle(), size, javaStack, nativeStack); - openGLInfo.setMemoryInfo(memoryInfo); - } + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, openGLID.getId(), openGLID.getEglContextNativeHandle(), size); + getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); } } @@ -400,20 +409,17 @@ public static void onGlBufferData(int target, long size, int usage, String javaS if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLID openGLID = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, eglContextId, target); - if (openGLID == null) { - MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null"); + OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, eglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe undo glBindBuffer()"); return; } - OpenGLInfo openGLInfo = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.BUFFER, openGLID.getEglContextNativeHandle(), openGLID.getId()); - if (openGLInfo != null) { - MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setBufferInfo(target, usage, openGLID.getId(), openGLID.getEglContextNativeHandle(), size, javaStack, nativeStack); - openGLInfo.setMemoryInfo(memoryInfo); - } + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setBufferInfo(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlBufferData(target, usage, openGLID.getId(), openGLID.getEglContextNativeHandle(), size); + getInstance().mMemoryListener.onGlBufferData(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); } } @@ -423,20 +429,19 @@ public static void onGlRenderbufferStorage(int target, int internalformat, int w if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLID openGLID = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, target); - if (openGLID == null) { - MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null"); + OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe undo glBindRenderbuffer()"); return; } - OpenGLInfo openGLInfo = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, openGLID.getEglContextNativeHandle(), openGLID.getId()); if (openGLInfo != null) { MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setRenderbufferInfo(target, width, height, internalformat, openGLID.getId(), openGLID.getEglContextNativeHandle(), size, javaStack, nativeStack); + memoryInfo.setRenderbufferInfo(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); } if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, openGLID.getId(), openGLID.getEglContextNativeHandle(), size); + getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java index 4e989ef3f..32de64701 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindCenter.java @@ -1,6 +1,5 @@ package com.tencent.matrix.openglleak.statistics; -import com.tencent.matrix.openglleak.statistics.resource.OpenGLID; import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; public class BindCenter { @@ -16,15 +15,12 @@ public static BindCenter getInstance() { private BindCenter() { } - public void glBindResource(OpenGLInfo.TYPE type, int target, long eglContextId, int id) { - BindMap.getInstance().putBindInfo(type, target, new OpenGLID(eglContextId, id)); + public void glBindResource(OpenGLInfo.TYPE type, int target, long eglContextId, OpenGLInfo info) { + BindMap.getInstance().putBindInfo(type, target, eglContextId, info); } - public void glBindResource(OpenGLInfo.TYPE type, int target, OpenGLID openGLID) { - BindMap.getInstance().putBindInfo(type, target, openGLID); - } - public OpenGLID findCurrentResourceIdByTarget(OpenGLInfo.TYPE type, long eglContextId, int target) { + public OpenGLInfo findCurrentResourceIdByTarget(OpenGLInfo.TYPE type, long eglContextId, int target) { return BindMap.getInstance().getBindInfo(type, eglContextId, target); } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java index f9661ab5b..95c48a555 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java @@ -1,6 +1,5 @@ package com.tencent.matrix.openglleak.statistics; -import com.tencent.matrix.openglleak.statistics.resource.OpenGLID; import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.openglleak.utils.ExecuteCenter; @@ -31,9 +30,9 @@ public class BindMap { private static final BindMap mInstance = new BindMap(); - private final Map> bindTextureMap; - private final Map> bindBufferMap; - private final Map> bindRenderbufferMap; + private final Map> bindTextureMap; + private final Map> bindBufferMap; + private final Map> bindRenderbufferMap; static BindMap getInstance() { return mInstance; @@ -45,28 +44,28 @@ private BindMap() { bindRenderbufferMap = new HashMap<>(); } - private OpenGLID getBindMapInfo(final Map> bindMap, long eglContextId, int target) { + private OpenGLInfo getBindMapInfo(final Map> bindMap, long eglContextNativeHandle, int target) { synchronized (bindMap) { - Map subTextureMap = bindMap.get(eglContextId); + Map subTextureMap = bindMap.get(eglContextNativeHandle); if (subTextureMap == null) { subTextureMap = new HashMap<>(); - bindMap.put(eglContextId, subTextureMap); + bindMap.put(eglContextNativeHandle, subTextureMap); } return subTextureMap.get(target); } } - private void putInBindMap(final Map> bindMap, final int target, final OpenGLID openGLID, OpenGLInfo.TYPE type) { + private void putInBindMap(final Map> bindMap, final int target, final long eglContextNativeHandle, final OpenGLInfo openGLInfo, OpenGLInfo.TYPE type) { if (!isSupportTarget(type, target)) { return; } synchronized (bindMap) { - Map subTextureMap = bindMap.get(openGLID.getEglContextNativeHandle()); + Map subTextureMap = bindMap.get(eglContextNativeHandle); if (subTextureMap == null) { subTextureMap = new HashMap<>(); - bindMap.put(openGLID.getEglContextNativeHandle(), subTextureMap); + bindMap.put(eglContextNativeHandle, subTextureMap); } - subTextureMap.put(target, openGLID); + subTextureMap.put(target, openGLInfo); } } @@ -100,7 +99,7 @@ private boolean isSupportTargetOfRenderbuffer(int target) { return target == GL_RENDERBUFFER; } - public OpenGLID getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int target) { + public OpenGLInfo getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int target) { switch (type) { case BUFFER: return getBindMapInfo(bindBufferMap, eglContextId, target); @@ -113,19 +112,19 @@ public OpenGLID getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int target) } - public void putBindInfo(final OpenGLInfo.TYPE type, final int target, final OpenGLID openGLID) { + public void putBindInfo(final OpenGLInfo.TYPE type, final int target, final long eglContextId, final OpenGLInfo info) { ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { switch (type) { case BUFFER: - putInBindMap(bindBufferMap, target, openGLID, OpenGLInfo.TYPE.BUFFER); + putInBindMap(bindBufferMap, target, eglContextId, info, OpenGLInfo.TYPE.BUFFER); break; case TEXTURE: - putInBindMap(bindTextureMap, target, openGLID, OpenGLInfo.TYPE.TEXTURE); + putInBindMap(bindTextureMap, target, eglContextId, info, OpenGLInfo.TYPE.TEXTURE); break; case RENDER_BUFFERS: - putInBindMap(bindRenderbufferMap, target, openGLID, OpenGLInfo.TYPE.RENDER_BUFFERS); + putInBindMap(bindRenderbufferMap, target, eglContextId, info, OpenGLInfo.TYPE.RENDER_BUFFERS); break; } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLID.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLID.java deleted file mode 100644 index e3478ebb1..000000000 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLID.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.tencent.matrix.openglleak.statistics.resource; - -import java.util.Objects; - -public class OpenGLID { - - private final int id; - - private final long eglContextNativeHandle; - - public OpenGLID(long eglContextNativeHandle, int id) { - this.id = id; - this.eglContextNativeHandle = eglContextNativeHandle; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - OpenGLID openGLID = (OpenGLID) o; - return id == openGLID.id && eglContextNativeHandle == openGLID.eglContextNativeHandle; - } - - @Override - public int hashCode() { - return Objects.hash(id, eglContextNativeHandle); - } - - public int getId() { - return id; - } - - public long getEglContextNativeHandle() { - return eglContextNativeHandle; - } - - @Override - public String toString() { - return "OpenGLID{" + - "id=" + id + - ", eglContextNativeHandle=" + eglContextNativeHandle + - '}'; - } - -} 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 d2f536b9b..5597ca5a3 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 @@ -8,7 +8,8 @@ public class OpenGLInfo { private String threadId = ""; - private final OpenGLID openGLID; + private final int id; + private final long eglContextNativeHandle; private String javaStack = ""; private String nativeStack = ""; private long nativeStackPtr = 0L; @@ -25,7 +26,8 @@ public enum TYPE { public OpenGLInfo(OpenGLInfo clone) { this.threadId = clone.threadId; - this.openGLID = clone.openGLID; + this.id = clone.id; + this.eglContextNativeHandle = clone.eglContextNativeHandle; this.javaStack = clone.javaStack; this.nativeStack = clone.nativeStack; this.nativeStackPtr = clone.nativeStackPtr; @@ -34,24 +36,22 @@ public OpenGLInfo(OpenGLInfo clone) { } - public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, boolean genOrDelete) { + public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle) { this.threadId = threadId; - this.openGLID = new OpenGLID(eglContextNativeHandle, id); + this.id = id; + this.eglContextNativeHandle = eglContextNativeHandle; this.type = type; } - public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, boolean genOrDelete, ActivityRecorder.ActivityInfo activityInfo, AtomicInteger counter) { + public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, ActivityRecorder.ActivityInfo activityInfo, AtomicInteger counter) { this.threadId = threadId; this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; this.type = type; this.activityInfo = activityInfo; this.counter = counter; - this.openGLID = new OpenGLID(eglContextNativeHandle, id); - } - - public OpenGLID getOpenGLID() { - return openGLID; + this.id = id; + this.eglContextNativeHandle = eglContextNativeHandle; } public MemoryInfo getMemoryInfo() { @@ -59,7 +59,7 @@ public MemoryInfo getMemoryInfo() { } public long getEglContextNativeHandle() { - return openGLID.getEglContextNativeHandle(); + return eglContextNativeHandle; } public void setMemoryInfo(MemoryInfo memoryInfo) { @@ -67,7 +67,7 @@ public void setMemoryInfo(MemoryInfo memoryInfo) { } public int getId() { - return openGLID.getId(); + return id; } public String getThreadId() { @@ -101,11 +101,11 @@ public ActivityRecorder.ActivityInfo getActivityInfo() { @Override public String toString() { return "OpenGLInfo{" + - "id=" + openGLID.getId() + + "id=" + id + ", activityName=" + activityInfo + ", type='" + type.toString() + '\'' + ", threadId='" + threadId + '\'' + - ", eglContextNativeHandle='" + openGLID.getEglContextNativeHandle() + '\'' + + ", eglContextNativeHandle='" + eglContextNativeHandle + '\'' + ", javaStack='" + javaStack + '\'' + ", nativeStack='" + getNativeStack() + '\'' + ", nativeStackPtr=" + nativeStackPtr + @@ -117,14 +117,15 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || !(o instanceof OpenGLInfo)) return false; OpenGLInfo that = (OpenGLInfo) o; - return openGLID.equals(that.openGLID) && + return id == that.id && + eglContextNativeHandle == that.eglContextNativeHandle && threadId.equals(that.threadId) && type == that.type; } @Override public int hashCode() { - return Objects.hash(openGLID.hashCode(), threadId, type); + return Objects.hash(id, eglContextNativeHandle, threadId, type); } } From 8a6126164e86e1246b1fef5bbe86f3ef349878a6 Mon Sep 17 00:00:00 2001 From: opdeng Date: Fri, 3 Dec 2021 17:12:18 +0800 Subject: [PATCH 077/163] =?UTF-8?q?memory=20info=20=E9=87=8A=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../openglleak/statistics/resource/ResRecordManager.java | 9 --------- 1 file changed, 9 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 39ec86eed..276099c60 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 @@ -84,15 +84,6 @@ public void run() { counter.set(counter.get() - 1); if (counter.get() == 0) { releaseNative(info.getNativeStackPtr()); - - // 释放 memory info - MemoryInfo memoryInfo = info.getMemoryInfo(); - if (null != memoryInfo) { - long memNativePtr = memoryInfo.getNativeStackPtr(); - if (memNativePtr != 0) { - releaseNative(memNativePtr); - } - } } mInfoList.remove(del); From 78695656f482f4bd902f82ce438215119a35e8eb Mon Sep 17 00:00:00 2001 From: aurorani Date: Fri, 3 Dec 2021 18:14:42 +0800 Subject: [PATCH 078/163] fix: Fix mute mode in manual dump processor. --- .../matrix/resource/processor/ManualDumpProcessor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 dcde6d372..ae1efb5a5 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 @@ -77,8 +77,12 @@ public boolean process(final DestroyedActivityInfo destroyedActivityInfo) { @Override public void onDumpComplete(@Nullable ManualDumpData data) { if (data != null) { - MatrixLog.i(TAG, "shown notification!!!3"); - publishResult(destroyedActivityInfo, data); + if (!isMuted) { + MatrixLog.i(TAG, "shown notification!!!3"); + publishResult(destroyedActivityInfo, data); + } else { + MatrixLog.i(TAG, "mute mode, notification will not be shown."); + } } } }); From 083ed81cb681611101f9979ca2022084d3e19334 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 3 Dec 2021 18:16:14 +0800 Subject: [PATCH 079/163] use ExecuteCenter --- .../matrix/openglleak/hook/OpenGLHook.java | 253 ++++++++++++------ .../statistics/resource/ResRecordManager.java | 104 ++++--- .../openglleak/utils/ExecuteCenter.java | 6 +- .../openglleak/utils/GlLeakHandlerThread.java | 2 +- 4 files changed, 221 insertions(+), 144 deletions(-) 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 617620ce8..f61308659 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,14 +2,17 @@ import android.opengl.EGL14; +import com.tencent.matrix.openglleak.R; import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.BindCenter; import com.tencent.matrix.openglleak.statistics.resource.MemoryInfo; import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.openglleak.statistics.resource.ResRecordManager; import com.tencent.matrix.openglleak.utils.ActivityRecorder; +import com.tencent.matrix.openglleak.utils.ExecuteCenter; import com.tencent.matrix.util.MatrixLog; +import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; public class OpenGLHook { @@ -130,18 +133,23 @@ public boolean hook(String targetFuncName, int index) { private static native boolean hookGlRenderbufferStorage(int index); - public static void onGlGenTextures(int[] ids, String threadId, String javaStack, long nativeStackPtr) { + public static void onGlGenTextures(int[] ids, final String threadId, final String javaStack, final long nativeStackPtr) { if (ids.length > 0) { - AtomicInteger counter = new AtomicInteger(ids.length); + final AtomicInteger counter = new AtomicInteger(ids.length); long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); - ResRecordManager.getInstance().gen(openGLInfo); + for (final int id : ids) { + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + ResRecordManager.getInstance().gen(openGLInfo); + } + }); if (getInstance().mResourceListener != null) { getInstance().mResourceListener.onGlGenTextures(openGLInfo); @@ -159,8 +167,13 @@ public static void onGlDeleteTextures(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId); - ResRecordManager.getInstance().delete(openGLInfo); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + ResRecordManager.getInstance().delete(openGLInfo); + } + }); if (getInstance().mResourceListener != null) { getInstance().mResourceListener.onGlDeleteTextures(openGLInfo); @@ -179,8 +192,13 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); - ResRecordManager.getInstance().gen(openGLInfo); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + ResRecordManager.getInstance().gen(openGLInfo); + } + }); if (getInstance().mResourceListener != null) { getInstance().mResourceListener.onGlGenBuffers(openGLInfo); @@ -198,8 +216,13 @@ public static void onGlDeleteBuffers(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId); - ResRecordManager.getInstance().delete(openGLInfo); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + ResRecordManager.getInstance().delete(openGLInfo); + } + }); if (getInstance().mResourceListener != null) { getInstance().mResourceListener.onGlDeleteBuffers(openGLInfo); @@ -218,8 +241,13 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); - ResRecordManager.getInstance().gen(openGLInfo); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + ResRecordManager.getInstance().gen(openGLInfo); + } + }); if (getInstance().mResourceListener != null) { getInstance().mResourceListener.onGlGenFramebuffers(openGLInfo); @@ -237,8 +265,13 @@ public static void onGlDeleteFramebuffers(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId); - ResRecordManager.getInstance().delete(openGLInfo); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + ResRecordManager.getInstance().delete(openGLInfo); + } + }); if (getInstance().mResourceListener != null) { getInstance().mResourceListener.onGlDeleteFramebuffers(openGLInfo); @@ -257,8 +290,13 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); - ResRecordManager.getInstance().gen(openGLInfo); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + ResRecordManager.getInstance().gen(openGLInfo); + } + }); if (getInstance().mResourceListener != null) { getInstance().mResourceListener.onGlGenRenderbuffers(openGLInfo); @@ -276,8 +314,13 @@ public static void onGlDeleteRenderbuffers(int[] ids, String threadId) { } for (int id : ids) { - OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId); - ResRecordManager.getInstance().delete(openGLInfo); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + ResRecordManager.getInstance().delete(openGLInfo); + } + }); if (getInstance().mResourceListener != null) { getInstance().mResourceListener.onGlDeleteRenderbuffers(openGLInfo); @@ -293,87 +336,119 @@ public static void onGetError(int eid) { } - public static void onGlBindTexture(int target, int id) { + public static void onGlBindTexture(final int target, final int id) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLInfo info = null; - if (id != 0) { - info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.TEXTURE, eglContextId, id); - } - BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.TEXTURE, target, eglContextId, info); + final long finalEglContextId = eglContextId; + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + OpenGLInfo info = null; + if (id != 0) { + info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.TEXTURE, finalEglContextId, id); + } + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.TEXTURE, target, finalEglContextId, info); + } + }); if (getInstance().mBindListener != null) { getInstance().mBindListener.onGlBindTexture(target, eglContextId, id); } } - public static void onGlBindBuffer(int target, int id) { + public static void onGlBindBuffer(final int target, final int id) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLInfo info = null; - if (id != 0) { - info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.BUFFER, eglContextId, id); - } - BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.BUFFER, target, eglContextId, info); + final long finalEglContextId = eglContextId; + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + OpenGLInfo info = null; + if (id != 0) { + info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.BUFFER, finalEglContextId, id); + } + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.BUFFER, target, finalEglContextId, info); + } + }); if (getInstance().mBindListener != null) { getInstance().mBindListener.onGlBindBuffer(target, eglContextId, id); } } - public static void onGlBindFramebuffer(int target, int id) { + public static void onGlBindFramebuffer(final int target, final int id) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLInfo info = null; - if (id != 0) { - info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, eglContextId, id); - } - BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.FRAME_BUFFERS, target, eglContextId, info); + final long finalEglContextId = eglContextId; + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + OpenGLInfo info = null; + if (id != 0) { + info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, finalEglContextId, id); + } + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.FRAME_BUFFERS, target, finalEglContextId, info); + } + }); if (getInstance().mBindListener != null) { getInstance().mBindListener.onGlBindFramebuffer(target, eglContextId, id); } } - public static void onGlBindRenderbuffer(int target, int id) { + public static void onGlBindRenderbuffer(final int target, final int id) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLInfo info = null; - if (id != 0) { - info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, id); - } - BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.RENDER_BUFFERS, target, eglContextId, info); + final long finalEglContextId = eglContextId; + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + OpenGLInfo info = null; + if (id != 0) { + info = ResRecordManager.getInstance().findOpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, finalEglContextId, id); + } + BindCenter.getInstance().glBindResource(OpenGLInfo.TYPE.RENDER_BUFFERS, target, finalEglContextId, info); + } + }); if (getInstance().mBindListener != null) { getInstance().mBindListener.onGlBindRenderbuffer(target, eglContextId, id); } } - public static void onGlTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, long size, String javaStack, long nativeStack) { + 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 String javaStack, final long nativeStack) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe undo glBindTextures()"); - return; - } - MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); - openGLInfo.setMemoryInfo(memoryInfo); + + final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe undo glBindTextures()"); + return; + } + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); + + } + }); if (getInstance().mMemoryListener != null) { getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); @@ -381,19 +456,25 @@ public static void onGlTexImage2D(int target, int level, int internalFormat, int } - public static void onGlTexImage3D(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, long size, String javaStack, long nativeStack) { + 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 String javaStack, final long nativeStack) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe undo glBindTextures()"); - return; - } - MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); - openGLInfo.setMemoryInfo(memoryInfo); + + final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe undo glBindTextures()"); + return; + } + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); + } + }); if (getInstance().mMemoryListener != null) { getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); @@ -401,7 +482,7 @@ public static void onGlTexImage3D(int target, int level, int internalFormat, int } - public static void onGlBufferData(int target, long size, int usage, String javaStack, long nativeStack) { + public static void onGlBufferData(final int target, final long size, final int usage, final String javaStack, final long nativeStack) { if (Thread.currentThread().getName().equals("RenderThread")) { return; } @@ -409,14 +490,20 @@ public static void onGlBufferData(int target, long size, int usage, String javaS if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, eglContextId, target); - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe undo glBindBuffer()"); - return; - } - MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setBufferInfo(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); - openGLInfo.setMemoryInfo(memoryInfo); + + final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, eglContextId, target); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe undo glBindBuffer()"); + return; + } + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setBufferInfo(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); + } + }); if (getInstance().mMemoryListener != null) { getInstance().mMemoryListener.onGlBufferData(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); @@ -424,21 +511,25 @@ public static void onGlBufferData(int target, long size, int usage, String javaS } - public static void onGlRenderbufferStorage(int target, int internalformat, int width, int height, long size, String javaStack, long nativeStack) { + public static void onGlRenderbufferStorage(final int target, final int internalformat, final int width, final int height, final long size, final String javaStack, final long nativeStack) { long eglContextId = 0L; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, target); - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe undo glBindRenderbuffer()"); - return; - } - if (openGLInfo != null) { - MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setRenderbufferInfo(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); - openGLInfo.setMemoryInfo(memoryInfo); - } + + final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, target); + ExecuteCenter.getInstance().post(new Runnable() { + @Override + public void run() { + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe undo glBindRenderbuffer()"); + return; + } + MemoryInfo memoryInfo = new MemoryInfo(); + memoryInfo.setRenderbufferInfo(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); + openGLInfo.setMemoryInfo(memoryInfo); + } + }); if (getInstance().mMemoryListener != null) { getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); 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 39ec86eed..f0ed35648 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 @@ -1,10 +1,8 @@ package com.tencent.matrix.openglleak.statistics.resource; import android.annotation.SuppressLint; -import android.os.Handler; import com.tencent.matrix.openglleak.utils.AutoWrapBuilder; -import com.tencent.matrix.openglleak.utils.GlLeakHandlerThread; import java.io.BufferedWriter; import java.io.File; @@ -24,13 +22,11 @@ public class ResRecordManager { private static final ResRecordManager mInstance = new ResRecordManager(); - private final Handler mH; - private final List mCallbackList = new LinkedList<>(); private final List mInfoList = new LinkedList<>(); private ResRecordManager() { - mH = new Handler(GlLeakHandlerThread.getInstance().getLooper()); + } public static ResRecordManager getInstance() { @@ -38,75 +34,65 @@ public static ResRecordManager getInstance() { } public void gen(final OpenGLInfo gen) { - mH.post(new Runnable() { - @Override - public void run() { - if (gen == null) { - return; - } + if (gen == null) { + return; + } - synchronized (mInfoList) { - mInfoList.add(gen); - } + synchronized (mInfoList) { + mInfoList.add(gen); + } - synchronized (mCallbackList) { - for (Callback cb : mCallbackList) { - if (null != cb) { - cb.gen(gen); - } - } + synchronized (mCallbackList) { + for (Callback cb : mCallbackList) { + if (null != cb) { + cb.gen(gen); } } - }); + } } public void delete(final OpenGLInfo del) { - mH.post(new Runnable() { - @Override - public void run() { - if (del == null) { - return; - } + if (del == null) { + return; + } - synchronized (mInfoList) { - // 之前可能释放过 - int index = mInfoList.indexOf(del); - if (-1 == index) { - return; - } + synchronized (mInfoList) { + // 之前可能释放过 + int index = mInfoList.indexOf(del); + if (-1 == index) { + return; + } - OpenGLInfo info = mInfoList.get(index); - if (null == info) { - return; - } + OpenGLInfo info = mInfoList.get(index); + if (null == info) { + return; + } - AtomicInteger counter = info.getCounter(); - counter.set(counter.get() - 1); - if (counter.get() == 0) { - releaseNative(info.getNativeStackPtr()); - - // 释放 memory info - MemoryInfo memoryInfo = info.getMemoryInfo(); - if (null != memoryInfo) { - long memNativePtr = memoryInfo.getNativeStackPtr(); - if (memNativePtr != 0) { - releaseNative(memNativePtr); - } - } + AtomicInteger counter = info.getCounter(); + counter.set(counter.get() - 1); + if (counter.get() == 0) { + releaseNative(info.getNativeStackPtr()); + + // 释放 memory info + MemoryInfo memoryInfo = info.getMemoryInfo(); + if (null != memoryInfo) { + long memNativePtr = memoryInfo.getNativeStackPtr(); + if (memNativePtr != 0) { + releaseNative(memNativePtr); } - - mInfoList.remove(del); } + } - synchronized (mCallbackList) { - for (Callback cb : mCallbackList) { - if (null != cb) { - cb.delete(del); - } - } + mInfoList.remove(del); + } + + synchronized (mCallbackList) { + for (Callback cb : mCallbackList) { + if (null != cb) { + cb.delete(del); } } - }); + } } public OpenGLInfo findOpenGLInfo(OpenGLInfo.TYPE type, long eglContextId, int openGLInfoId) { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java index 10b9f2ae1..ec1930352 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java @@ -1,5 +1,7 @@ package com.tencent.matrix.openglleak.utils; +import android.opengl.GLES20; +import android.opengl.GLES30; import android.os.Handler; import android.os.HandlerThread; @@ -14,9 +16,7 @@ public static ExecuteCenter getInstance() { } private ExecuteCenter() { - HandlerThread mHandlerThread = new HandlerThread("matrix.GpuResLeakMonitor"); - mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()); + mHandler = new Handler(GlLeakHandlerThread.getInstance().getLooper()); } public void post(Runnable runnable) { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java index 707993f25..7bafd1f74 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/GlLeakHandlerThread.java @@ -4,7 +4,7 @@ public class GlLeakHandlerThread extends HandlerThread { - private static GlLeakHandlerThread mInstance = new GlLeakHandlerThread("GpuResLeakMonitor"); + private static final GlLeakHandlerThread mInstance = new GlLeakHandlerThread("GpuResLeakMonitor"); private GlLeakHandlerThread(String name) { super(name); From 4c8d9ff017f0d8c1090454f7781c44346e6af4e6 Mon Sep 17 00:00:00 2001 From: aurorani Date: Fri, 3 Dec 2021 18:21:58 +0800 Subject: [PATCH 080/163] refactor: Change confusing method name. --- .../matrix/resource/processor/ManualDumpProcessor.java | 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/ManualDumpProcessor.java b/matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/processor/ManualDumpProcessor.java index ae1efb5a5..3da36c114 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 @@ -79,7 +79,7 @@ public void onDumpComplete(@Nullable ManualDumpData data) { if (data != null) { if (!isMuted) { MatrixLog.i(TAG, "shown notification!!!3"); - publishResult(destroyedActivityInfo, data); + sendResultNotification(destroyedActivityInfo, data); } else { MatrixLog.i(TAG, "mute mode, notification will not be shown."); } @@ -90,7 +90,7 @@ public void onDumpComplete(@Nullable ManualDumpData data) { return true; } - private void publishResult(DestroyedActivityInfo activityInfo, ManualDumpData data) { + private void sendResultNotification(DestroyedActivityInfo activityInfo, ManualDumpData data) { final Context context = getWatcher().getContext(); Intent targetIntent = new Intent(); From ba437ce4c7896991d6ec64b31e44f71963f979bc Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 3 Dec 2021 19:38:20 +0800 Subject: [PATCH 081/163] fix memory info native stack ptr leak --- ...leak_statistics_resource_ResRecordManager.cpp | 2 +- ...glleak_statistics_resource_ResRecordManager.h | 2 +- .../statistics/CustomizeLeakMonitor.java | 2 +- .../statistics/resource/OpenGLInfo.java | 7 ++++++- .../statistics/resource/ResRecordManager.java | 16 ++++++++-------- .../statistics/resource/ResRecorder.java | 2 +- .../openglleak/utils/ActivityRecorder.java | 6 +++--- .../matrix/openglleak/utils/ExecuteCenter.java | 3 --- 8 files changed, 21 insertions(+), 19 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp index e1e0d8b13..0204ef7f7 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.cpp @@ -60,7 +60,7 @@ void get_native_stack(wechat_backtrace::Backtrace* backtrace, char *&stack) { extern "C" JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager_releaseNative - (JNIEnv *env, jobject thiz, jlong jl) { + (JNIEnv *env, jclass thiz, jlong jl) { int64_t addr = jl; wechat_backtrace::Backtrace* ptr = (wechat_backtrace::Backtrace*) addr; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h index 55c6e09f1..837a132af 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/cpp/com_tencent_matrix_openglleak_statistics_resource_ResRecordManager.h @@ -14,7 +14,7 @@ extern "C" { * Signature: ()Z */ JNIEXPORT void JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager_releaseNative - (JNIEnv *, jobject thiz, jlong); + (JNIEnv *, jclass thiz, jlong); JNIEXPORT jstring JNICALL Java_com_tencent_matrix_openglleak_statistics_resource_ResRecordManager_dumpNativeStack (JNIEnv *, jclass thiz, jlong); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java index 7c2e5b1da..7f0087d0a 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java @@ -7,7 +7,7 @@ public class CustomizeLeakMonitor { - private ResRecorder mResRecorder; + private final ResRecorder mResRecorder; public CustomizeLeakMonitor() { mResRecorder = new ResRecorder(); 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 5597ca5a3..edb0650cb 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 @@ -63,6 +63,11 @@ public long getEglContextNativeHandle() { } public void setMemoryInfo(MemoryInfo memoryInfo) { + if (this.memoryInfo != null) { + if (memoryInfo.getNativeStackPtr() != 0) { + ResRecordManager.releaseNative(memoryInfo.getNativeStackPtr()); + } + } this.memoryInfo = memoryInfo; } @@ -117,7 +122,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || !(o instanceof OpenGLInfo)) return false; OpenGLInfo that = (OpenGLInfo) o; - return id == that.id && + return id == that.id && eglContextNativeHandle == that.eglContextNativeHandle && threadId.equals(that.threadId) && type == that.type; 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 f0ed35648..aecbb3799 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 @@ -72,14 +72,14 @@ public void delete(final OpenGLInfo del) { counter.set(counter.get() - 1); if (counter.get() == 0) { releaseNative(info.getNativeStackPtr()); + } - // 释放 memory info - MemoryInfo memoryInfo = info.getMemoryInfo(); - if (null != memoryInfo) { - long memNativePtr = memoryInfo.getNativeStackPtr(); - if (memNativePtr != 0) { - releaseNative(memNativePtr); - } + // 释放 memory info + MemoryInfo memoryInfo = info.getMemoryInfo(); + if (null != memoryInfo) { + long memNativePtr = memoryInfo.getNativeStackPtr(); + if (memNativePtr != 0) { + releaseNative(memNativePtr); } } @@ -135,7 +135,7 @@ public String getNativeStack(OpenGLInfo item) { public static native String dumpNativeStack(long nativeStackPtr); - private native void releaseNative(long nativeStackPtr); + public static native void releaseNative(long nativeStackPtr); protected void registerCallback(Callback callback) { if (null == callback) { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java index 6d2957fc4..b43008e80 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java @@ -9,7 +9,7 @@ public class ResRecorder implements ResRecordManager.Callback { public ResRecorder() { } - private List mList = new LinkedList<>(); + private final List mList = new LinkedList<>(); public void start() { ResRecordManager.getInstance().registerCallback(this); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java index f4b4edbe9..748fe32b7 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java @@ -13,8 +13,8 @@ public class ActivityRecorder implements Application.ActivityLifecycleCallbacks { - private static ActivityRecorder mInstance = new ActivityRecorder(); - private List mList = new LinkedList<>(); + private static final ActivityRecorder mInstance = new ActivityRecorder(); + private final List mList = new LinkedList<>(); private ActivityRecorder() { } @@ -73,7 +73,7 @@ public void onActivityDestroyed(@NonNull Activity activity) { mList.remove(new ActivityInfo(activity.hashCode(), activity.getLocalClassName())); } - public class ActivityInfo { + public static class ActivityInfo { public int activityHashcode; public String name; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java index ec1930352..13aa03159 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ExecuteCenter.java @@ -1,9 +1,6 @@ package com.tencent.matrix.openglleak.utils; -import android.opengl.GLES20; -import android.opengl.GLES30; import android.os.Handler; -import android.os.HandlerThread; public class ExecuteCenter { From eba399f2987587c2508be0cf5611422061d23f53 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 14:50:29 +0800 Subject: [PATCH 082/163] fix glBind interface support target by api level --- .../matrix/openglleak/statistics/BindMap.java | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java index 95c48a555..5c7893cd6 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java @@ -22,17 +22,28 @@ import static android.opengl.GLES30.GL_TEXTURE_3D; import static android.opengl.GLES30.GL_TRANSFORM_FEEDBACK_BUFFER; import static android.opengl.GLES30.GL_UNIFORM_BUFFER; +import static android.opengl.GLES31.GL_ATOMIC_COUNTER_BUFFER; +import static android.opengl.GLES31.GL_DISPATCH_INDIRECT_BUFFER; +import static android.opengl.GLES31.GL_DRAW_INDIRECT_BUFFER; +import static android.opengl.GLES31.GL_SHADER_STORAGE_BUFFER; +import static android.opengl.GLES31.GL_TEXTURE_2D_MULTISAMPLE; +import static android.opengl.GLES32.GL_TEXTURE_2D_MULTISAMPLE_ARRAY; +import static android.opengl.GLES32.GL_TEXTURE_BUFFER; +import static android.opengl.GLES32.GL_TEXTURE_CUBE_MAP_ARRAY; import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP; import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; +import android.opengl.GLES20; + public class BindMap { private static final BindMap mInstance = new BindMap(); private final Map> bindTextureMap; private final Map> bindBufferMap; - private final Map> bindRenderbufferMap; + // glRenderbufferStorage target only support GL_RENDERBUFFER + private final Map bindRenderbufferMap; static BindMap getInstance() { return mInstance; @@ -56,9 +67,6 @@ private OpenGLInfo getBindMapInfo(final Map> bind } private void putInBindMap(final Map> bindMap, final int target, final long eglContextNativeHandle, final OpenGLInfo openGLInfo, OpenGLInfo.TYPE type) { - if (!isSupportTarget(type, target)) { - return; - } synchronized (bindMap) { Map subTextureMap = bindMap.get(eglContextNativeHandle); if (subTextureMap == null) { @@ -83,16 +91,34 @@ private boolean isSupportTarget(OpenGLInfo.TYPE type, int target) { } private boolean isSupportTargetOfTexture(int target) { - return target == GL_TEXTURE_2D || target == GL_TEXTURE_3D || target == GL_TEXTURE_CUBE_MAP_POSITIVE_X - || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X || target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y - || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z - || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_CUBE_MAP; + boolean targetOnUnder31 = target == GL_TEXTURE_2D || target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_CUBE_MAP; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + boolean targetOn31 = target == GL_TEXTURE_2D_MULTISAMPLE; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + boolean targetOn32 = target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || target == GL_TEXTURE_CUBE_MAP_ARRAY || target == GL_TEXTURE_BUFFER; + return targetOnUnder31 || targetOn32 || targetOn31; + } else { + return targetOnUnder31 || targetOn31; + } + } + return targetOnUnder31; } private boolean isSupportTargetOfBuffer(int target) { - return target == GL_ARRAY_BUFFER || target == GL_COPY_WRITE_BUFFER || target == GL_COPY_READ_BUFFER + boolean targetOnUnder31 = target == GL_ARRAY_BUFFER || target == GL_COPY_READ_BUFFER || target == GL_COPY_WRITE_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER || target == GL_PIXEL_PACK_BUFFER || target == GL_PIXEL_UNPACK_BUFFER || target == GL_TRANSFORM_FEEDBACK_BUFFER || target == GL_UNIFORM_BUFFER; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + boolean targetOn31 = target == GL_ATOMIC_COUNTER_BUFFER || target == GL_DISPATCH_INDIRECT_BUFFER || target == GL_DRAW_INDIRECT_BUFFER + || target == GL_SHADER_STORAGE_BUFFER; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + boolean targetOn32 = target == GL_TEXTURE_BUFFER; + return targetOnUnder31 || targetOn31 || targetOn32; + } else { + return targetOnUnder31 || targetOn31; + } + } + return targetOnUnder31; } private boolean isSupportTargetOfRenderbuffer(int target) { @@ -106,13 +132,16 @@ public OpenGLInfo getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int targe case TEXTURE: return getBindMapInfo(bindTextureMap, eglContextId, target); case RENDER_BUFFERS: - return getBindMapInfo(bindRenderbufferMap, eglContextId, target); + return bindRenderbufferMap.get(eglContextId); } return null; } public void putBindInfo(final OpenGLInfo.TYPE type, final int target, final long eglContextId, final OpenGLInfo info) { + if (!isSupportTarget(type, target)) { + return; + } ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { @@ -124,7 +153,7 @@ public void run() { putInBindMap(bindTextureMap, target, eglContextId, info, OpenGLInfo.TYPE.TEXTURE); break; case RENDER_BUFFERS: - putInBindMap(bindRenderbufferMap, target, eglContextId, info, OpenGLInfo.TYPE.RENDER_BUFFERS); + bindRenderbufferMap.put(eglContextId, info); break; } } From 02996b3d0e172534e8852a09dc35ecea0e756c5f Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 15:49:12 +0800 Subject: [PATCH 083/163] add special case of glBufferData --- .../matrix/openglleak/hook/OpenGLHook.java | 10 +++++++++- .../matrix/openglleak/statistics/BindMap.java | 18 +++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) 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 f61308659..703211247 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 @@ -1,5 +1,7 @@ package com.tencent.matrix.openglleak.hook; +import static android.opengl.GLES30.GL_PIXEL_UNPACK_BUFFER; + import android.opengl.EGL14; import com.tencent.matrix.openglleak.R; @@ -499,8 +501,14 @@ public void run() { MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe undo glBindBuffer()"); return; } + long actualSize = -1; + if (target == GL_PIXEL_UNPACK_BUFFER) { + actualSize = size * 2; + } else { + actualSize = size; + } MemoryInfo memoryInfo = new MemoryInfo(); - memoryInfo.setBufferInfo(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); + memoryInfo.setBufferInfo(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), actualSize, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); } }); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java index 5c7893cd6..8606832f8 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java @@ -1,19 +1,9 @@ package com.tencent.matrix.openglleak.statistics; -import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; -import com.tencent.matrix.openglleak.utils.ExecuteCenter; - -import java.util.HashMap; -import java.util.Map; - import static android.opengl.GLES20.GL_ARRAY_BUFFER; import static android.opengl.GLES20.GL_ELEMENT_ARRAY_BUFFER; import static android.opengl.GLES20.GL_RENDERBUFFER; import static android.opengl.GLES20.GL_TEXTURE_2D; -import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; -import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; -import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X; -import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; import static android.opengl.GLES30.GL_COPY_READ_BUFFER; import static android.opengl.GLES30.GL_COPY_WRITE_BUFFER; import static android.opengl.GLES30.GL_PIXEL_PACK_BUFFER; @@ -31,10 +21,12 @@ import static android.opengl.GLES32.GL_TEXTURE_BUFFER; import static android.opengl.GLES32.GL_TEXTURE_CUBE_MAP_ARRAY; import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP; -import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; -import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; -import android.opengl.GLES20; +import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; +import com.tencent.matrix.openglleak.utils.ExecuteCenter; + +import java.util.HashMap; +import java.util.Map; public class BindMap { From 5bb4201b85bee2b8a75a0c6015260eedfb189da8 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 21:01:18 +0800 Subject: [PATCH 084/163] fix cube map size judge error & fix dump logic --- .../matrix/openglleak/hook/OpenGLHook.java | 8 +- .../matrix/openglleak/statistics/BindMap.java | 29 +++--- .../statistics/resource/FaceInfo.java | 28 ++++++ .../statistics/resource/MemoryInfo.java | 93 +++++++++++++++++-- .../statistics/resource/OpenGLReportInfo.java | 24 ++--- 5 files changed, 141 insertions(+), 41 deletions(-) create mode 100644 matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/FaceInfo.java 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 703211247..958d3c413 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 @@ -445,7 +445,7 @@ public void run() { MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe undo glBindTextures()"); return; } - MemoryInfo memoryInfo = new MemoryInfo(); + MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); @@ -472,7 +472,7 @@ public void run() { MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe undo glBindTextures()"); return; } - MemoryInfo memoryInfo = new MemoryInfo(); + MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); } @@ -507,7 +507,7 @@ public void run() { } else { actualSize = size; } - MemoryInfo memoryInfo = new MemoryInfo(); + MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.BUFFER); memoryInfo.setBufferInfo(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), actualSize, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); } @@ -533,7 +533,7 @@ public void run() { MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe undo glBindRenderbuffer()"); return; } - MemoryInfo memoryInfo = new MemoryInfo(); + MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.RENDER_BUFFERS); memoryInfo.setRenderbufferInfo(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java index 8606832f8..4c2ae46fa 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java @@ -4,6 +4,11 @@ import static android.opengl.GLES20.GL_ELEMENT_ARRAY_BUFFER; import static android.opengl.GLES20.GL_RENDERBUFFER; import static android.opengl.GLES20.GL_TEXTURE_2D; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; import static android.opengl.GLES30.GL_COPY_READ_BUFFER; import static android.opengl.GLES30.GL_COPY_WRITE_BUFFER; import static android.opengl.GLES30.GL_PIXEL_PACK_BUFFER; @@ -21,6 +26,7 @@ import static android.opengl.GLES32.GL_TEXTURE_BUFFER; import static android.opengl.GLES32.GL_TEXTURE_CUBE_MAP_ARRAY; import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP; +import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; import com.tencent.matrix.openglleak.utils.ExecuteCenter; @@ -83,17 +89,7 @@ private boolean isSupportTarget(OpenGLInfo.TYPE type, int target) { } private boolean isSupportTargetOfTexture(int target) { - boolean targetOnUnder31 = target == GL_TEXTURE_2D || target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_CUBE_MAP; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - boolean targetOn31 = target == GL_TEXTURE_2D_MULTISAMPLE; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { - boolean targetOn32 = target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY || target == GL_TEXTURE_CUBE_MAP_ARRAY || target == GL_TEXTURE_BUFFER; - return targetOnUnder31 || targetOn32 || targetOn31; - } else { - return targetOnUnder31 || targetOn31; - } - } - return targetOnUnder31; + return target == GL_TEXTURE_2D || target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_CUBE_MAP; } private boolean isSupportTargetOfBuffer(int target) { @@ -122,13 +118,22 @@ public OpenGLInfo getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int targe case BUFFER: return getBindMapInfo(bindBufferMap, eglContextId, target); case TEXTURE: - return getBindMapInfo(bindTextureMap, eglContextId, target); + int actualTarget = target; + if(is2DCubeMapTarget(target)) { + actualTarget = GL_TEXTURE_CUBE_MAP; + } + return getBindMapInfo(bindTextureMap, eglContextId, actualTarget); case RENDER_BUFFERS: return bindRenderbufferMap.get(eglContextId); } return null; } + private boolean is2DCubeMapTarget(int target) { + return target == GL_TEXTURE_CUBE_MAP_POSITIVE_X || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X || + target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y ||target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || + target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + } public void putBindInfo(final OpenGLInfo.TYPE type, final int target, final long eglContextId, final OpenGLInfo info) { if (!isSupportTarget(type, target)) { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/FaceInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/FaceInfo.java new file mode 100644 index 000000000..206d43cd2 --- /dev/null +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/FaceInfo.java @@ -0,0 +1,28 @@ +package com.tencent.matrix.openglleak.statistics.resource; + +public class FaceInfo { + + private String params; + + private long size; + + public FaceInfo() { + + } + + public String getParams() { + return params; + } + + public void setParams(String params) { + this.params = params; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } +} diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 003f059b4..f93c5ef4d 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -1,5 +1,18 @@ package com.tencent.matrix.openglleak.statistics.resource; +import static android.opengl.GLES20.GL_TEXTURE_2D; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; +import static android.opengl.GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; +import static android.opengl.GLES30.GL_TEXTURE_2D_ARRAY; +import static android.opengl.GLES30.GL_TEXTURE_3D; + +import android.media.FaceDetector; + + public class MemoryInfo { private int target; @@ -22,8 +35,6 @@ public class MemoryInfo { private int id; - private long size; - private long eglContextId; private int usage; @@ -34,13 +45,50 @@ public class MemoryInfo { private long nativeStackPtr; - private OpenGLInfo.TYPE resType; + private final OpenGLInfo.TYPE resType; - public MemoryInfo() { + // use for buffer & renderbuffer + private long size; + + // only use for textures + private FaceInfo[] faces; + + public MemoryInfo(OpenGLInfo.TYPE type) { + this.resType = type; + if (resType == OpenGLInfo.TYPE.TEXTURE) { + final int cubeMapFaceCount = 6; + faces = new FaceInfo[cubeMapFaceCount]; + } + } + private int getFaceId(int target) { + switch (target) { + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + return 0; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + return 1; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + return 2; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + return 3; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + return 4; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return 5; + default: + return -1; + } } public void setTexturesInfo(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { + int faceId = getFaceId(target); + if (faceId == -1) { + return; + } + this.target = target; this.level = level; this.internalFormat = internalFormat; @@ -52,10 +100,29 @@ public void setTexturesInfo(int target, int level, int internalFormat, int width this.type = type; this.id = id; this.eglContextId = eglContextId; - this.size = size; this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; - resType = OpenGLInfo.TYPE.TEXTURE; + + FaceInfo faceInfo = faces[faceId]; + if (faceInfo == null) { + faceInfo = new FaceInfo(); + } + faceInfo.setSize(size); + faceInfo.setParams("MemoryInfo{" + + "target=" + this.getTarget() + + ", id=" + this.getId() + + ", eglContextNativeHandle='" + this.getEglContextId() + '\'' + + ", level=" + this.getLevel() + + ", internalFormat=" + this.getInternalFormat() + + ", width=" + this.getWidth() + + ", height=" + this.getHeight() + + ", depth=" + this.getDepth() + + ", border=" + this.getBorder() + + ", format=" + this.getFormat() + + ", type=" + this.getType() + + ", size=" + this.getSize() + + '}'); + faces[faceId] = faceInfo; } public OpenGLInfo.TYPE getResType() { @@ -117,7 +184,18 @@ public int getId() { return id; } + public FaceInfo[] getFaces() { + return faces; + } + public long getSize() { + if (this.resType == OpenGLInfo.TYPE.TEXTURE) { + for (FaceInfo faceInfo : faces) { + if (faceInfo != null) { + this.size += faceInfo.getSize(); + } + } + } return size; } @@ -130,7 +208,6 @@ public int getUsage() { } - public void setBufferInfo(int target, int usage, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { this.target = target; this.usage = usage; @@ -139,7 +216,6 @@ public void setBufferInfo(int target, int usage, int id, long eglContextId, long this.size = size; this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; - resType = OpenGLInfo.TYPE.BUFFER; } public void setRenderbufferInfo(int target, int width, int height, int internalFormat, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { @@ -152,7 +228,6 @@ public void setRenderbufferInfo(int target, int width, int height, int internalF this.size = size; this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; - resType = OpenGLInfo.TYPE.RENDER_BUFFERS; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java index c17e58b69..3d688859b 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java @@ -25,25 +25,17 @@ public void appendParamsInfos(MemoryInfo memoryInfo) { } OpenGLInfo.TYPE resType = memoryInfo.getResType(); if (resType == OpenGLInfo.TYPE.TEXTURE) { - paramsList.add("MemoryInfo{" + - "target=" + memoryInfo.getTarget() + - ", id=" + memoryInfo.getId() + - ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + - ", level=" + memoryInfo.getLevel() + - ", internalFormat=" + memoryInfo.getInternalFormat() + - ", width=" + memoryInfo.getWidth() + - ", height=" + memoryInfo.getHeight() + - ", depth=" + memoryInfo.getDepth() + - ", border=" + memoryInfo.getBorder() + - ", format=" + memoryInfo.getFormat() + - ", type=" + memoryInfo.getType() + - ", size=" + memoryInfo.getSize() + - '}'); + FaceInfo[] faces = memoryInfo.getFaces(); + for (FaceInfo faceInfo : faces) { + if (faceInfo != null) { + paramsList.add(faceInfo.getParams()); + } + } } else if (resType == OpenGLInfo.TYPE.BUFFER) { paramsList.add("MemoryInfo{" + "target=" + memoryInfo.getTarget() + ", id=" + memoryInfo.getId() + - ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + + ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + ", usage=" + memoryInfo.getUsage() + ", size=" + memoryInfo.getSize() + '}'); @@ -51,7 +43,7 @@ public void appendParamsInfos(MemoryInfo memoryInfo) { paramsList.add("MemoryInfo{" + "target=" + memoryInfo.getTarget() + ", id=" + memoryInfo.getId() + - ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + + ", eglContextNativeHandle='" + memoryInfo.getEglContextId() + '\'' + ", internalFormat=" + memoryInfo.getInternalFormat() + ", width=" + memoryInfo.getWidth() + ", height=" + memoryInfo.getHeight() + From dfde44204b3c09cc9a26b7f035810ee3fd5c0a48 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 21:05:00 +0800 Subject: [PATCH 085/163] remove unuse import & do style --- .../com/tencent/matrix/openglleak/hook/OpenGLHook.java | 2 -- .../com/tencent/matrix/openglleak/statistics/BindMap.java | 7 ++----- .../matrix/openglleak/statistics/resource/MemoryInfo.java | 3 --- 3 files changed, 2 insertions(+), 10 deletions(-) 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 958d3c413..12e2320d7 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 @@ -4,7 +4,6 @@ import android.opengl.EGL14; -import com.tencent.matrix.openglleak.R; import com.tencent.matrix.openglleak.comm.FuncNameString; import com.tencent.matrix.openglleak.statistics.BindCenter; import com.tencent.matrix.openglleak.statistics.resource.MemoryInfo; @@ -14,7 +13,6 @@ import com.tencent.matrix.openglleak.utils.ExecuteCenter; import com.tencent.matrix.util.MatrixLog; -import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; public class OpenGLHook { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java index 4c2ae46fa..8f869e404 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/BindMap.java @@ -21,10 +21,7 @@ import static android.opengl.GLES31.GL_DISPATCH_INDIRECT_BUFFER; import static android.opengl.GLES31.GL_DRAW_INDIRECT_BUFFER; import static android.opengl.GLES31.GL_SHADER_STORAGE_BUFFER; -import static android.opengl.GLES31.GL_TEXTURE_2D_MULTISAMPLE; -import static android.opengl.GLES32.GL_TEXTURE_2D_MULTISAMPLE_ARRAY; import static android.opengl.GLES32.GL_TEXTURE_BUFFER; -import static android.opengl.GLES32.GL_TEXTURE_CUBE_MAP_ARRAY; import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP; import static javax.microedition.khronos.opengles.GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; @@ -119,7 +116,7 @@ public OpenGLInfo getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int targe return getBindMapInfo(bindBufferMap, eglContextId, target); case TEXTURE: int actualTarget = target; - if(is2DCubeMapTarget(target)) { + if (is2DCubeMapTarget(target)) { actualTarget = GL_TEXTURE_CUBE_MAP; } return getBindMapInfo(bindTextureMap, eglContextId, actualTarget); @@ -131,7 +128,7 @@ public OpenGLInfo getBindInfo(OpenGLInfo.TYPE type, long eglContextId, int targe private boolean is2DCubeMapTarget(int target) { return target == GL_TEXTURE_CUBE_MAP_POSITIVE_X || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X || - target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y ||target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || + target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z || target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index f93c5ef4d..04998dc46 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -10,9 +10,6 @@ import static android.opengl.GLES30.GL_TEXTURE_2D_ARRAY; import static android.opengl.GLES30.GL_TEXTURE_3D; -import android.media.FaceDetector; - - public class MemoryInfo { private int target; From 50f19af5b0a0f232476452af376c085c2bd5124a Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 21:36:35 +0800 Subject: [PATCH 086/163] fix some bug --- .../matrix/openglleak/hook/OpenGLHook.java | 33 +++++++++---------- .../statistics/resource/MemoryInfo.java | 5 ++- .../statistics/resource/OpenGLReportInfo.java | 2 +- .../statistics/resource/ResRecorder.java | 4 +-- 4 files changed, 22 insertions(+), 22 deletions(-) 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 12e2320d7..6ed38c821 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 @@ -435,14 +435,13 @@ public static void onGlTexImage2D(final int target, final int level, final int i } final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe undo glBindTextures()"); + return; + } ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe undo glBindTextures()"); - return; - } MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); @@ -463,13 +462,13 @@ public static void onGlTexImage3D(final int target, final int level, final int i } final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe undo glBindTextures()"); + return; + } ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe undo glBindTextures()"); - return; - } MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); @@ -492,13 +491,13 @@ public static void onGlBufferData(final int target, final long size, final int u } final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, eglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe undo glBindBuffer()"); + return; + } ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe undo glBindBuffer()"); - return; - } long actualSize = -1; if (target == GL_PIXEL_UNPACK_BUFFER) { actualSize = size * 2; @@ -524,13 +523,13 @@ public static void onGlRenderbufferStorage(final int target, final int internalf } final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe undo glBindRenderbuffer()"); + return; + } ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe undo glBindRenderbuffer()"); - return; - } MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.RENDER_BUFFERS); memoryInfo.setRenderbufferInfo(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 04998dc46..2e2aa8f4a 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -10,6 +10,8 @@ import static android.opengl.GLES30.GL_TEXTURE_2D_ARRAY; import static android.opengl.GLES30.GL_TEXTURE_3D; +import com.tencent.matrix.util.MatrixLog; + public class MemoryInfo { private int target; @@ -83,6 +85,7 @@ private int getFaceId(int target) { public void setTexturesInfo(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { int faceId = getFaceId(target); if (faceId == -1) { + MatrixLog.e("MicroMsg.OpenGLHook", "setTexturesInfo faceId = -1, target = " + target); return; } @@ -117,7 +120,7 @@ public void setTexturesInfo(int target, int level, int internalFormat, int width ", border=" + this.getBorder() + ", format=" + this.getFormat() + ", type=" + this.getType() + - ", size=" + this.getSize() + + ", size=" + size + '}'); faces[faceId] = faceInfo; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java index 3d688859b..16b610fa4 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java @@ -11,7 +11,7 @@ public class OpenGLReportInfo { private final List paramsList = new ArrayList<>(); - private int allocCount; + private int allocCount = 1; public OpenGLReportInfo(OpenGLInfo innerInfo) { this.innerInfo = innerInfo; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java index b43008e80..498a3b455 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java @@ -52,9 +52,7 @@ public List getCopyList() { public void clear() { synchronized (mList) { - if (null != mList) { - mList.clear(); - } + mList.clear(); } } } From 2a10e8a80de4e2e9e79e21eb7a779b069e5e03e5 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 22:02:19 +0800 Subject: [PATCH 087/163] style code --- .../statistics/resource/MemoryInfo.java | 66 ++++--------------- .../statistics/resource/OpenGLReportInfo.java | 10 +++ .../statistics/resource/ResRecordManager.java | 10 ++- 3 files changed, 30 insertions(+), 56 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 2e2aa8f4a..4cea0d812 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -16,22 +16,12 @@ public class MemoryInfo { private int target; - private int level; - private int internalFormat; private int width; private int height; - private int depth; - - private int border; - - private int format; - - private int type; - private int id; private long eglContextId; @@ -89,37 +79,23 @@ public void setTexturesInfo(int target, int level, int internalFormat, int width return; } - this.target = target; - this.level = level; - this.internalFormat = internalFormat; - this.width = width; - this.height = height; - this.depth = depth; - this.border = border; - this.format = format; - this.type = type; - this.id = id; - this.eglContextId = eglContextId; - this.javaStack = javaStack; - this.nativeStackPtr = nativeStackPtr; - FaceInfo faceInfo = faces[faceId]; if (faceInfo == null) { faceInfo = new FaceInfo(); } faceInfo.setSize(size); faceInfo.setParams("MemoryInfo{" + - "target=" + this.getTarget() + - ", id=" + this.getId() + - ", eglContextNativeHandle='" + this.getEglContextId() + '\'' + - ", level=" + this.getLevel() + - ", internalFormat=" + this.getInternalFormat() + - ", width=" + this.getWidth() + - ", height=" + this.getHeight() + - ", depth=" + this.getDepth() + - ", border=" + this.getBorder() + - ", format=" + this.getFormat() + - ", type=" + this.getType() + + "target=" + target + + ", id=" + id + + ", eglContextNativeHandle='" + eglContextId + '\'' + + ", level=" + level + + ", internalFormat=" + internalFormat + + ", width=" + width + + ", height=" + height + + ", depth=" + depth + + ", border=" + border + + ", format=" + format + + ", type=" + type + ", size=" + size + '}'); faces[faceId] = faceInfo; @@ -148,10 +124,6 @@ public int getTarget() { return target; } - public int getLevel() { - return level; - } - public int getInternalFormat() { return internalFormat; } @@ -164,22 +136,6 @@ public int getHeight() { return height; } - public int getDepth() { - return depth; - } - - public int getBorder() { - return border; - } - - public int getFormat() { - return format; - } - - public int getType() { - return type; - } - public int getId() { return id; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java index 16b610fa4..20ffdddda 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java @@ -11,6 +11,8 @@ public class OpenGLReportInfo { private final List paramsList = new ArrayList<>(); + private long totalSize; + private int allocCount = 1; public OpenGLReportInfo(OpenGLInfo innerInfo) { @@ -68,6 +70,14 @@ public void incAllocRecord(int id) { idList.add(id); } + public void appendSize(long size) { + this.totalSize += size; + } + + public long getTotalSize() { + return totalSize; + } + public String getAllocIdList() { return idList.toString(); } 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 aecbb3799..533616495 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 @@ -195,6 +195,7 @@ private String getResListString(List resList) { AutoWrapBuilder result = new AutoWrapBuilder(); for (OpenGLReportInfo report : resList) { result.append(String.format(" alloc count = %d", report.getAllocCount())) + .append(String.format(" total size = %s", report.getTotalSize())) .append(String.format(" id = %s", report.getAllocIdList())) .append(String.format(" activity = %s", report.innerInfo.getActivityInfo().name)) .append(String.format(" type = %s", report.innerInfo.getType())) @@ -245,6 +246,7 @@ public String dumpGLToString() { oldInfo.incAllocRecord(info.getId()); if (oldInfo.innerInfo.getMemoryInfo() != null) { oldInfo.appendParamsInfos(info.getMemoryInfo()); + oldInfo.appendSize(info.getMemoryInfo().getSize()); } infoMap.put(infoHash, oldInfo); } @@ -274,7 +276,13 @@ public String dumpGLToString() { Comparator comparator = new Comparator() { @Override public int compare(OpenGLReportInfo o1, OpenGLReportInfo o2) { - return o2.getAllocCount() - o1.getAllocCount(); + if (o2.getTotalSize() - o1.getTotalSize() > 0) { + return 1; + } else if (o2.getTotalSize() - o1.getTotalSize() == 0) { + return 0; + } else { + return -1; + } } }; From d24a46e28a5deabf042c94f873709985ddaf5d05 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 22:11:58 +0800 Subject: [PATCH 088/163] reuse memoryinfo --- .../matrix/openglleak/hook/OpenGLHook.java | 20 +++++++++++++++---- .../statistics/resource/MemoryInfo.java | 3 +++ 2 files changed, 19 insertions(+), 4 deletions(-) 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 6ed38c821..4fa8dfacf 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 @@ -442,7 +442,10 @@ public static void onGlTexImage2D(final int target, final int level, final int i ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo() ; + if (memoryInfo == null) { + memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); + } memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); @@ -469,7 +472,10 @@ public static void onGlTexImage3D(final int target, final int level, final int i ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo() ; + if (memoryInfo == null) { + memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); + } memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); } @@ -504,7 +510,10 @@ public void run() { } else { actualSize = size; } - MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.BUFFER); + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo() ; + if (memoryInfo == null) { + memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.BUFFER); + } memoryInfo.setBufferInfo(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), actualSize, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); } @@ -530,7 +539,10 @@ public static void onGlRenderbufferStorage(final int target, final int internalf ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - MemoryInfo memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.RENDER_BUFFERS); + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo() ; + if (memoryInfo == null) { + memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.RENDER_BUFFERS); + } memoryInfo.setRenderbufferInfo(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 4cea0d812..49c34667d 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -79,6 +79,9 @@ public void setTexturesInfo(int target, int level, int internalFormat, int width return; } + this.javaStack = javaStack; + this.nativeStackPtr = nativeStackPtr; + FaceInfo faceInfo = faces[faceId]; if (faceInfo == null) { faceInfo = new FaceInfo(); From 6d78922d58c19fbe7079e0ca3ee7d886cac811d1 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 22:13:49 +0800 Subject: [PATCH 089/163] style code --- .../com/tencent/matrix/openglleak/hook/OpenGLHook.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 4fa8dfacf..b831cc947 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 @@ -442,7 +442,7 @@ public static void onGlTexImage2D(final int target, final int level, final int i ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - MemoryInfo memoryInfo = openGLInfo.getMemoryInfo() ; + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo(); if (memoryInfo == null) { memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); } @@ -472,7 +472,7 @@ public static void onGlTexImage3D(final int target, final int level, final int i ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - MemoryInfo memoryInfo = openGLInfo.getMemoryInfo() ; + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo(); if (memoryInfo == null) { memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); } @@ -510,7 +510,7 @@ public void run() { } else { actualSize = size; } - MemoryInfo memoryInfo = openGLInfo.getMemoryInfo() ; + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo(); if (memoryInfo == null) { memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.BUFFER); } @@ -539,7 +539,7 @@ public static void onGlRenderbufferStorage(final int target, final int internalf ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { - MemoryInfo memoryInfo = openGLInfo.getMemoryInfo() ; + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo(); if (memoryInfo == null) { memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.RENDER_BUFFERS); } From 31dc956bbf5c1a442f7780b5b6e17cdb77801312 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 22:20:49 +0800 Subject: [PATCH 090/163] fix total size bufg --- .../matrix/openglleak/statistics/resource/OpenGLReportInfo.java | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java index 20ffdddda..a456ff852 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java @@ -19,6 +19,7 @@ public OpenGLReportInfo(OpenGLInfo innerInfo) { this.innerInfo = innerInfo; idList.add(innerInfo.getId()); appendParamsInfos(innerInfo.getMemoryInfo()); + totalSize += innerInfo.getMemoryInfo().getSize(); } public void appendParamsInfos(MemoryInfo memoryInfo) { From a3ef3a00c3da17f7a5cef9cedf5321e1a2a5f37a Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 22:31:35 +0800 Subject: [PATCH 091/163] fix null point --- .../matrix/openglleak/statistics/resource/OpenGLReportInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java index a456ff852..46ca19912 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java @@ -19,7 +19,6 @@ public OpenGLReportInfo(OpenGLInfo innerInfo) { this.innerInfo = innerInfo; idList.add(innerInfo.getId()); appendParamsInfos(innerInfo.getMemoryInfo()); - totalSize += innerInfo.getMemoryInfo().getSize(); } public void appendParamsInfos(MemoryInfo memoryInfo) { @@ -27,6 +26,7 @@ public void appendParamsInfos(MemoryInfo memoryInfo) { return; } OpenGLInfo.TYPE resType = memoryInfo.getResType(); + totalSize += innerInfo.getMemoryInfo().getSize(); if (resType == OpenGLInfo.TYPE.TEXTURE) { FaceInfo[] faces = memoryInfo.getFaces(); for (FaceInfo faceInfo : faces) { From 0b1892d79d38b446c1c0f5c4ac24e04c1493b286 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Mon, 6 Dec 2021 22:36:41 +0800 Subject: [PATCH 092/163] fix count total size error --- .../openglleak/statistics/resource/OpenGLReportInfo.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java index 46ca19912..1e04b1252 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java @@ -19,6 +19,9 @@ public OpenGLReportInfo(OpenGLInfo innerInfo) { this.innerInfo = innerInfo; idList.add(innerInfo.getId()); appendParamsInfos(innerInfo.getMemoryInfo()); + if (innerInfo.getMemoryInfo() != null) { + totalSize += innerInfo.getMemoryInfo().getSize(); + } } public void appendParamsInfos(MemoryInfo memoryInfo) { @@ -26,7 +29,7 @@ public void appendParamsInfos(MemoryInfo memoryInfo) { return; } OpenGLInfo.TYPE resType = memoryInfo.getResType(); - totalSize += innerInfo.getMemoryInfo().getSize(); + if (resType == OpenGLInfo.TYPE.TEXTURE) { FaceInfo[] faces = memoryInfo.getFaces(); for (FaceInfo faceInfo : faces) { From 0a0f7edb29677a60c5bbff87dc2f3bb16c5a8341 Mon Sep 17 00:00:00 2001 From: opdeng Date: Tue, 7 Dec 2021 11:12:14 +0800 Subject: [PATCH 093/163] faceinfo delete params --- .../statistics/resource/FaceInfo.java | 121 +++++++++++++++++- .../statistics/resource/MemoryInfo.java | 27 ++-- .../statistics/resource/OpenGLInfo.java | 1 + .../statistics/resource/OpenGLReportInfo.java | 2 +- 4 files changed, 129 insertions(+), 22 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/FaceInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/FaceInfo.java index 206d43cd2..28830ced3 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/FaceInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/FaceInfo.java @@ -2,20 +2,109 @@ public class FaceInfo { - private String params; - private long size; + private int target; + private int id; + private long eglContextNativeHandle; + private int level; + private int internalFormat; + private int width; + private int height; + private int depth; + private int border; + private int format; + private int type; - public FaceInfo() { + public int getTarget() { + return target; + } + + public void setTarget(int target) { + this.target = target; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public long getEglContextNativeHandle() { + return eglContextNativeHandle; + } + + public void setEglContextNativeHandle(long eglContextNativeHandle) { + this.eglContextNativeHandle = eglContextNativeHandle; + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public int getInternalFormat() { + return internalFormat; + } + + public void setInternalFormat(int internalFormat) { + this.internalFormat = internalFormat; + } + + public int getWidth() { + return width; + } + public void setWidth(int width) { + this.width = width; } - public String getParams() { - return params; + public int getHeight() { + return height; } - public void setParams(String params) { - this.params = params; + public void setHeight(int height) { + this.height = height; + } + + public int getDepth() { + return depth; + } + + public void setDepth(int depth) { + this.depth = depth; + } + + public int getBorder() { + return border; + } + + public void setBorder(int border) { + this.border = border; + } + + public int getFormat() { + return format; + } + + public void setFormat(int format) { + this.format = format; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public FaceInfo() { + } public long getSize() { @@ -25,4 +114,22 @@ public long getSize() { public void setSize(long size) { this.size = size; } + + @Override + public String toString() { + return "FaceInfo{" + + "size=" + size + + ", target=" + target + + ", id=" + id + + ", eglContextNativeHandle=" + eglContextNativeHandle + + ", level=" + level + + ", internalFormat=" + internalFormat + + ", width=" + width + + ", height=" + height + + ", depth=" + depth + + ", border=" + border + + ", format=" + format + + ", type=" + type + + '}'; + } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 49c34667d..5cb3e25f3 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -86,21 +86,20 @@ public void setTexturesInfo(int target, int level, int internalFormat, int width if (faceInfo == null) { faceInfo = new FaceInfo(); } + + faceInfo.setTarget(target); + faceInfo.setId(id); + faceInfo.setEglContextNativeHandle(eglContextId); + faceInfo.setLevel(level); + faceInfo.setInternalFormat(internalFormat); + faceInfo.setWidth(width); + faceInfo.setHeight(height); + faceInfo.setDepth(depth); + faceInfo.setBorder(border); + faceInfo.setFormat(format); + faceInfo.setType(type); faceInfo.setSize(size); - faceInfo.setParams("MemoryInfo{" + - "target=" + target + - ", id=" + id + - ", eglContextNativeHandle='" + eglContextId + '\'' + - ", level=" + level + - ", internalFormat=" + internalFormat + - ", width=" + width + - ", height=" + height + - ", depth=" + depth + - ", border=" + border + - ", format=" + format + - ", type=" + type + - ", size=" + size + - '}'); + faces[faceId] = faceInfo; } 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 edb0650cb..0072f1b69 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 @@ -114,6 +114,7 @@ public String toString() { ", javaStack='" + javaStack + '\'' + ", nativeStack='" + getNativeStack() + '\'' + ", nativeStackPtr=" + nativeStackPtr + + ", memoryInfo=" + memoryInfo + '}'; } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java index 1e04b1252..8bb0e49c2 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java @@ -34,7 +34,7 @@ public void appendParamsInfos(MemoryInfo memoryInfo) { FaceInfo[] faces = memoryInfo.getFaces(); for (FaceInfo faceInfo : faces) { if (faceInfo != null) { - paramsList.add(faceInfo.getParams()); + paramsList.add(faceInfo.toString()); } } } else if (resType == OpenGLInfo.TYPE.BUFFER) { From 04aabfcc4874e1a8971ab6c64338e050d59642b4 Mon Sep 17 00:00:00 2001 From: opdeng Date: Tue, 7 Dec 2021 11:17:47 +0800 Subject: [PATCH 094/163] OpenGLReportInfo -> OpenGLDumpInfo --- ...nGLReportInfo.java => OpenGLDumpInfo.java} | 4 +-- .../statistics/resource/ResRecordManager.java | 28 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) rename matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/{OpenGLReportInfo.java => OpenGLDumpInfo.java} (97%) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLDumpInfo.java similarity index 97% rename from matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java rename to matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLDumpInfo.java index 8bb0e49c2..bf25b399f 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLReportInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/OpenGLDumpInfo.java @@ -3,7 +3,7 @@ import java.util.ArrayList; import java.util.List; -public class OpenGLReportInfo { +public class OpenGLDumpInfo { public final OpenGLInfo innerInfo; @@ -15,7 +15,7 @@ public class OpenGLReportInfo { private int allocCount = 1; - public OpenGLReportInfo(OpenGLInfo innerInfo) { + public OpenGLDumpInfo(OpenGLInfo innerInfo) { this.innerInfo = innerInfo; idList.add(innerInfo.getId()); appendParamsInfos(innerInfo.getMemoryInfo()); 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 533616495..bda1c2963 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 @@ -191,9 +191,9 @@ public void dumpGLToFile(String filePath) { } @SuppressLint("DefaultLocale") - private String getResListString(List resList) { + private String getResListString(List resList) { AutoWrapBuilder result = new AutoWrapBuilder(); - for (OpenGLReportInfo report : resList) { + for (OpenGLDumpInfo report : resList) { result.append(String.format(" alloc count = %d", report.getAllocCount())) .append(String.format(" total size = %s", report.getTotalSize())) .append(String.format(" id = %s", report.getAllocIdList())) @@ -208,7 +208,7 @@ private String getResListString(List resList) { return result.toString(); } - private String getMemoryInfoStr(OpenGLReportInfo reportInfo) { + private String getMemoryInfoStr(OpenGLDumpInfo reportInfo) { return reportInfo.getParamsInfos() + "\n" + String.format(" memory java stack = %s", reportInfo.innerInfo.getMemoryInfo().getJavaStack()) + @@ -218,7 +218,7 @@ private String getMemoryInfoStr(OpenGLReportInfo reportInfo) { @SuppressLint("DefaultLocale") public String dumpGLToString() { - Map infoMap = new HashMap<>(); + Map infoMap = new HashMap<>(); for (int i = 0; i < mInfoList.size(); i++) { OpenGLInfo info = mInfoList.get(i); @@ -231,10 +231,10 @@ public String dumpGLToString() { long infoHash = javaHash + nativeHash + memoryNativeHash + memoryJavaHash; - OpenGLReportInfo oldInfo = infoMap.get(infoHash); + OpenGLDumpInfo oldInfo = infoMap.get(infoHash); if (oldInfo == null) { - OpenGLReportInfo openGLReportInfo = new OpenGLReportInfo(info); - infoMap.put(infoHash, openGLReportInfo); + OpenGLDumpInfo openGLDumpInfo = new OpenGLDumpInfo(info); + infoMap.put(infoHash, openGLDumpInfo); } else { // resource part boolean isSameType = info.getType() == oldInfo.innerInfo.getType(); @@ -253,12 +253,12 @@ public String dumpGLToString() { } } - List textureList = new ArrayList<>(); - List bufferList = new ArrayList<>(); - List framebufferList = new ArrayList<>(); - List renderbufferList = new ArrayList<>(); + List textureList = new ArrayList<>(); + List bufferList = new ArrayList<>(); + List framebufferList = new ArrayList<>(); + List renderbufferList = new ArrayList<>(); - for (OpenGLReportInfo reportInfo : infoMap.values()) { + for (OpenGLDumpInfo reportInfo : infoMap.values()) { if (reportInfo.innerInfo.getType() == OpenGLInfo.TYPE.TEXTURE) { textureList.add(reportInfo); } @@ -273,9 +273,9 @@ public String dumpGLToString() { } } - Comparator comparator = new Comparator() { + Comparator comparator = new Comparator() { @Override - public int compare(OpenGLReportInfo o1, OpenGLReportInfo o2) { + public int compare(OpenGLDumpInfo o1, OpenGLDumpInfo o2) { if (o2.getTotalSize() - o1.getTotalSize() > 0) { return 1; } else if (o2.getTotalSize() - o1.getTotalSize() == 0) { From 42fa1901adb36bb742aa00bc89c57da374881b46 Mon Sep 17 00:00:00 2001 From: opdeng Date: Tue, 7 Dec 2021 12:33:40 +0800 Subject: [PATCH 095/163] bug fix --- .../statistics/CustomizeLeakMonitor.java | 2 +- .../statistics/LeakMonitorDefault.java | 36 ++++--------------- .../statistics/resource/MemoryInfo.java | 21 ++++++++++- .../statistics/resource/ResRecorder.java | 18 ++-------- .../openglleak/utils/ActivityRecorder.java | 31 ++++++++++++++++ 5 files changed, 60 insertions(+), 48 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java index 7f0087d0a..11f695bf8 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/CustomizeLeakMonitor.java @@ -20,7 +20,7 @@ public void checkStart() { public List checkEnd() { mResRecorder.end(); - return mResRecorder.getCopyList(); + return mResRecorder.getCurList(); } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java index a9283637c..9cd785ae9 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/LeakMonitorDefault.java @@ -8,14 +8,13 @@ import androidx.annotation.Nullable; import com.tencent.matrix.openglleak.statistics.resource.OpenGLInfo; +import com.tencent.matrix.openglleak.utils.ActivityRecorder; import com.tencent.matrix.util.MatrixLog; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.Map; public abstract class LeakMonitorDefault implements Application.ActivityLifecycleCallbacks { @@ -30,7 +29,7 @@ public void start(Application context) { context.registerActivityLifecycleCallbacks(this); MatrixLog.i(TAG, "start"); - Activity currentActivity = getActivity(); + Activity currentActivity = ActivityRecorder.getActivity(); if (null != currentActivity) { ActivityLeakMonitor activityLeakMonitor = new ActivityLeakMonitor(currentActivity.hashCode(), new CustomizeLeakMonitor()); activityLeakMonitor.start(); @@ -81,8 +80,10 @@ public void onActivityDestroyed(@NonNull Activity activity) { leaks = activityLeakMonitor.end(); for (OpenGLInfo leakItem : leaks) { if (null != leakItem) { - if (leakItem.getActivityInfo().activityHashcode == activityLeakMonitor.mActivityHashCode) { - onLeak(leakItem); + if (null != leakItem.getActivityInfo()) { + if (leakItem.getActivityInfo().activityHashcode == activityLeakMonitor.mActivityHashCode) { + onLeak(leakItem); + } } } } @@ -118,31 +119,6 @@ public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bun } - public static Activity getActivity() { - Class activityThreadClass = null; - try { - activityThreadClass = Class.forName("android.app.ActivityThread"); - Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null); - Field activitiesField = activityThreadClass.getDeclaredField("mActivities"); - activitiesField.setAccessible(true); - Map activities = (Map) activitiesField.get(activityThread); - for (Object activityRecord : activities.values()) { - Class activityRecordClass = activityRecord.getClass(); - Field pausedField = activityRecordClass.getDeclaredField("paused"); - pausedField.setAccessible(true); - if (!pausedField.getBoolean(activityRecord)) { - Field activityField = activityRecordClass.getDeclaredField("activity"); - activityField.setAccessible(true); - Activity activity = (Activity) activityField.get(activityRecord); - return activity; - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - class ActivityLeakMonitor { private int mActivityHashCode; private CustomizeLeakMonitor mMonitor; diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 5cb3e25f3..1498b9295 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -12,6 +12,8 @@ import com.tencent.matrix.util.MatrixLog; +import java.util.Arrays; + public class MemoryInfo { private int target; @@ -188,5 +190,22 @@ public void setRenderbufferInfo(int target, int width, int height, int internalF this.nativeStackPtr = nativeStackPtr; } - + @Override + public String toString() { + return "MemoryInfo{" + + "target=" + target + + ", internalFormat=" + internalFormat + + ", width=" + width + + ", height=" + height + + ", id=" + id + + ", eglContextId=" + eglContextId + + ", usage=" + usage + + ", javaStack='" + javaStack + '\'' + + ", nativeStack='" + nativeStack + '\'' + + ", nativeStackPtr=" + nativeStackPtr + + ", resType=" + resType + + ", size=" + size + + ", faces=" + Arrays.toString(faces) + + '}'; + } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java index 498a3b455..759a496f6 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/ResRecorder.java @@ -1,6 +1,5 @@ package com.tencent.matrix.openglleak.statistics.resource; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -33,21 +32,8 @@ public void delete(final OpenGLInfo res) { } } - public List getCopyList() { - List ll = new ArrayList<>(); - - synchronized (mList) { - for (OpenGLInfo item : mList) { - if (item == null) { - break; - } - - OpenGLInfo clone = new OpenGLInfo(item); - ll.add(clone); - } - } - - return ll; + public List getCurList() { + return mList; } public void clear() { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java index 748fe32b7..8a5c9dcf4 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/ActivityRecorder.java @@ -7,8 +7,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.lang.reflect.Field; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Objects; public class ActivityRecorder implements Application.ActivityLifecycleCallbacks { @@ -24,6 +26,10 @@ public static ActivityRecorder getInstance() { } public void start(Application context) { + Activity activity = getActivity(); + if (null != activity) { + currentActivityInfo = new ActivityInfo(activity.hashCode(), activity.getLocalClassName()); + } context.registerActivityLifecycleCallbacks(this); } @@ -73,6 +79,31 @@ public void onActivityDestroyed(@NonNull Activity activity) { mList.remove(new ActivityInfo(activity.hashCode(), activity.getLocalClassName())); } + public static Activity getActivity() { + Class activityThreadClass = null; + try { + activityThreadClass = Class.forName("android.app.ActivityThread"); + Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null); + Field activitiesField = activityThreadClass.getDeclaredField("mActivities"); + activitiesField.setAccessible(true); + Map activities = (Map) activitiesField.get(activityThread); + for (Object activityRecord : activities.values()) { + Class activityRecordClass = activityRecord.getClass(); + Field pausedField = activityRecordClass.getDeclaredField("paused"); + pausedField.setAccessible(true); + if (!pausedField.getBoolean(activityRecord)) { + Field activityField = activityRecordClass.getDeclaredField("activity"); + activityField.setAccessible(true); + Activity activity = (Activity) activityField.get(activityRecord); + return activity; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + public static class ActivityInfo { public int activityHashcode; public String name; From c888989633e5451231a802e290634b10636584e7 Mon Sep 17 00:00:00 2001 From: opdeng Date: Tue, 7 Dec 2021 12:41:25 +0800 Subject: [PATCH 096/163] fix memory toString size bug --- .../matrix/openglleak/statistics/resource/MemoryInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 1498b9295..3e6b4652d 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -204,7 +204,7 @@ public String toString() { ", nativeStack='" + nativeStack + '\'' + ", nativeStackPtr=" + nativeStackPtr + ", resType=" + resType + - ", size=" + size + + ", size=" + getSize() + ", faces=" + Arrays.toString(faces) + '}'; } From 589e2501fa33980319a37fed25eb847290f33247 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Tue, 7 Dec 2021 20:32:22 +0800 Subject: [PATCH 097/163] fix jni leak & redelete native ptr --- .../src/main/cpp/my_functions.h | 86 +++++++++++++------ .../detector/OpenglIndexDetectorService.java | 1 - .../matrix/openglleak/hook/OpenGLHook.java | 81 +++++++++-------- .../statistics/resource/MemoryInfo.java | 14 ++- .../statistics/resource/OpenGLInfo.java | 1 + .../statistics/resource/ResRecordManager.java | 1 + 6 files changed, 113 insertions(+), 71 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 3cf5f45d7..9e7601155 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 @@ -67,6 +67,8 @@ const size_t BUF_SIZE = 1024; static pthread_once_t g_onceInitTls = PTHREAD_ONCE_INIT; static pthread_key_t g_tlsJavaEnv; +map jni_env_status; + static bool is_stacktrace_enabled = true; void enable_stacktrace(bool enable) { @@ -106,11 +108,18 @@ inline bool is_render_thread() { JNIEnv *GET_ENV() { JNIEnv *env; int ret = m_java_vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + thread::id thread_id = this_thread::get_id(); + map::iterator it = jni_env_status.find(thread_id); + if (it == jni_env_status.end()) { + jni_env_status.insert(map::value_type(thread_id, ret)); + } if (ret != JNI_OK) { pthread_once(&g_onceInitTls, []() { pthread_key_create(&g_tlsJavaEnv, [](void *d) { if (d && m_java_vm) m_java_vm->DetachCurrentThread(); + thread::id thread_id = this_thread::get_id(); + jni_env_status.erase(thread_id); }); }); @@ -161,6 +170,12 @@ void get_thread_id_string(char *&result) { thread_id_to_string(thread_id, result); } +bool is_need_get_java_stack() { + thread::id thread_id = this_thread::get_id(); + map::iterator it = jni_env_status.find(thread_id); + return it->second; +} + GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { if (NULL != system_glGenTextures) { system_glGenTextures(n, textures); @@ -197,8 +212,8 @@ GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { } jstring java_stack; - char *javaStack; - if (is_javastack_enabled) { + char *javaStack = nullptr; + if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -209,7 +224,7 @@ GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { java_stack, (int64_t) backtracePrt); delete[] result; - if (is_javastack_enabled) { + if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } @@ -292,8 +307,8 @@ GL_APICALL void GL_APIENTRY my_glGenBuffers(GLsizei n, GLuint *buffers) { } jstring java_stack; - char *javaStack; - if (is_javastack_enabled) { + char *javaStack = nullptr; + if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -304,7 +319,7 @@ GL_APICALL void GL_APIENTRY my_glGenBuffers(GLsizei n, GLuint *buffers) { java_stack, (int64_t) backtracePrt); delete[] result; - if (is_javastack_enabled) { + if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } @@ -386,8 +401,8 @@ GL_APICALL void GL_APIENTRY my_glGenFramebuffers(GLsizei n, GLuint *buffers) { } jstring java_stack; - char *javaStack; - if (is_javastack_enabled) { + char *javaStack = nullptr; + if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -398,7 +413,7 @@ GL_APICALL void GL_APIENTRY my_glGenFramebuffers(GLsizei n, GLuint *buffers) { j_thread_id, java_stack, (int64_t) backtracePrt); delete[] result; - if (is_javastack_enabled) { + if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } @@ -481,8 +496,8 @@ GL_APICALL void GL_APIENTRY my_glGenRenderbuffers(GLsizei n, GLuint *buffers) { } jstring java_stack; - char *javaStack; - if (is_javastack_enabled) { + char *javaStack = nullptr; + if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -493,7 +508,7 @@ GL_APICALL void GL_APIENTRY my_glGenRenderbuffers(GLsizei n, GLuint *buffers) { j_thread_id, java_stack, (int64_t) backtracePrt); delete[] result; - if (is_javastack_enabled) { + if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } @@ -584,8 +599,8 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, } jstring java_stack; - char *javaStack; - if (is_javastack_enabled) { + char *javaStack = nullptr; + if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -593,8 +608,13 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, } env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, level, - internalformat, width, height, border, format, type, size, java_stack, (int64_t) backtracePrt); + internalformat, width, height, border, format, type, size, + java_stack, (int64_t) backtracePrt); + if (is_javastack_enabled && javaStack != nullptr) { + free(javaStack); + } + env->DeleteLocalRef(java_stack); } } @@ -627,8 +647,8 @@ my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, } jstring java_stack; - char *javaStack; - if (is_javastack_enabled) { + char *javaStack = nullptr; + if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -636,7 +656,13 @@ my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, } env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage3D, target, level, - internalformat, width, height, depth, border, format, type, size, java_stack, (int64_t) backtracePrt); + internalformat, width, height, depth, border, format, type, size, + java_stack, (int64_t) backtracePrt); + + if (is_javastack_enabled && javaStack != nullptr) { + free(javaStack); + } + env->DeleteLocalRef(java_stack); } } @@ -717,15 +743,21 @@ my_glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage } jstring java_stack; - char *javaStack; - if (is_javastack_enabled) { + char *javaStack = nullptr; + if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { java_stack = env->NewStringUTF(""); } - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBufferData, target, size, usage, java_stack, (int64_t) backtracePrt); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBufferData, target, size, usage, + java_stack, (int64_t) backtracePrt); + + if (is_javastack_enabled && javaStack != nullptr) { + free(javaStack); + } + env->DeleteLocalRef(java_stack); } } @@ -754,8 +786,8 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL } jstring java_stack; - char *javaStack; - if (is_javastack_enabled) { + char *javaStack = nullptr; + if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -764,7 +796,13 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL long size = Utils::getRenderbufferSizeByFormula(internalformat, width, height); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlRenderbufferStorage, target, - width, height, internalformat, size, java_stack, (int64_t) backtracePrt); + width, height, internalformat, size, java_stack, + (int64_t) backtracePrt); + + if (is_javastack_enabled && javaStack != nullptr) { + free(javaStack); + } + env->DeleteLocalRef(java_stack); } } diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java index 7bde78637..bdc45bb89 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java @@ -39,7 +39,6 @@ public IBinder onBind(Intent intent) { private Map seekOpenglFuncIndex() { // 初始化 egl 环境,目的为了初始化 gl 表 EGLHelper.initOpenGL(); - OpenGLHook.getInstance().init(); MatrixLog.i(TAG, "init env succ"); 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 b831cc947..81faaccfa 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 @@ -433,15 +433,16 @@ public static void onGlTexImage2D(final int target, final int level, final int i if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - - final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe undo glBindTextures()"); - return; - } + final long finalEglContextId = eglContextId; ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { + final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, finalEglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlTexImage2D: getCurrentResourceIdByTarget openGLID == null, maybe undo glBindTextures()"); + return; + } + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo(); if (memoryInfo == null) { memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); @@ -449,13 +450,12 @@ public void run() { memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, 0, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); + } } }); - if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage2D(target, level, internalFormat, width, height, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); - } - } 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 String javaStack, final long nativeStack) { @@ -463,28 +463,29 @@ public static void onGlTexImage3D(final int target, final int level, final int i if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - - final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, eglContextId, target); - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe undo glBindTextures()"); - return; - } + final long finalEglContextId = eglContextId; ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { + final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.TEXTURE, finalEglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlTexImage3D: getCurrentResourceIdByTarget result == null, maybe undo glBindTextures()"); + return; + } + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo(); if (memoryInfo == null) { memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.TEXTURE); } memoryInfo.setTexturesInfo(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); + } } }); - if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); - } - } public static void onGlBufferData(final int target, final long size, final int usage, final String javaStack, final long nativeStack) { @@ -496,14 +497,16 @@ public static void onGlBufferData(final int target, final long size, final int u eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, eglContextId, target); - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe undo glBindBuffer()"); - return; - } + final long finalEglContextId = eglContextId; ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { + final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.BUFFER, finalEglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlBufferData: getCurrentResourceIdByTarget result == null, maybe undo glBindBuffer()"); + return; + } + long actualSize = -1; if (target == GL_PIXEL_UNPACK_BUFFER) { actualSize = size * 2; @@ -516,13 +519,13 @@ public void run() { } memoryInfo.setBufferInfo(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), actualSize, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlBufferData(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); + } } }); - if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlBufferData(target, usage, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); - } - } public static void onGlRenderbufferStorage(final int target, final int internalformat, final int width, final int height, final long size, final String javaStack, final long nativeStack) { @@ -531,26 +534,28 @@ public static void onGlRenderbufferStorage(final int target, final int internalf eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); } - final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, eglContextId, target); - if (openGLInfo == null) { - MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe undo glBindRenderbuffer()"); - return; - } + final long finalEglContextId = eglContextId; ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { + final OpenGLInfo openGLInfo = BindCenter.getInstance().findCurrentResourceIdByTarget(OpenGLInfo.TYPE.RENDER_BUFFERS, finalEglContextId, target); + if (openGLInfo == null) { + MatrixLog.e(TAG, "onGlRenderbufferStorage: getCurrentResourceIdByTarget result == null, maybe undo glBindRenderbuffer()"); + return; + } + MemoryInfo memoryInfo = openGLInfo.getMemoryInfo(); if (memoryInfo == null) { memoryInfo = new MemoryInfo(OpenGLInfo.TYPE.RENDER_BUFFERS); } memoryInfo.setRenderbufferInfo(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size, javaStack, nativeStack); openGLInfo.setMemoryInfo(memoryInfo); + + if (getInstance().mMemoryListener != null) { + getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); + } } }); - - if (getInstance().mMemoryListener != null) { - getInstance().mMemoryListener.onGlRenderbufferStorage(target, width, height, internalformat, openGLInfo.getId(), openGLInfo.getEglContextNativeHandle(), size); - } } public interface ErrorListener { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 3e6b4652d..2a06e2b19 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -32,8 +32,6 @@ public class MemoryInfo { private String javaStack = ""; - private String nativeStack = ""; - private long nativeStackPtr; private final OpenGLInfo.TYPE resType; @@ -74,6 +72,10 @@ private int getFaceId(int target) { } } + public void releaseNativeStackPtr() { + nativeStackPtr = 0; + } + public void setTexturesInfo(int target, int level, int internalFormat, int width, int height, int depth, int border, int format, int type, int id, long eglContextId, long size, String javaStack, long nativeStackPtr) { int faceId = getFaceId(target); if (faceId == -1) { @@ -114,10 +116,7 @@ public String getJavaStack() { } public String getNativeStack() { - if (nativeStack.isEmpty() && nativeStackPtr != 0) { - nativeStack = ResRecordManager.dumpNativeStack(nativeStackPtr); - } - return nativeStack; + return nativeStackPtr != 0 ? ResRecordManager.dumpNativeStack(nativeStackPtr) : ""; } public long getNativeStackPtr() { @@ -201,8 +200,7 @@ public String toString() { ", eglContextId=" + eglContextId + ", usage=" + usage + ", javaStack='" + javaStack + '\'' + - ", nativeStack='" + nativeStack + '\'' + - ", nativeStackPtr=" + nativeStackPtr + + ", nativeStack='" + getNativeStack() + '\'' + ", resType=" + resType + ", size=" + getSize() + ", faces=" + Arrays.toString(faces) + 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 0072f1b69..4d5d3279e 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 @@ -66,6 +66,7 @@ public void setMemoryInfo(MemoryInfo memoryInfo) { if (this.memoryInfo != null) { if (memoryInfo.getNativeStackPtr() != 0) { ResRecordManager.releaseNative(memoryInfo.getNativeStackPtr()); + memoryInfo.releaseNativeStackPtr(); } } this.memoryInfo = memoryInfo; 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 bda1c2963..ba0d2ae88 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 @@ -80,6 +80,7 @@ public void delete(final OpenGLInfo del) { long memNativePtr = memoryInfo.getNativeStackPtr(); if (memNativePtr != 0) { releaseNative(memNativePtr); + memoryInfo.releaseNativeStackPtr(); } } From da1eec8474538619c9190cc795ce537a0ba108c1 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 8 Dec 2021 12:36:38 +0800 Subject: [PATCH 098/163] fix judge error --- .../matrix-opengl-leak/src/main/cpp/my_functions.h | 2 +- .../java/com/tencent/matrix/openglleak/OpenglLeakPlugin.java | 2 +- 2 files changed, 2 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 9e7601155..e423554d7 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 @@ -173,7 +173,7 @@ void get_thread_id_string(char *&result) { bool is_need_get_java_stack() { thread::id thread_id = this_thread::get_id(); map::iterator it = jni_env_status.find(thread_id); - return it->second; + return it->second == JNI_OK; } GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { 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 1ca00c967..d2492fdfc 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 @@ -185,7 +185,7 @@ public void setNativeStackDump(boolean open) { } public void setJavaStackDump(boolean open) { - OpenGLHook.getInstance().setJavaStackDump(true); + OpenGLHook.getInstance().setJavaStackDump(open); } public void clear() { From 11d0cf69a0e4de04c43251e52f7060ac84c122c1 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 8 Dec 2021 14:49:38 +0800 Subject: [PATCH 099/163] try to fix global ref decode crash problem --- .../src/main/cpp/my_functions.h | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 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 e423554d7..b78e33047 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 @@ -111,7 +111,7 @@ JNIEnv *GET_ENV() { thread::id thread_id = this_thread::get_id(); map::iterator it = jni_env_status.find(thread_id); if (it == jni_env_status.end()) { - jni_env_status.insert(map::value_type(thread_id, ret)); + jni_env_status[thread_id] = ret; } if (ret != JNI_OK) { pthread_once(&g_onceInitTls, []() { @@ -172,8 +172,7 @@ void get_thread_id_string(char *&result) { bool is_need_get_java_stack() { thread::id thread_id = this_thread::get_id(); - map::iterator it = jni_env_status.find(thread_id); - return it->second == JNI_OK; + return jni_env_status[thread_id] == JNI_OK; } GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { @@ -599,14 +598,16 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, } jstring java_stack; + jstring local_java_stack; char *javaStack = nullptr; if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); - java_stack = env->NewStringUTF(javaStack); + local_java_stack = env->NewStringUTF(javaStack); } else { - java_stack = env->NewStringUTF(""); + local_java_stack = env->NewStringUTF(""); } + java_stack = static_cast(env->NewGlobalRef(local_java_stack)); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, level, internalformat, width, height, border, format, type, size, java_stack, (int64_t) backtracePrt); @@ -614,7 +615,8 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } - env->DeleteLocalRef(java_stack); + env->DeleteLocalRef(local_java_stack); + env->DeleteGlobalRef(java_stack); } } @@ -647,14 +649,16 @@ my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, } jstring java_stack; + jstring local_java_stack; char *javaStack = nullptr; if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); - java_stack = env->NewStringUTF(javaStack); + local_java_stack = env->NewStringUTF(javaStack); } else { - java_stack = env->NewStringUTF(""); + local_java_stack = env->NewStringUTF(""); } + java_stack = static_cast(env->NewGlobalRef(local_java_stack)); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage3D, target, level, internalformat, width, height, depth, border, format, type, size, java_stack, (int64_t) backtracePrt); @@ -662,7 +666,8 @@ my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } - env->DeleteLocalRef(java_stack); + env->DeleteLocalRef(local_java_stack); + env->DeleteGlobalRef(java_stack); } } @@ -743,21 +748,24 @@ my_glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage } jstring java_stack; + jstring local_java_stack; char *javaStack = nullptr; if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); - java_stack = env->NewStringUTF(javaStack); + local_java_stack = env->NewStringUTF(javaStack); } else { - java_stack = env->NewStringUTF(""); + local_java_stack = env->NewStringUTF(""); } + java_stack = static_cast(env->NewGlobalRef(local_java_stack)); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBufferData, target, size, usage, java_stack, (int64_t) backtracePrt); if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } - env->DeleteLocalRef(java_stack); + env->DeleteLocalRef(local_java_stack); + env->DeleteGlobalRef(java_stack); } } @@ -786,15 +794,17 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL } jstring java_stack; + jstring local_java_stack; char *javaStack = nullptr; if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); - java_stack = env->NewStringUTF(javaStack); + local_java_stack = env->NewStringUTF(javaStack); } else { - java_stack = env->NewStringUTF(""); + local_java_stack = env->NewStringUTF(""); } long size = Utils::getRenderbufferSizeByFormula(internalformat, width, height); + java_stack = static_cast(env->NewGlobalRef(local_java_stack)); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlRenderbufferStorage, target, width, height, internalformat, size, java_stack, (int64_t) backtracePrt); @@ -802,7 +812,8 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } - env->DeleteLocalRef(java_stack); + env->DeleteLocalRef(local_java_stack); + env->DeleteGlobalRef(java_stack); } } From ede7fbe8765906fd3307777fc7dc7491336f5d03 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 8 Dec 2021 19:01:56 +0800 Subject: [PATCH 100/163] fix 32bit jni abort crash --- ...cent_matrix_openglleak_hook_OpenGLHook.cpp | 2 +- .../src/main/cpp/my_functions.h | 56 ++++++++----------- .../matrix/openglleak/hook/OpenGLHook.java | 2 +- 3 files changed, 25 insertions(+), 35 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 930fcae8a..58ce9e5dd 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 @@ -44,7 +44,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_tencent_matrix_openglleak_hook_Op method_onGlBindRenderbuffer = env->GetStaticMethodID(class_OpenGLHook, "onGlBindRenderbuffer", "(II)V"); method_onGlTexImage2D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage2D", "(IIIIIIIIJLjava/lang/String;J)V"); method_onGlTexImage3D = env->GetStaticMethodID(class_OpenGLHook, "onGlTexImage3D", "(IIIIIIIIIJLjava/lang/String;J)V"); - method_onGlBufferData = env->GetStaticMethodID(class_OpenGLHook, "onGlBufferData", "(IJILjava/lang/String;J)V"); + method_onGlBufferData = env->GetStaticMethodID(class_OpenGLHook, "onGlBufferData", "(IIJLjava/lang/String;J)V"); method_onGlRenderbufferStorage = env->GetStaticMethodID(class_OpenGLHook, "onGlRenderbufferStorage", "(IIIIJLjava/lang/String;J)V"); return true; } 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 b78e33047..fe0bd3b6a 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 @@ -598,25 +598,22 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, } jstring java_stack; - jstring local_java_stack; - char *javaStack = nullptr; + const char *javaStack = nullptr; if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); - local_java_stack = env->NewStringUTF(javaStack); + java_stack = env->NewStringUTF(javaStack); } else { - local_java_stack = env->NewStringUTF(""); + java_stack = env->NewStringUTF(""); } - java_stack = static_cast(env->NewGlobalRef(local_java_stack)); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage2D, target, level, - internalformat, width, height, border, format, type, size, - java_stack, (int64_t) backtracePrt); + internalformat, width, height, border, format, type, (jlong) size, + java_stack, (jlong) backtracePrt); if (is_javastack_enabled && javaStack != nullptr) { - free(javaStack); + free((void *) javaStack); } - env->DeleteLocalRef(local_java_stack); - env->DeleteGlobalRef(java_stack); + env->DeleteLocalRef(java_stack); } } @@ -649,24 +646,22 @@ my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, } jstring java_stack; - jstring local_java_stack; char *javaStack = nullptr; if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); - local_java_stack = env->NewStringUTF(javaStack); + java_stack = env->NewStringUTF(javaStack); } else { - local_java_stack = env->NewStringUTF(""); + java_stack = env->NewStringUTF(""); } - java_stack = static_cast(env->NewGlobalRef(local_java_stack)); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlTexImage3D, target, level, - internalformat, width, height, depth, border, format, type, size, - java_stack, (int64_t) backtracePrt); + internalformat, width, height, depth, border, format, type, + (jlong) size, + java_stack, (jlong) backtracePrt); if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } - env->DeleteLocalRef(local_java_stack); env->DeleteGlobalRef(java_stack); } } @@ -748,24 +743,22 @@ my_glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage } jstring java_stack; - jstring local_java_stack; char *javaStack = nullptr; if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); - local_java_stack = env->NewStringUTF(javaStack); + java_stack = env->NewStringUTF(javaStack); } else { - local_java_stack = env->NewStringUTF(""); + java_stack = env->NewStringUTF(""); } - java_stack = static_cast(env->NewGlobalRef(local_java_stack)); - env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBufferData, target, size, usage, - java_stack, (int64_t) backtracePrt); + env->CallStaticVoidMethod(class_OpenGLHook, method_onGlBufferData, target, + usage, (jlong) size, + java_stack, (jlong) backtracePrt); if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } - env->DeleteLocalRef(local_java_stack); - env->DeleteGlobalRef(java_stack); + env->DeleteLocalRef(java_stack); } } @@ -794,26 +787,23 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL } jstring java_stack; - jstring local_java_stack; char *javaStack = nullptr; if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); - local_java_stack = env->NewStringUTF(javaStack); + java_stack = env->NewStringUTF(javaStack); } else { - local_java_stack = env->NewStringUTF(""); + java_stack = env->NewStringUTF(""); } long size = Utils::getRenderbufferSizeByFormula(internalformat, width, height); - java_stack = static_cast(env->NewGlobalRef(local_java_stack)); env->CallStaticVoidMethod(class_OpenGLHook, method_onGlRenderbufferStorage, target, - width, height, internalformat, size, java_stack, - (int64_t) backtracePrt); + width, height, internalformat, (jlong) size, java_stack, + (jlong) backtracePrt); if (is_javastack_enabled && javaStack != nullptr) { free(javaStack); } - env->DeleteLocalRef(local_java_stack); - env->DeleteGlobalRef(java_stack); + env->DeleteLocalRef(java_stack); } } 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 81faaccfa..ff223f1ad 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 @@ -488,7 +488,7 @@ public void run() { } - public static void onGlBufferData(final int target, final long size, final int usage, final String javaStack, final long nativeStack) { + public static void onGlBufferData(final int target, final int usage, final long size, final String javaStack, final long nativeStack) { if (Thread.currentThread().getName().equals("RenderThread")) { return; } From e2c900a2f4f8666c3e318ed1faf6945ac3bdb15c Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 8 Dec 2021 19:03:48 +0800 Subject: [PATCH 101/163] un use void* & const --- .../matrix-opengl-leak/src/main/cpp/my_functions.h | 4 ++-- 1 file changed, 2 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 fe0bd3b6a..338ee0c58 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 @@ -598,7 +598,7 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, } jstring java_stack; - const char *javaStack = nullptr; + char *javaStack = nullptr; if (is_javastack_enabled && is_need_get_java_stack()) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); @@ -611,7 +611,7 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, java_stack, (jlong) backtracePrt); if (is_javastack_enabled && javaStack != nullptr) { - free((void *) javaStack); + free(javaStack); } env->DeleteLocalRef(java_stack); } From 4ca1019cb9494feadaac086a8bc9eefb23df5cf4 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 8 Dec 2021 19:35:05 +0800 Subject: [PATCH 102/163] remove EGL release --- .../com/tencent/matrix/openglleak/OpenglLeakPlugin.java | 3 --- .../java/com/tencent/matrix/openglleak/utils/EGLHelper.java | 6 ------ 2 files changed, 9 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 d2492fdfc..4cf88be44 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 @@ -116,9 +116,6 @@ 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)); - - EGLHelper.release(); - 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/utils/EGLHelper.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/utils/EGLHelper.java index d822ccba5..fff23f4ee 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 @@ -74,10 +74,4 @@ public static void initOpenGL() { GLES20.glFlush(); } - - public static void release() { - EGL14.eglDestroySurface(mEGLDisplay, mEglSurface); - EGL14.eglDestroyContext(mEGLDisplay, mEglContext); - } - } From d5c0652131f1b6345d1b7483ec8bf9cdb513a505 Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Wed, 8 Dec 2021 19:37:44 +0800 Subject: [PATCH 103/163] remove EGL release --- .../matrix/openglleak/detector/OpenglIndexDetectorService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java index bdc45bb89..5aecfb384 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/detector/OpenglIndexDetectorService.java @@ -108,8 +108,6 @@ private Map seekOpenglFuncIndex() { out.put(FuncNameString.GL_RENDER_BUFFER_STORAGE, glRenderbufferStorageIndex); MatrixLog.i(TAG, "seek func index succ!"); - - EGLHelper.release(); return out; } From 04bcc13f5e603a4afe0c5c06807181161e26961b Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Thu, 9 Dec 2021 15:49:05 +0800 Subject: [PATCH 104/163] fix native stack empty & tree_balance null pointer --- .../src/main/cpp/my_functions.h | 32 +++++-------------- .../statistics/resource/MemoryInfo.java | 4 +++ .../statistics/resource/OpenGLInfo.java | 7 ++-- 3 files changed, 14 insertions(+), 29 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 338ee0c58..1e9655319 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 @@ -66,9 +66,6 @@ const size_t BUF_SIZE = 1024; static pthread_once_t g_onceInitTls = PTHREAD_ONCE_INIT; static pthread_key_t g_tlsJavaEnv; - -map jni_env_status; - static bool is_stacktrace_enabled = true; void enable_stacktrace(bool enable) { @@ -108,18 +105,11 @@ inline bool is_render_thread() { JNIEnv *GET_ENV() { JNIEnv *env; int ret = m_java_vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); - thread::id thread_id = this_thread::get_id(); - map::iterator it = jni_env_status.find(thread_id); - if (it == jni_env_status.end()) { - jni_env_status[thread_id] = ret; - } if (ret != JNI_OK) { pthread_once(&g_onceInitTls, []() { pthread_key_create(&g_tlsJavaEnv, [](void *d) { if (d && m_java_vm) m_java_vm->DetachCurrentThread(); - thread::id thread_id = this_thread::get_id(); - jni_env_status.erase(thread_id); }); }); @@ -169,12 +159,6 @@ void get_thread_id_string(char *&result) { thread::id thread_id = this_thread::get_id(); thread_id_to_string(thread_id, result); } - -bool is_need_get_java_stack() { - thread::id thread_id = this_thread::get_id(); - return jni_env_status[thread_id] == JNI_OK; -} - GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { if (NULL != system_glGenTextures) { system_glGenTextures(n, textures); @@ -212,7 +196,7 @@ GL_APICALL void GL_APIENTRY my_glGenTextures(GLsizei n, GLuint *textures) { jstring java_stack; char *javaStack = nullptr; - if (is_javastack_enabled && is_need_get_java_stack()) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -307,7 +291,7 @@ GL_APICALL void GL_APIENTRY my_glGenBuffers(GLsizei n, GLuint *buffers) { jstring java_stack; char *javaStack = nullptr; - if (is_javastack_enabled && is_need_get_java_stack()) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -401,7 +385,7 @@ GL_APICALL void GL_APIENTRY my_glGenFramebuffers(GLsizei n, GLuint *buffers) { jstring java_stack; char *javaStack = nullptr; - if (is_javastack_enabled && is_need_get_java_stack()) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -496,7 +480,7 @@ GL_APICALL void GL_APIENTRY my_glGenRenderbuffers(GLsizei n, GLuint *buffers) { jstring java_stack; char *javaStack = nullptr; - if (is_javastack_enabled && is_need_get_java_stack()) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -599,7 +583,7 @@ my_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, jstring java_stack; char *javaStack = nullptr; - if (is_javastack_enabled && is_need_get_java_stack()) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -647,7 +631,7 @@ my_glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, jstring java_stack; char *javaStack = nullptr; - if (is_javastack_enabled && is_need_get_java_stack()) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -744,7 +728,7 @@ my_glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage jstring java_stack; char *javaStack = nullptr; - if (is_javastack_enabled && is_need_get_java_stack()) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { @@ -788,7 +772,7 @@ my_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GL jstring java_stack; char *javaStack = nullptr; - if (is_javastack_enabled && is_need_get_java_stack()) { + if (is_javastack_enabled) { javaStack = get_java_stack(); java_stack = env->NewStringUTF(javaStack); } else { diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index 2a06e2b19..eca10d44f 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -83,6 +83,10 @@ public void setTexturesInfo(int target, int level, int internalFormat, int width return; } + if (this.nativeStackPtr != 0) { + ResRecordManager.releaseNative(this.nativeStackPtr); + } + this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; 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 4d5d3279e..f3a1321b7 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 @@ -63,11 +63,8 @@ public long getEglContextNativeHandle() { } public void setMemoryInfo(MemoryInfo memoryInfo) { - if (this.memoryInfo != null) { - if (memoryInfo.getNativeStackPtr() != 0) { - ResRecordManager.releaseNative(memoryInfo.getNativeStackPtr()); - memoryInfo.releaseNativeStackPtr(); - } + if (this.memoryInfo == memoryInfo) { + return; } this.memoryInfo = memoryInfo; } From 4b8543121e4c14618f0706f5dc130ad73cdfbace Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 10 Dec 2021 15:03:23 +0800 Subject: [PATCH 105/163] TouchEventTracer's Birth --- .../src/main/cpp/MatrixTracer.cc | 97 +++++++++++++++++- .../src/main/cpp/MatrixTracer.h | 2 + .../src/main/cpp/TouchEventTracer.cc | 79 +++++++++++++++ .../src/main/cpp/TouchEventTracer.h | 15 +++ .../com/tencent/matrix/trace/TracePlugin.java | 20 +++- .../matrix/trace/config/TraceConfig.java | 41 ++++++-- .../matrix/trace/constants/Constants.java | 6 +- .../trace/listeners/IDefaultConfig.java | 4 +- .../trace/tracer/TouchEventLagTracer.java | 98 +++++++++++++++++++ 9 files changed, 344 insertions(+), 18 deletions(-) create mode 100644 matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.cc create mode 100644 matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.h create mode 100644 matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/TouchEventLagTracer.java 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 ed0fd22af..bdf482cb6 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 @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -46,15 +47,19 @@ #include "nativehelper/scoped_utf_chars.h" #include "nativehelper/scoped_local_ref.h" #include "AnrDumper.h" +#include "TouchEventTracer.h" #define PROP_VALUE_MAX 92 #define PROP_SDK_NAME "ro.build.version.sdk" #define HOOK_CONNECT_PATH "/dev/socket/tombstoned_java_trace" #define HOOK_OPEN_PATH "/data/anr/traces.txt" +#define VALIDATE_RET 50 #define HOOK_REQUEST_GROUPID_THREAD_PRIO_TRACE 0x01 +#define HOOK_REQUEST_GROUPID_TOUCH_EVENT_TRACE 0x07 using namespace MatrixTracer; +using namespace std; static std::optional sAnrDumper; static bool isTraceWrite = false; @@ -63,16 +68,22 @@ static bool isHooking = false; static std::string anrTracePathstring; static std::string printTracePathstring; static int signalCatcherTid; +static int currentTouchFd; +static bool inputHasSent; static struct StacktraceJNI { jclass AnrDetective; jclass ThreadPriorityDetective; + jclass TouchEventLagTracer; jmethodID AnrDetector_onANRDumped; jmethodID AnrDetector_onANRDumpTrace; jmethodID AnrDetector_onPrintTrace; jmethodID ThreadPriorityDetective_onMainThreadPriorityModified; jmethodID ThreadPriorityDetective_onMainThreadTimerSlackModified; + + jmethodID TouchEventLagTracer_onTouchEvenLag; + jmethodID TouchEventLagTracer_onTouchEvenLagDumpTrace; } gJ; int (*original_setpriority)(int __which, id_t __who, int __priority); @@ -102,7 +113,6 @@ int my_prctl(int option, unsigned long arg2, unsigned long arg3, if (gettid()==getpid() && arg2 > 50000) { JNIEnv *env = JniInvocation::getEnv(); env->CallStaticVoidMethod(gJ.ThreadPriorityDetective, gJ.ThreadPriorityDetective_onMainThreadTimerSlackModified, arg2); - } } @@ -169,6 +179,53 @@ ssize_t my_write(int fd, const void* const buf, size_t count) { return original_write(fd, buf, count); } +void onTouchEventLag(int fd) { + JNIEnv *env = JniInvocation::getEnv(); + if (!env) return; + env->CallStaticVoidMethod(gJ.TouchEventLagTracer, gJ.TouchEventLagTracer_onTouchEvenLag, fd); +} + +void onTouchEventLagDumpTrace(int fd) { + JNIEnv *env = JniInvocation::getEnv(); + if (!env) return; + env->CallStaticVoidMethod(gJ.TouchEventLagTracer, gJ.TouchEventLagTracer_onTouchEvenLagDumpTrace, fd); +} + +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, + struct sockaddr *src_addr, socklen_t *addrlen) { + long ret = original_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); + + if (currentTouchFd == sockfd && inputHasSent && ret > VALIDATE_RET) { + TouchEventTracer::touchRecv(sockfd); + } + + if (currentTouchFd != sockfd) { + TouchEventTracer::touchSendFinish(sockfd); + } + + if (ret > 0) { + currentTouchFd = sockfd; + } else if (ret == 0) { + TouchEventTracer::touchSendFinish(sockfd); + } + return ret; +} + +ssize_t (*original_sendto)(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); +ssize_t my_sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) { + + long ret = original_sendto(sockfd, buf, len, flags, dest_addr, addrlen); + if (ret >= 0) { + inputHasSent = true; + TouchEventTracer::touchSendFinish(sockfd); + } + return ret; +} + bool anrDumpCallback() { JNIEnv *env = JniInvocation::getEnv(); if (!env) return false; @@ -286,6 +343,18 @@ static void nativeInitMainThreadPriorityDetective(JNIEnv *env, jclass) { xhook_refresh(true); } +static void nativeInitTouchEventLagDetective(JNIEnv *env, jclass, jint threshold) { + xhook_grouped_register(HOOK_REQUEST_GROUPID_TOUCH_EVENT_TRACE, ".*libinput\\.so$", "__sendto_chk", + (void *) my_sendto, (void **) (&original_sendto)); + xhook_grouped_register(HOOK_REQUEST_GROUPID_TOUCH_EVENT_TRACE, ".*libinput\\.so$", "sendto", + (void *) my_sendto, (void **) (&original_sendto)); + xhook_grouped_register(HOOK_REQUEST_GROUPID_TOUCH_EVENT_TRACE, ".*libinput\\.so$", "recvfrom", + (void *) my_recvfrom, (void **) (&original_recvfrom)); + xhook_refresh(true); + + TouchEventTracer::start(threshold); + +} static void nativePrintTrace() { fromMyPrintTrace = true; kill(getpid(), SIGQUIT); @@ -302,6 +371,12 @@ static const JNINativeMethod ANR_METHODS[] = { static const JNINativeMethod THREAD_PRIORITY_METHODS[] = { {"nativeInitMainThreadPriorityDetective", "()V", (void *) nativeInitMainThreadPriorityDetective}, + +}; + +static const JNINativeMethod TOUCH_EVENT_TRACE_METHODS[] = { + {"nativeInitTouchEventLagDetective", "(I)V", (void *) nativeInitTouchEventLagDetective}, + }; JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { @@ -331,22 +406,36 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { jclass threadPriorityDetectiveCls = env->FindClass("com/tencent/matrix/trace/tracer/ThreadPriorityTracer"); - if (!threadPriorityDetectiveCls) + + jclass touchEventLagTracerCls = env->FindClass("com/tencent/matrix/trace/tracer/TouchEventLagTracer"); + + if (!threadPriorityDetectiveCls || !touchEventLagTracerCls) return -1; gJ.ThreadPriorityDetective = static_cast(env->NewGlobalRef(threadPriorityDetectiveCls)); + gJ.TouchEventLagTracer = static_cast(env->NewGlobalRef(touchEventLagTracerCls)); + + gJ.ThreadPriorityDetective_onMainThreadPriorityModified = env->GetStaticMethodID(threadPriorityDetectiveCls, "onMainThreadPriorityModified", "(I)V"); gJ.ThreadPriorityDetective_onMainThreadTimerSlackModified = env->GetStaticMethodID(threadPriorityDetectiveCls, "onMainThreadTimerSlackModified", "(J)V"); + gJ.TouchEventLagTracer_onTouchEvenLag = + env->GetStaticMethodID(touchEventLagTracerCls, "onTouchEventLag", "(I)V"); + + gJ.TouchEventLagTracer_onTouchEvenLagDumpTrace = + env->GetStaticMethodID(touchEventLagTracerCls, "onTouchEventLagDumpTrace", "(I)V"); if (env->RegisterNatives( threadPriorityDetectiveCls, THREAD_PRIORITY_METHODS, static_cast(NELEM(THREAD_PRIORITY_METHODS))) != 0) return -1; - env->DeleteLocalRef(threadPriorityDetectiveCls); - + if (env->RegisterNatives( + touchEventLagTracerCls, TOUCH_EVENT_TRACE_METHODS, static_cast(NELEM(TOUCH_EVENT_TRACE_METHODS))) != 0) + return -1; + env->DeleteLocalRef(threadPriorityDetectiveCls); + env->DeleteLocalRef(touchEventLagTracerCls); return JNI_VERSION_1_6; } // namespace MatrixTracer diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.h b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.h index 047c578a0..7d86edb8d 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.h +++ b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/MatrixTracer.h @@ -26,4 +26,6 @@ bool anrDumpTraceCallback(); bool printTraceCallback(); void hookAnrTraceWrite(bool isSigUser); void unHookAnrTraceWrite(); +void onTouchEventLag(int fd); +void onTouchEventLagDumpTrace(int fd); #endif // LAGDETECTOR_LAG_DETECTOR_MAIN_CPP_MatrixTracer_H_ \ No newline at end of file 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 new file mode 100644 index 000000000..c0c229ce1 --- /dev/null +++ b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.cc @@ -0,0 +1,79 @@ +// +// Created by 贾建业 on 2021/11/16. +// + +#include "TouchEventTracer.h" +#include "Logging.h" +#include "MatrixTracer.h" +#include "unistd.h" + +#include +#include +#include +#include + +using namespace std; + +static mutex queueMutex; +static lock_guard lock(queueMutex); +static bool loopRunning = false; +static bool startDetect = false; +static int LAG_THRESHOLD; +long lastRecvTouchEventTimeStamp = 0; +static int currentFd = 0; +static int lagFd = 0; + +void reportLag() { + if (lagFd == 0) { + return; + } + onTouchEventLag(lagFd); +} + +void TouchEventTracer::touchRecv(int fd) { + currentFd = fd; + lagFd = 0; + if (lagFd == fd) { + lastRecvTouchEventTimeStamp = 0; + } else { + lastRecvTouchEventTimeStamp = time(nullptr); + queueMutex.unlock(); + } +} + +void TouchEventTracer::touchSendFinish(int fd) { + if (lagFd == fd) { + reportLag(); + } + lagFd = 0; + lastRecvTouchEventTimeStamp = 0; + startDetect = true; +} + + +void recvQueueLooper() { + queueMutex.lock(); + while (loopRunning) { + if (lastRecvTouchEventTimeStamp == 0) { + queueMutex.lock(); + } else { + long lastRecvTouchEventTimeStampNow = lastRecvTouchEventTimeStamp; + if (lastRecvTouchEventTimeStampNow <= 0) { + continue; + } + + if (time(nullptr) - lastRecvTouchEventTimeStampNow >= LAG_THRESHOLD && startDetect) { + lagFd = currentFd; + onTouchEventLagDumpTrace(currentFd); + queueMutex.lock(); + } + } + } +} + +void TouchEventTracer::start(int threshold) { + LAG_THRESHOLD = threshold / 1000; + loopRunning = true; + thread recvThread = thread(recvQueueLooper); + recvThread.detach(); +} diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.h b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.h new file mode 100644 index 000000000..1a5f9a0ff --- /dev/null +++ b/matrix/matrix-android/matrix-trace-canary/src/main/cpp/TouchEventTracer.h @@ -0,0 +1,15 @@ +// +// Created by 贾建业 on 2021/11/16. +// + +#ifndef MATRIX_ANDROID_TOUCHEVENTTRACER_H +#define MATRIX_ANDROID_TOUCHEVENTTRACER_H + +class TouchEventTracer{ +public : + static void touchRecv(int fd); + static void touchSendFinish(int fd); + static void start(int threshold); +}; + +#endif //MATRIX_ANDROID_TOUCHEVENTTRACER_H 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 7d8c893ac..319924708 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 @@ -33,6 +33,7 @@ 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; @@ -49,7 +50,9 @@ public class TracePlugin extends Plugin { private LooperAnrTracer looperAnrTracer; private SignalAnrTracer signalAnrTracer; private IdleHandlerLagTracer idleHandlerLagTracer; + private TouchEventLagTracer touchEventLagTracer; private ThreadPriorityTracer threadPriorityTracer; + private static boolean supportFrameMetrics; public TracePlugin(TraceConfig config) { this.traceConfig = config; @@ -59,15 +62,18 @@ public TracePlugin(TraceConfig config) { public void init(Application app, PluginListener listener) { super.init(app, listener); MatrixLog.i(TAG, "trace plugin init, trace config: %s", traceConfig.toString()); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + int sdkInt = Build.VERSION.SDK_INT; + if (sdkInt < Build.VERSION_CODES.JELLY_BEAN) { MatrixLog.e(TAG, "[FrameBeat] API is low Build.VERSION_CODES.JELLY_BEAN(16), TracePlugin is not supported"); unSupportPlugin(); return; + } else if (sdkInt >= Build.VERSION_CODES.O) { + supportFrameMetrics = true; } looperAnrTracer = new LooperAnrTracer(traceConfig); - frameTracer = new FrameTracer(traceConfig); + frameTracer = new FrameTracer(traceConfig, supportFrameMetrics); evilMethodTracer = new EvilMethodTracer(traceConfig); @@ -89,7 +95,7 @@ public void run() { if (willUiThreadMonitorRunning(traceConfig)) { if (!UIThreadMonitor.getMonitor().isInit()) { try { - UIThreadMonitor.getMonitor().init(traceConfig); + UIThreadMonitor.getMonitor().init(traceConfig, supportFrameMetrics); } catch (java.lang.RuntimeException e) { MatrixLog.e(TAG, "[start] RuntimeException:%s", e); return; @@ -109,11 +115,16 @@ public void run() { looperAnrTracer.onStartTrace(); } - if (traceConfig.isIdleHandlerEnable()) { + if (traceConfig.isIdleHandlerTraceEnable()) { idleHandlerLagTracer = new IdleHandlerLagTracer(traceConfig); idleHandlerLagTracer.onStartTrace(); } + if (traceConfig.isTouchEventTraceEnable()) { + touchEventLagTracer = new TouchEventLagTracer(traceConfig); + touchEventLagTracer.onStartTrace(); + } + if (traceConfig.isSignalAnrTraceEnable()) { if (!SignalAnrTracer.hasInstance) { signalAnrTracer = new SignalAnrTracer(traceConfig); @@ -148,7 +159,6 @@ public void run() { MatrixLog.w(TAG, "start TracePlugin in Thread[%s] but not in mainThread!", Thread.currentThread().getId()); MatrixHandlerThread.getDefaultMainHandler().post(runnable); } - } @Override 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 96c90da9c..18a733686 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 @@ -41,7 +41,10 @@ public class TraceConfig implements IDefaultConfig { public boolean defaultStartupEnable; public boolean defaultAppMethodBeatEnable = true; public boolean defaultAnrEnable; - public boolean defualtIdleHandlerEnable; + public boolean defaultIdleHandlerTraceEnable; + public int idleHandlerLagThreshold = Constants.DEFAULT_IDLE_HANDLER_LAG; + public int touchEventLagThreshold = Constants.DEFAULT_TOUCH_EVENT_LAG; + public boolean defaultTouchEventTraceEnable; public boolean isDebug; public boolean isDevEnv; public boolean defaultSignalAnrEnable; @@ -78,7 +81,7 @@ public String toString() { @Override public boolean isAppMethodBeatEnable() { - return defaultAppMethodBeatEnable; + return defaultMethodTraceEnable || defaultStartupEnable; } @Override @@ -121,8 +124,12 @@ public boolean isAnrTraceEnable() { } @Override - public boolean isIdleHandlerEnable() { - return defualtIdleHandlerEnable; + public boolean isIdleHandlerTraceEnable() { + return defaultIdleHandlerTraceEnable; + } + + public boolean isTouchEventTraceEnable() { + return defaultTouchEventTraceEnable; } @Override @@ -178,6 +185,13 @@ public Set getSplashActivities() { return splashActivitiesSet; } + public int getIdleHandlerLagThreshold() { + return idleHandlerLagThreshold; + } + + public int getTouchEventLagThreshold() { + return touchEventLagThreshold; + } public int getEvilThresholdMs() { return null == dynamicConfig @@ -303,8 +317,23 @@ public Builder printTracePath(String anrTraceFilePath) { return this; } - public Builder enableIdleHandlerTrace(boolean enable) { - config.defualtIdleHandlerEnable = enable; + public Builder enableIdleHandlerTraceEnable(boolean enable) { + config.defaultIdleHandlerTraceEnable = enable; + return this; + } + + public Builder setIdleHandlerThreshold(int threshold) { + config.idleHandlerLagThreshold = threshold; + return this; + } + + public Builder enableTouchEventTraceEnable(boolean enable) { + config.defaultTouchEventTraceEnable = enable; + return this; + } + + public Builder setTouchEventThreshold(int threshold) { + config.touchEventLagThreshold = threshold; return this; } diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/constants/Constants.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/constants/Constants.java index 90e17648f..0915c4af5 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/constants/Constants.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/constants/Constants.java @@ -30,10 +30,12 @@ public class Constants { public static final int DEFAULT_EVIL_METHOD_THRESHOLD_MS = 700; public static final int DEFAULT_FPS_TIME_SLICE_ALIVE_MS = 10 * 1000; public static final int TIME_MILLIS_TO_NANO = 1000000; + public static final int TIME_SECOND_TO_NANO = 1000000000; public static final int DEFAULT_INPUT_EXPIRED_TIME = 500; public static final int DEFAULT_ANR = 5 * 1000; public static final int DEFAULT_NORMAL_LAG = 2 * 1000; public static final int DEFAULT_IDLE_HANDLER_LAG = 2 * 1000; + public static final int DEFAULT_TOUCH_EVENT_LAG = 2 * 1000; public static final int DEFAULT_ANR_INVALID = 6 * 1000; public static final long DEFAULT_FRAME_DURATION = 16666667L; @@ -45,7 +47,7 @@ public class Constants { public static final int DEFAULT_STARTUP_THRESHOLD_MS_WARM = 4 * 1000; public static final int DEFAULT_STARTUP_THRESHOLD_MS_COLD = 10 * 1000; - public static final int DEFAULT_RELEASE_BUFFER_DELAY = 15 * 1000; + public static final int DEFAULT_RELEASE_BUFFER_DELAY = 10 * 1000; public static final int TARGET_EVIL_METHOD_STACK = 30; public static final int MAX_LIMIT_ANALYSE_STACK_KEY_NUM = 10; @@ -53,6 +55,6 @@ public class Constants { public enum Type { - NORMAL, ANR, STARTUP, LAG, SIGNAL_ANR, LAG_IDLE_HANDLER, PRIORITY_MODIFIED, TIMERSLACK_MODIFIED + NORMAL, ANR, STARTUP, LAG, SIGNAL_ANR, LAG_IDLE_HANDLER, LAG_TOUCH, PRIORITY_MODIFIED, TIMERSLACK_MODIFIED } } 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 2694439ee..00ab53187 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 @@ -30,7 +30,9 @@ public interface IDefaultConfig { boolean isAnrTraceEnable(); - boolean isIdleHandlerEnable(); + boolean isIdleHandlerTraceEnable(); + + boolean isTouchEventTraceEnable(); boolean isSignalAnrTraceEnable(); diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/TouchEventLagTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/TouchEventLagTracer.java new file mode 100644 index 000000000..9d0c189a0 --- /dev/null +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/TouchEventLagTracer.java @@ -0,0 +1,98 @@ +package com.tencent.matrix.trace.tracer; + +import static com.tencent.matrix.trace.constants.Constants.DEFAULT_TOUCH_EVENT_LAG; + +import androidx.annotation.Keep; + +import com.tencent.matrix.AppActiveMatrixDelegate; +import com.tencent.matrix.Matrix; +import com.tencent.matrix.report.Issue; +import com.tencent.matrix.trace.TracePlugin; +import com.tencent.matrix.trace.config.SharePluginInfo; +import com.tencent.matrix.trace.config.TraceConfig; +import com.tencent.matrix.trace.constants.Constants; +import com.tencent.matrix.trace.util.AppForegroundUtil; +import com.tencent.matrix.trace.util.Utils; +import com.tencent.matrix.util.DeviceUtil; +import com.tencent.matrix.util.MatrixHandlerThread; +import com.tencent.matrix.util.MatrixLog; + +import org.json.JSONObject; + +public class TouchEventLagTracer extends Tracer { + private static final String TAG = "Matrix.TouchEventLagTracer"; + private static TraceConfig traceConfig; + private static long lastLagTime = 0; + private static String currentLagFdStackTrace; + + static { + System.loadLibrary("trace-canary"); + } + + public TouchEventLagTracer(TraceConfig config) { + traceConfig = config; + } + + @Override + public synchronized void onAlive() { + super.onAlive(); + if (traceConfig.isTouchEventTraceEnable()) { + nativeInitTouchEventLagDetective(traceConfig.touchEventLagThreshold); + } + } + + @Override + public void onDead() { + super.onDead(); + + } + + public static native void nativeInitTouchEventLagDetective(int lagThreshold); + + @Keep + private static void onTouchEventLagDumpTrace(int fd) { + MatrixLog.e(TAG, "onTouchEventLagDumpTrace, fd = " + fd); + currentLagFdStackTrace = Utils.getMainThreadJavaStackTrace(); + } + @Keep + private static void onTouchEventLag(final int fd) { + MatrixLog.e(TAG, "onTouchEventLag, fd = " + fd); + MatrixHandlerThread.getDefaultHandler().post(new Runnable() { + @Override + public void run() { + try { + if (System.currentTimeMillis() - lastLagTime < DEFAULT_TOUCH_EVENT_LAG * 2) { + return; + } + MatrixLog.i(TAG, "onTouchEventLag report"); + + lastLagTime = System.currentTimeMillis(); + + TracePlugin plugin = Matrix.with().getPluginByClass(TracePlugin.class); + if (null == plugin) { + return; + } + + String stackTrace = currentLagFdStackTrace; + boolean currentForeground = AppForegroundUtil.isInterestingToUser(); + String scene = AppActiveMatrixDelegate.INSTANCE.getVisibleScene(); + + JSONObject jsonObject = new JSONObject(); + jsonObject = DeviceUtil.getDeviceInfo(jsonObject, Matrix.with().getApplication()); + jsonObject.put(SharePluginInfo.ISSUE_STACK_TYPE, Constants.Type.LAG_TOUCH); + jsonObject.put(SharePluginInfo.ISSUE_SCENE, scene); + jsonObject.put(SharePluginInfo.ISSUE_THREAD_STACK, stackTrace); + jsonObject.put(SharePluginInfo.ISSUE_PROCESS_FOREGROUND, currentForeground); + + Issue issue = new Issue(); + issue.setTag(SharePluginInfo.TAG_PLUGIN_EVIL_METHOD); + issue.setContent(jsonObject); + plugin.onDetectIssue(issue); + + } catch (Throwable t) { + MatrixLog.e(TAG, "Matrix error, error = " + t.getMessage()); + } + } + }); + } +} From fc821ed1d9074b358b395752b94600dff7a1772a Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 10 Dec 2021 15:05:35 +0800 Subject: [PATCH 106/163] FrameTracer use OnFrameMetricsAvailableListener on hign api level devices --- .../matrix/trace/core/UIThreadMonitor.java | 72 +++++++++++-------- .../matrix/trace/tracer/FrameTracer.java | 66 ++++++++++++----- 2 files changed, 92 insertions(+), 46 deletions(-) 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 55a8aaf44..a24462d30 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 @@ -21,6 +21,7 @@ import android.os.SystemClock; import android.view.Choreographer; +import com.tencent.matrix.AppActiveMatrixDelegate; import com.tencent.matrix.trace.config.TraceConfig; import com.tencent.matrix.trace.constants.Constants; import com.tencent.matrix.trace.listeners.LooperObserver; @@ -78,6 +79,7 @@ public class UIThreadMonitor implements BeatLifecycle, Runnable { private final static UIThreadMonitor sInstance = new UIThreadMonitor(); private TraceConfig config; + private static boolean useFrameMetrics; private Object callbackQueueLock; private Object[] callbackQueues; private Method addTraversalQueue; @@ -102,21 +104,14 @@ public boolean isInit() { return isInit; } - public void init(TraceConfig config) { + public void init(TraceConfig config, boolean supportFrameMetrics) { + this.config = config; + useFrameMetrics = supportFrameMetrics; + if (Thread.currentThread() != Looper.getMainLooper().getThread()) { throw new AssertionError("must be init in main thread!"); } - this.config = config; - choreographer = Choreographer.getInstance(); - callbackQueueLock = ReflectUtils.reflectObject(choreographer, "mLock", new Object()); - callbackQueues = ReflectUtils.reflectObject(choreographer, "mCallbackQueues", null); - if (null != callbackQueues) { - addInputQueue = ReflectUtils.reflectMethod(callbackQueues[CALLBACK_INPUT], ADD_CALLBACK, long.class, Object.class, Object.class); - addAnimationQueue = ReflectUtils.reflectMethod(callbackQueues[CALLBACK_ANIMATION], ADD_CALLBACK, long.class, Object.class, Object.class); - addTraversalQueue = ReflectUtils.reflectMethod(callbackQueues[CALLBACK_TRAVERSAL], ADD_CALLBACK, long.class, Object.class, Object.class); - } - vsyncReceiver = ReflectUtils.reflectObject(choreographer, "mDisplayEventReceiver", null); - frameIntervalNanos = ReflectUtils.reflectObject(choreographer, "mFrameIntervalNanos", Constants.DEFAULT_FRAME_DURATION); + boolean historyMsgRecorder = config.historyMsgRecorder; boolean denseMsgTracer = config.denseMsgTracer; @@ -139,19 +134,33 @@ public void dispatchEnd() { } }); - this.isInit = true; - MatrixLog.i(TAG, "[UIThreadMonitor] %s %s %s %s %s %s frameIntervalNanos:%s", callbackQueueLock == null, callbackQueues == null, - addInputQueue == null, addTraversalQueue == null, addAnimationQueue == null, vsyncReceiver == null, frameIntervalNanos); + 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) { + addInputQueue = ReflectUtils.reflectMethod(callbackQueues[CALLBACK_INPUT], ADD_CALLBACK, long.class, Object.class, Object.class); + addAnimationQueue = ReflectUtils.reflectMethod(callbackQueues[CALLBACK_ANIMATION], ADD_CALLBACK, long.class, Object.class, Object.class); + addTraversalQueue = ReflectUtils.reflectMethod(callbackQueues[CALLBACK_TRAVERSAL], ADD_CALLBACK, long.class, Object.class, Object.class); + } + vsyncReceiver = ReflectUtils.reflectObject(choreographer, "mDisplayEventReceiver", null); - if (config.isDevEnv()) { - addObserver(new LooperObserver() { - @Override - public void doFrame(String focusedActivity, long startNs, long endNs, boolean isVsyncFrame, long intendedFrameTimeNs, long inputCostNs, long animationCostNs, long traversalCostNs) { - MatrixLog.i(TAG, "focusedActivity[%s] frame cost:%sms isVsyncFrame=%s intendedFrameTimeNs=%s [%s|%s|%s]ns", - focusedActivity, (endNs - startNs) / Constants.TIME_MILLIS_TO_NANO, isVsyncFrame, intendedFrameTimeNs, inputCostNs, animationCostNs, traversalCostNs); - } - }); + + this.isInit = true; + MatrixLog.i(TAG, "[UIThreadMonitor] %s %s %s %s %s %s frameIntervalNanos:%s", callbackQueueLock == null, callbackQueues == null, + addInputQueue == null, addTraversalQueue == null, addAnimationQueue == null, vsyncReceiver == null, frameIntervalNanos); + + if (config.isDevEnv()) { + addObserver(new LooperObserver() { + @Override + public void doFrame(String focusedActivity, long startNs, long endNs, boolean isVsyncFrame, long intendedFrameTimeNs, long inputCostNs, long animationCostNs, long traversalCostNs) { + MatrixLog.i(TAG, "focusedActivity[%s] frame cost:%sms isVsyncFrame=%s intendedFrameTimeNs=%s [%s|%s|%s]ns", + focusedActivity, (endNs - startNs) / Constants.TIME_MILLIS_TO_NANO, isVsyncFrame, intendedFrameTimeNs, inputCostNs, animationCostNs, traversalCostNs); + } + }); + } } } @@ -214,8 +223,9 @@ public void removeObserver(LooperObserver observer) { private void dispatchBegin() { token = dispatchTimeMs[0] = System.nanoTime(); dispatchTimeMs[2] = SystemClock.currentThreadTimeMillis(); - AppMethodBeat.i(AppMethodBeat.METHOD_ID_DISPATCH); - + if (config.isAppMethodBeatEnable()) { + AppMethodBeat.i(AppMethodBeat.METHOD_ID_DISPATCH); + } synchronized (observers) { for (LooperObserver observer : observers) { if (!observer.isDispatchBegin()) { @@ -256,7 +266,7 @@ private void dispatchEnd() { traceBegin = System.nanoTime(); } - if (config.isFPSEnable()) { + if (config.isFPSEnable() && !useFrameMetrics) { long startNs = token; long intendedFrameTimeNs = startNs; if (isVsyncFrame) { @@ -269,7 +279,7 @@ private void dispatchEnd() { synchronized (observers) { for (LooperObserver observer : observers) { if (observer.isDispatchBegin()) { - observer.doFrame(AppMethodBeat.getVisibleScene(), startNs, endNs, isVsyncFrame, intendedFrameTimeNs, queueCost[CALLBACK_INPUT], queueCost[CALLBACK_ANIMATION], queueCost[CALLBACK_TRAVERSAL]); + observer.doFrame(AppActiveMatrixDelegate.INSTANCE.getVisibleScene(), startNs, endNs, isVsyncFrame, intendedFrameTimeNs, queueCost[CALLBACK_INPUT], queueCost[CALLBACK_ANIMATION], queueCost[CALLBACK_TRAVERSAL]); } } } @@ -322,9 +332,11 @@ public synchronized void onStart() { MatrixLog.i(TAG, "[onStart] callbackExist:%s %s", Arrays.toString(callbackExist), Utils.getStack()); callbackExist = new boolean[CALLBACK_LAST + 1]; } - queueStatus = new int[CALLBACK_LAST + 1]; - queueCost = new long[CALLBACK_LAST + 1]; - addFrameCallback(CALLBACK_INPUT, this, true); + if (!useFrameMetrics) { + queueStatus = new int[CALLBACK_LAST + 1]; + queueCost = new long[CALLBACK_LAST + 1]; + addFrameCallback(CALLBACK_INPUT, this, true); + } } } diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/FrameTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/FrameTracer.java index e8d9499a2..35e1adfce 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/FrameTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/FrameTracer.java @@ -18,9 +18,14 @@ import android.app.Activity; import android.app.Application; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; +import android.view.FrameMetrics; +import android.view.Window; + +import androidx.annotation.RequiresApi; import com.tencent.matrix.AppActiveMatrixDelegate; import com.tencent.matrix.Matrix; @@ -49,12 +54,14 @@ public class FrameTracer extends Tracer implements Application.ActivityLifecycleCallbacks { private static final String TAG = "Matrix.FrameTracer"; + private static boolean useFrameMetrics; private final HashSet listeners = new HashSet<>(); private DropFrameListener dropFrameListener; private int dropFrameListenerThreshold = 0; - private final long frameIntervalNs; + private long frameIntervalNs; + private int refreshRate; private final TraceConfig config; - private long timeSliceMs; + private final long timeSliceMs; private boolean isFPSEnable; private long frozenThreshold; private long highThreshold; @@ -63,8 +70,10 @@ public class FrameTracer extends Tracer implements Application.ActivityLifecycle private int droppedSum = 0; private long durationSum = 0; private Map lastResumeTimeMap = new HashMap<>(); + private Map frameListenerMap = new HashMap<>(); - public FrameTracer(TraceConfig config) { + public FrameTracer(TraceConfig config, boolean supportFrameMetrics) { + useFrameMetrics = supportFrameMetrics; this.config = config; this.frameIntervalNs = UIThreadMonitor.getMonitor().getFrameIntervalNanos(); this.timeSliceMs = config.getTimeSliceMs(); @@ -96,7 +105,9 @@ public void removeListener(IDoFrameListener listener) { public void onAlive() { super.onAlive(); if (isFPSEnable) { - UIThreadMonitor.getMonitor().addObserver(this); + if (!useFrameMetrics) { + UIThreadMonitor.getMonitor().addObserver(this); + } Matrix.with().getApplication().registerActivityLifecycleCallbacks(this); } } @@ -130,14 +141,14 @@ private void notifyListener(final String focusedActivity, final long startNs, fi final long intendedFrameTimeNs, final long inputCostNs, final long animationCostNs, final long traversalCostNs) { long traceBegin = System.currentTimeMillis(); try { - final long jiter = endNs - intendedFrameTimeNs; - final int dropFrame = (int) (jiter / frameIntervalNs); + final long jitter = endNs - intendedFrameTimeNs; + final int dropFrame = (int) (jitter / frameIntervalNs); if (dropFrameListener != null) { if (dropFrame > dropFrameListenerThreshold) { try { if (AppActiveMatrixDelegate.getTopActivityName() != null) { long lastResumeTime = lastResumeTimeMap.get(AppActiveMatrixDelegate.getTopActivityName()); - dropFrameListener.dropFrame(dropFrame, AppActiveMatrixDelegate.getTopActivityName(), lastResumeTime); + dropFrameListener.dropFrame(dropFrame, jitter, AppActiveMatrixDelegate.getTopActivityName(), lastResumeTime); } } catch (Exception e) { MatrixLog.e(TAG, "dropFrameListener error e:" + e.getMessage()); @@ -146,7 +157,7 @@ private void notifyListener(final String focusedActivity, final long startNs, fi } droppedSum += dropFrame; - durationSum += Math.max(jiter, frameIntervalNs); + durationSum += Math.max(jitter, frameIntervalNs); synchronized (listeners) { for (final IDoFrameListener listener : listeners) { @@ -232,7 +243,6 @@ public void doReplayInner(String visibleScene, long startNs, long endNs, int dro } item.collect(droppedFrames); - if (item.sumFrameCost >= timeSliceMs) { // report map.remove(visibleScene); item.report(); @@ -254,7 +264,7 @@ private class FrameCollectItem { } void collect(int droppedFrames) { - float frameIntervalCost = 1f * UIThreadMonitor.getMonitor().getFrameIntervalNanos() + float frameIntervalCost = 1f * FrameTracer.this.frameIntervalNs / Constants.TIME_MILLIS_TO_NANO; sumFrameCost += (droppedFrames + 1) * frameIntervalCost; sumDroppedFrames += droppedFrames; @@ -278,9 +288,8 @@ void collect(int droppedFrames) { } void report() { - float fps = Math.min(60.f, 1000.f * sumFrame / sumFrameCost); + float fps = Math.min(refreshRate, 1000.f * sumFrame / sumFrameCost); MatrixLog.i(TAG, "[report] FPS:%s %s", fps, toString()); - try { TracePlugin plugin = Matrix.with().getPluginByClass(TracePlugin.class); if (null == plugin) { @@ -353,12 +362,30 @@ public void removeDropFrameListener() { } public interface DropFrameListener { - void dropFrame(int dropedFrame, String scene, long lastResume); + void dropFrame(int droppedFrame, long jitter, String scene, long lastResume); } + @RequiresApi(api = Build.VERSION_CODES.N) @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - + public void onActivityCreated(final Activity activity, Bundle savedInstanceState) { + if (useFrameMetrics) { + this.refreshRate = (int) activity.getWindowManager().getDefaultDisplay().getRefreshRate(); + this.frameIntervalNs = Constants.TIME_SECOND_TO_NANO / (long) refreshRate; + Window.OnFrameMetricsAvailableListener onFrameMetricsAvailableListener = new Window.OnFrameMetricsAvailableListener() { + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCountSinceLastInvocation) { + FrameMetrics frameMetricsCopy = new FrameMetrics(frameMetrics); + long vsynTime = frameMetricsCopy.getMetric(FrameMetrics.VSYNC_TIMESTAMP); + long intendedVsyncTime = frameMetricsCopy.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP); + frameMetricsCopy.getMetric(FrameMetrics.DRAW_DURATION); + notifyListener(AppActiveMatrixDelegate.INSTANCE.getVisibleScene(), intendedVsyncTime, vsynTime, true, intendedVsyncTime, 0, 0, 0); + } + }; + this.frameListenerMap.put(activity.hashCode(), onFrameMetricsAvailableListener); + activity.getWindow().addOnFrameMetricsAvailableListener(onFrameMetricsAvailableListener, new Handler()); + MatrixLog.i(TAG, "onActivityCreated addOnFrameMetricsAvailableListener"); + } } @Override @@ -386,8 +413,15 @@ public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } + @RequiresApi(api = Build.VERSION_CODES.N) @Override public void onActivityDestroyed(Activity activity) { - + if (useFrameMetrics) { + try { + activity.getWindow().removeOnFrameMetricsAvailableListener(frameListenerMap.remove(activity.hashCode())); + } catch (Throwable t) { + MatrixLog.e(TAG, "removeOnFrameMetricsAvailableListener error : " + t.getMessage()); + } + } } } From de8cbb7392d4a3845444a11e3e4cb28f08d08ac3 Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 10 Dec 2021 15:06:44 +0800 Subject: [PATCH 107/163] Fix sBuffer can not be released --- .../matrix/trace/core/AppMethodBeat.java | 45 +++++++++++-------- .../matrix/trace/tracer/EvilMethodTracer.java | 3 +- .../matrix/trace/tracer/LooperAnrTracer.java | 7 +-- .../matrix/trace/tracer/SignalAnrTracer.java | 4 +- 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/core/AppMethodBeat.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/core/AppMethodBeat.java index 38e512f4c..1a326874b 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/core/AppMethodBeat.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/core/AppMethodBeat.java @@ -86,14 +86,15 @@ public void dispatchEnd() { AppMethodBeat.dispatchEnd(); } }; + private static Runnable realReleaseRunnable = new Runnable() { + @Override + public void run() { + realRelease(); + } + }; static { - sHandler.postDelayed(new Runnable() { - @Override - public void run() { - realRelease(); - } - }, Constants.DEFAULT_RELEASE_BUFFER_DELAY); + MatrixHandlerThread.getDefaultHandler().postDelayed(realReleaseRunnable, Constants.DEFAULT_RELEASE_BUFFER_DELAY); } /** @@ -127,6 +128,7 @@ public void onStart() { synchronized (statusLock) { if (status < STATUS_STARTED && status >= STATUS_EXPIRED_START) { sHandler.removeCallbacks(checkStartExpiredRunnable); + MatrixHandlerThread.getDefaultHandler().removeCallbacks(realReleaseRunnable); if (sBuffer == null) { throw new RuntimeException(TAG + " sBuffer == null"); } @@ -168,7 +170,7 @@ public static boolean isRealTrace() { private static void realRelease() { synchronized (statusLock) { - if (status == STATUS_DEFAULT) { + if (status == STATUS_DEFAULT || status <= STATUS_READY) { MatrixLog.i(TAG, "[realRelease] timestamp:%s", System.currentTimeMillis()); sHandler.removeCallbacksAndMessages(null); LooperMonitor.unregister(looperMonitorListener); @@ -181,7 +183,6 @@ private static void realRelease() { private static void realExecute() { MatrixLog.i(TAG, "[realExecute] timestamp:%s", System.currentTimeMillis()); - sCurrentDiffTime = SystemClock.uptimeMillis() - sDiffTime; sHandler.removeCallbacksAndMessages(null); @@ -253,7 +254,7 @@ public static void i(int methodId) { mergeData(methodId, sIndex, true); } else { sIndex = 0; - mergeData(methodId, sIndex, true); + mergeData(methodId, sIndex, true); } ++sIndex; assertIn = false; @@ -324,15 +325,20 @@ private static void mergeData(int methodId, int index, boolean isIn) { if (methodId == AppMethodBeat.METHOD_ID_DISPATCH) { sCurrentDiffTime = SystemClock.uptimeMillis() - sDiffTime; } - long trueId = 0L; - if (isIn) { - trueId |= 1L << 63; + + try { + long trueId = 0L; + if (isIn) { + trueId |= 1L << 63; + } + trueId |= (long) methodId << 43; + trueId |= sCurrentDiffTime & 0x7FFFFFFFFFFL; + sBuffer[index] = trueId; + checkPileup(index); + sLastIndex = index; + } catch (Throwable t) { + MatrixLog.e(TAG, t.getMessage()); } - trueId |= (long) methodId << 43; - trueId |= sCurrentDiffTime & 0x7FFFFFFFFFFL; - sBuffer[index] = trueId; - checkPileup(index); - sLastIndex = index; } public void addListener(IAppMethodBeatListener listener) { @@ -359,6 +365,7 @@ public IndexRecord maskIndex(String source) { indexRecord.source = source; IndexRecord record = sIndexRecordHead; IndexRecord last = null; + while (record != null) { if (indexRecord.index <= record.index) { if (null == last) { @@ -459,8 +466,8 @@ private long[] copyData(IndexRecord startRecord, IndexRecord endRecord) { return data; } return data; - } catch (OutOfMemoryError e) { - MatrixLog.e(TAG, e.toString()); + } catch (Throwable t) { + MatrixLog.e(TAG, t.toString()); return data; } finally { MatrixLog.i(TAG, "[copyData] [%s:%s] length:%s cost:%sms", Math.max(0, startRecord.index), endRecord.index, data.length, System.currentTimeMillis() - current); diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/EvilMethodTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/EvilMethodTracer.java index 81578f9ca..70fad2d2b 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/EvilMethodTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/EvilMethodTracer.java @@ -18,6 +18,7 @@ import android.os.Process; +import com.tencent.matrix.AppActiveMatrixDelegate; import com.tencent.matrix.Matrix; import com.tencent.matrix.report.Issue; import com.tencent.matrix.trace.TracePlugin; @@ -97,7 +98,7 @@ public void dispatchEnd(long beginNs, long cpuBeginMs, long endNs, long cpuEndMs long[] data = AppMethodBeat.getInstance().copyData(indexRecord); long[] queueCosts = new long[3]; System.arraycopy(queueTypeCosts, 0, queueCosts, 0, 3); - String scene = AppMethodBeat.getVisibleScene(); + String scene = AppActiveMatrixDelegate.INSTANCE.getVisibleScene(); MatrixHandlerThread.getDefaultHandler().post(new AnalyseTask(isForeground(), scene, data, queueCosts, cpuEndMs - cpuBeginMs, dispatchCost, endNs / Constants.TIME_MILLIS_TO_NANO)); } } finally { diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/LooperAnrTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/LooperAnrTracer.java index 9d17b80b5..fb3ac3cf7 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/LooperAnrTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/LooperAnrTracer.java @@ -21,6 +21,7 @@ import android.os.Process; import android.os.SystemClock; +import com.tencent.matrix.AppActiveMatrixDelegate; import com.tencent.matrix.Matrix; import com.tencent.matrix.report.Issue; import com.tencent.matrix.trace.TracePlugin; @@ -119,7 +120,7 @@ class LagHandleTask implements Runnable { @Override public void run() { - String scene = AppMethodBeat.getVisibleScene(); + String scene = AppActiveMatrixDelegate.INSTANCE.getVisibleScene(); boolean isForeground = isForeground(); try { TracePlugin plugin = Matrix.with().getPluginByClass(TracePlugin.class); @@ -176,7 +177,7 @@ public void run() { int[] processStat = Utils.getProcessPriority(Process.myPid()); long[] data = AppMethodBeat.getInstance().copyData(beginRecord); beginRecord.release(); - String scene = AppMethodBeat.getVisibleScene(); + String scene = AppActiveMatrixDelegate.INSTANCE.getVisibleScene(); // memory long[] memoryInfo = dumpMemory(); @@ -315,7 +316,7 @@ private String printAnr(String scene, int[] processStat, long[] memoryInfo, Thre private String printInputExpired(long inputCost) { StringBuilder print = new StringBuilder(); - String scene = AppMethodBeat.getVisibleScene(); + String scene = AppActiveMatrixDelegate.INSTANCE.getVisibleScene(); boolean isForeground = isForeground(); // memory long[] memoryInfo = dumpMemory(); 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 d95491639..62ef327dd 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 @@ -28,13 +28,13 @@ import androidx.annotation.Keep; import androidx.annotation.RequiresApi; +import com.tencent.matrix.AppActiveMatrixDelegate; import com.tencent.matrix.Matrix; import com.tencent.matrix.report.Issue; import com.tencent.matrix.trace.TracePlugin; import com.tencent.matrix.trace.config.SharePluginInfo; import com.tencent.matrix.trace.config.TraceConfig; import com.tencent.matrix.trace.constants.Constants; -import com.tencent.matrix.trace.core.AppMethodBeat; import com.tencent.matrix.trace.util.AppForegroundUtil; import com.tencent.matrix.trace.util.Utils; import com.tencent.matrix.util.DeviceUtil; @@ -160,7 +160,7 @@ private static void report(boolean fromProcessErrorState) { return; } - String scene = AppMethodBeat.getVisibleScene(); + String scene = AppActiveMatrixDelegate.INSTANCE.getVisibleScene(); JSONObject jsonObject = new JSONObject(); jsonObject = DeviceUtil.getDeviceInfo(jsonObject, Matrix.with().getApplication()); From ac5163ef87e6188ca1c2cdf2e091226e9a8c1bcc Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 10 Dec 2021 15:08:00 +0800 Subject: [PATCH 108/163] CMakeLists add TouchEventTracer.cc --- matrix/matrix-android/matrix-trace-canary/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix/matrix-android/matrix-trace-canary/CMakeLists.txt b/matrix/matrix-android/matrix-trace-canary/CMakeLists.txt index 9317c6435..887cc2061 100644 --- a/matrix/matrix-android/matrix-trace-canary/CMakeLists.txt +++ b/matrix/matrix-android/matrix-trace-canary/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(trace-canary src/main/cpp/SignalHandler.cc src/main/cpp/Support.cc src/main/cpp/AnrDumper.cc + src/main/cpp/TouchEventTracer.cc src/main/cpp/nativehelper/managed_jnienv.cc ) @@ -23,7 +24,7 @@ find_library( log-lib target_link_libraries( trace-canary PRIVATE ${log-lib} PRIVATE ${EXT_DEP}/lib/${ANDROID_ABI}/libxhook.a - ) + ) set_target_properties(trace-canary PROPERTIES CXX_STANDARD_REQUIRED ON From 36b178ef5d1e5de5995e99d4d9d47a83bab1f6e3 Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 10 Dec 2021 15:10:12 +0800 Subject: [PATCH 109/163] Fix IdleHandlerLagTracer --- .../trace/tracer/IdleHandlerLagTracer.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/IdleHandlerLagTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/IdleHandlerLagTracer.java index 7a005ce91..4ebbdcbd8 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/IdleHandlerLagTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/IdleHandlerLagTracer.java @@ -23,13 +23,13 @@ import androidx.annotation.Nullable; +import com.tencent.matrix.AppActiveMatrixDelegate; import com.tencent.matrix.Matrix; import com.tencent.matrix.report.Issue; import com.tencent.matrix.trace.TracePlugin; import com.tencent.matrix.trace.config.SharePluginInfo; import com.tencent.matrix.trace.config.TraceConfig; import com.tencent.matrix.trace.constants.Constants; -import com.tencent.matrix.trace.core.AppMethodBeat; import com.tencent.matrix.trace.util.AppForegroundUtil; import com.tencent.matrix.trace.util.Utils; import com.tencent.matrix.util.DeviceUtil; @@ -44,22 +44,22 @@ public class IdleHandlerLagTracer extends Tracer { - private static final String TAG = "Matrix.AnrTracer"; - private final TraceConfig traceConfig; + private static final String TAG = "Matrix.IdleHandlerLagTracer"; + private static TraceConfig traceConfig; private static HandlerThread idleHandlerLagHandlerThread; private static Handler idleHandlerLagHandler; - private static Runnable idleHanlderLagRunnable; + private static Runnable idleHandlerLagRunnable; - public IdleHandlerLagTracer(TraceConfig traceConfig) { - this.traceConfig = traceConfig; + public IdleHandlerLagTracer(TraceConfig config) { + traceConfig = config; } @Override public void onAlive() { super.onAlive(); - if (traceConfig.isIdleHandlerEnable()) { + if (traceConfig.isIdleHandlerTraceEnable()) { idleHandlerLagHandlerThread = new HandlerThread("IdleHandlerLagThread"); - idleHanlderLagRunnable = new IdleHandlerLagRunable(); + idleHandlerLagRunnable = new IdleHandlerLagRunable(); detectIdleHandler(); } } @@ -67,7 +67,7 @@ public void onAlive() { @Override public void onDead() { super.onDead(); - if (traceConfig.isIdleHandlerEnable()) { + if (traceConfig.isIdleHandlerTraceEnable()) { idleHandlerLagHandler.removeCallbacksAndMessages(null); } } @@ -83,7 +83,7 @@ public void run() { String stackTrace = Utils.getMainThreadJavaStackTrace(); boolean currentForeground = AppForegroundUtil.isInterestingToUser(); - String scene = AppMethodBeat.getVisibleScene(); + String scene = AppActiveMatrixDelegate.INSTANCE.getVisibleScene(); JSONObject jsonObject = new JSONObject(); jsonObject = DeviceUtil.getDeviceInfo(jsonObject, Matrix.with().getApplication()); @@ -125,7 +125,7 @@ private static void detectIdleHandler() { static class MyIdleHandler implements MessageQueue.IdleHandler { - private MessageQueue.IdleHandler idleHandler; + private final MessageQueue.IdleHandler idleHandler; MyIdleHandler(MessageQueue.IdleHandler idleHandler) { this.idleHandler = idleHandler; @@ -133,9 +133,9 @@ static class MyIdleHandler implements MessageQueue.IdleHandler { @Override public boolean queueIdle() { - idleHandlerLagHandler.postDelayed(idleHanlderLagRunnable, Constants.DEFAULT_IDLE_HANDLER_LAG); + idleHandlerLagHandler.postDelayed(idleHandlerLagRunnable, traceConfig.idleHandlerLagThreshold); boolean ret = this.idleHandler.queueIdle(); - idleHandlerLagHandler.removeCallbacks(idleHanlderLagRunnable); + idleHandlerLagHandler.removeCallbacks(idleHandlerLagRunnable); return ret; } } From 99794ced842ffd7a05c27931697340c0446cc284 Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 10 Dec 2021 15:11:18 +0800 Subject: [PATCH 110/163] MatrixTraffic supports dump stack trace --- .../src/main/cpp/MatrixTraffic.cc | 43 +++++++++++++++++-- .../src/main/cpp/MatrixTraffic.h | 2 + .../src/main/cpp/TrafficCollector.cc | 30 +++++++++++-- .../src/main/cpp/TrafficCollector.h | 5 ++- .../tencent/matrix/traffic/TrafficConfig.java | 12 +++++- .../tencent/matrix/traffic/TrafficPlugin.java | 28 ++++++++++-- 6 files changed, 106 insertions(+), 14 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 760a5ee52..a3f06273c 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -34,6 +34,12 @@ using namespace std; using namespace MatrixTraffic; static bool HOOKED = false; +static struct StacktraceJNI { + jclass TrafficPlugin; + jmethodID TrafficPlugin_setFdStackTrace; +} gJ; + + 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); @@ -95,6 +101,12 @@ ssize_t my_sendmsg(int sockfd, const struct msghdr *msg, int flags) { return original_sendmsg(sockfd, msg, flags); } +int (*original_close)(int fd); +int my_close(int fd) { + TrafficCollector::enQueueClose(fd); + return original_close(fd); +} + static jobject nativeGetTrafficInfoMap(JNIEnv *env, jclass, jint type) { return TrafficCollector::getTrafficInfoMap(type); } @@ -110,6 +122,14 @@ static void nativeClearTrafficInfo(JNIEnv *env, jclass) { TrafficCollector::clearTrafficInfo(); } +void setStackTrace(char* threadName) { + JNIEnv *env = JniInvocation::getEnv(); + if (!env) return; + jstring jThreadName = env->NewStringUTF(threadName); + env->CallStaticVoidMethod(gJ.TrafficPlugin, gJ.TrafficPlugin_setFdStackTrace, jThreadName); + env->DeleteLocalRef(jThreadName); +} + static void hookSocket(bool rxHook, bool txHook) { if (HOOKED) { return; @@ -118,6 +138,9 @@ static void hookSocket(bool rxHook, bool txHook) { 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)); + if (rxHook) { xhook_grouped_register(HOOK_REQUEST_GROUPID_TRAFFIC, ".*\\.so$", "read", (void *) my_read, (void **) (&original_read)); @@ -154,14 +177,23 @@ static void hookSocket(bool rxHook, bool txHook) { 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, ".*libtraffic-collector\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libbinder\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libGLES_mali\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libhwui\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libEGL\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libwcdb\\.so$", nullptr); + 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, ".*libwechatxlog\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libmmkv\\.so$", nullptr); xhook_refresh(true); HOOKED = true; } -static void nativeInitMatrixTraffic(JNIEnv *env, jclass, jboolean rxEnable, jboolean txEnable) { - TrafficCollector::startLoop(); +static void nativeInitMatrixTraffic(JNIEnv *env, jclass, jboolean rxEnable, jboolean txEnable, jboolean dumpStackTrace) { + TrafficCollector::startLoop(dumpStackTrace == JNI_TRUE); hookSocket(rxEnable == JNI_TRUE, txEnable == JNI_TRUE); } @@ -169,7 +201,7 @@ template static inline constexpr std::size_t NELEM(const T(&)[sz]) { return sz; } static const JNINativeMethod TRAFFIC_METHODS[] = { - {"nativeInitMatrixTraffic", "(ZZ)V", (void *) nativeInitMatrixTraffic}, + {"nativeInitMatrixTraffic", "(ZZZ)V", (void *) nativeInitMatrixTraffic}, {"nativeGetTrafficInfoMap", "(I)Ljava/util/HashMap;", (void *) nativeGetTrafficInfoMap}, {"nativeClearTrafficInfo", "()V", (void *) nativeClearTrafficInfo}, {"nativeReleaseMatrixTraffic", "()V", (void *) nativeReleaseMatrixTraffic}, @@ -185,6 +217,9 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { jclass trafficCollectorCls = env->FindClass("com/tencent/matrix/traffic/TrafficPlugin"); if (!trafficCollectorCls) return -1; + gJ.TrafficPlugin = static_cast(env->NewGlobalRef(trafficCollectorCls)); + gJ.TrafficPlugin_setFdStackTrace = + env->GetStaticMethodID(trafficCollectorCls, "setStackTrace", "(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 71634bda2..dd83748c2 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.h @@ -21,4 +21,6 @@ #ifndef MATRIX_ANDROID_MATRIXTRAFFIC_H #define MATRIX_ANDROID_MATRIXTRAFFIC_H +void setStackTrace(char* threadName); + #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 e3e506a83..f1ca16f14 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.cc @@ -25,6 +25,7 @@ #include #include #include +#include "MatrixTraffic.h" #include #include @@ -36,6 +37,7 @@ namespace MatrixTraffic { static mutex queueMutex; static lock_guard lock(queueMutex); static bool loopRunning = false; +static bool sDumpStackTrace = false; static map fdFamilyMap; static blocking_queue> msgQueue; static map rxTrafficInfoMap; @@ -46,13 +48,16 @@ static mutex txTrafficInfoMapLock; static map fdThreadNameMap; static mutex fdThreadNameMapLock; -string getThreadName(int fd) { +string getThreadNameAndSaveStack(int fd) { fdThreadNameMapLock.lock(); if (fdThreadNameMap.count(fd) == 0) { auto threadName = new char[15]; prctl(PR_GET_NAME, threadName); fdThreadNameMap[fd] = threadName; fdThreadNameMapLock.unlock(); + if (sDumpStackTrace) { + setStackTrace(threadName); + } return threadName; } else { auto threadName = fdThreadNameMap[fd]; @@ -65,7 +70,17 @@ void TrafficCollector::enQueueConnect(int fd, sockaddr *addr, socklen_t addr_len if (!loopRunning) { return; } - shared_ptr msg = make_shared(MSG_TYPE_CONNECT, fd, addr->sa_family, getThreadName(fd), 0); + + shared_ptr msg = make_shared(MSG_TYPE_CONNECT, fd, addr->sa_family, getThreadNameAndSaveStack(fd), 0); + msgQueue.push(msg); + queueMutex.unlock(); +} + +void TrafficCollector::enQueueClose(int fd) { + if (!loopRunning) { + return; + } + shared_ptr msg = make_shared(MSG_TYPE_CLOSE, fd, 0, "", 0); msgQueue.push(msg); queueMutex.unlock(); } @@ -74,7 +89,8 @@ void enQueueMsg(int type, int fd, size_t len) { if (!loopRunning) { return; } - shared_ptr msg = make_shared(type, fd, 0, getThreadName(fd), len); + + shared_ptr msg = make_shared(type, fd, 0, getThreadNameAndSaveStack(fd), len); msgQueue.push(msg); queueMutex.unlock(); } @@ -129,6 +145,11 @@ void loop() { if (fdFamilyMap[msg->fd] != AF_LOCAL) { appendTxTraffic(msg->threadName, msg->len); } + } else if (msg->type == MSG_TYPE_CLOSE) { + fdThreadNameMapLock.lock(); + fdThreadNameMap.erase(msg->fd); + fdThreadNameMapLock.unlock(); + fdFamilyMap.erase(msg->fd); } msgQueue.pop(); } @@ -136,7 +157,8 @@ void loop() { } -void TrafficCollector::startLoop() { +void TrafficCollector::startLoop(bool dumpStackTrace) { + sDumpStackTrace = dumpStackTrace; loopRunning = true; thread loopThread(loop); loopThread.detach(); 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 e46e98e2c..36920a1e9 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/TrafficCollector.h @@ -43,6 +43,7 @@ #define MSG_TYPE_SENDTO 22 #define MSG_TYPE_SENDMSG 23 +#define MSG_TYPE_CLOSE 30 #define TYPE_GET_TRAFFIC_RX 0 #define TYPE_GET_TRAFFIC_TX 1 @@ -65,12 +66,14 @@ class TrafficMsg { class TrafficCollector { public : - static void startLoop(); + static void startLoop(bool dumpStackTrace); static void stopLoop(); 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); static void enQueueRx(int type, int fd, size_t len); 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 68b012ba2..7ac6bee7b 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 @@ -3,13 +3,15 @@ public class TrafficConfig { private boolean rxCollectorEnable; private boolean txCollectorEnable; + private boolean dumpStackTrace; public TrafficConfig() { } - public TrafficConfig(boolean rxCollectorEnable, boolean txCollectorEnable) { + public TrafficConfig(boolean rxCollectorEnable, boolean txCollectorEnable, boolean dumpStackTrace) { this.rxCollectorEnable = rxCollectorEnable; this.txCollectorEnable = txCollectorEnable; + this.dumpStackTrace = dumpStackTrace; } public boolean isRxCollectorEnable() { @@ -25,4 +27,12 @@ public boolean isTxCollectorEnable() { public void setTxCollectorEnable(boolean txCollectorEnable) { this.txCollectorEnable = txCollectorEnable; } + + public boolean willDumpStackTrace() { + return dumpStackTrace; + } + + public void setDumpStackTrace(boolean dumpStackTrace) { + this.dumpStackTrace = dumpStackTrace; + } } 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 bbfb7d939..c0f8ac250 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 @@ -1,15 +1,22 @@ package com.tencent.matrix.traffic; +import androidx.annotation.Keep; + import com.tencent.matrix.plugin.Plugin; +import com.tencent.matrix.util.MatrixLog; import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; public class TrafficPlugin extends Plugin { + private static final String TAG = "TrafficPlugin"; final private TrafficConfig trafficConfig; 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<>(); + //TODO will be done in next upgrade //public static final int TYPE_GET_TRAFFIC_ALL = 2; @@ -27,7 +34,8 @@ public void start() { return; } super.start(); - nativeInitMatrixTraffic(trafficConfig.isRxCollectorEnable(), trafficConfig.isTxCollectorEnable()); + MatrixLog.i(TAG, "start"); + nativeInitMatrixTraffic(trafficConfig.isRxCollectorEnable(), trafficConfig.isTxCollectorEnable(), trafficConfig.willDumpStackTrace()); } @@ -44,11 +52,17 @@ public void stop() { public HashMap getTrafficInfoMap(int type) { return nativeGetTrafficInfoMap(type); } + + public ConcurrentHashMap getStackTraceMap() { + return stackTraceMap; + } + public void clearTrafficInfo() { + stackTraceMap.clear(); nativeClearTrafficInfo(); } - private static native void nativeInitMatrixTraffic(boolean rxEnable, boolean txEnable); + private static native void nativeInitMatrixTraffic(boolean rxEnable, boolean txEnable, boolean dumpStackTrace); private static native String nativeGetTrafficInfo(); private static native String nativeGetAllStackTraceTrafficInfo(); private static native void nativeReleaseMatrixTraffic(); @@ -56,11 +70,17 @@ public void clearTrafficInfo() { private static native void nativeClearTrafficInfo(); private static native HashMap nativeGetTrafficInfoMap(int type); - public static String getJavaStackTrace() { + @Keep + private static void setStackTrace(String threadName) { + MatrixLog.i(TAG, "setStackTrace, threadName = " + threadName); StringBuilder stackTrace = new StringBuilder(); for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) { stackTrace.append(stackTraceElement.toString()).append("\n"); } - return stackTrace.toString(); + stackTraceMap.put(threadName, stackTrace.toString()); + } + + public void clearStackTrace() { + stackTraceMap.clear(); } } From 6443d907f968df7176362e853e613782e1e38060 Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 10 Dec 2021 16:23:43 +0800 Subject: [PATCH 111/163] ignore liblog.so --- .../matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc | 1 + 1 file changed, 1 insertion(+) 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 a3f06273c..345bf6c74 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -187,6 +187,7 @@ static void hookSocket(bool rxHook, bool txHook) { xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libartbase\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libwechatxlog\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libmmkv\\.so$", nullptr); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*liblog\\.so$", nullptr); xhook_refresh(true); HOOKED = true; From c78e34f5027ab51b67d8a58e887cd1dd297ece85 Mon Sep 17 00:00:00 2001 From: leafjia Date: Fri, 10 Dec 2021 16:29:03 +0800 Subject: [PATCH 112/163] remove unused code --- .../matrix/trace/tracer/FrameTracer.java | 2 +- .../trace/tracer/IdleHandlerLagTracer.java | 2 +- .../matrix/trace/tracer/LooperAnrTracer.java | 18 ++++++------------ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/FrameTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/FrameTracer.java index 35e1adfce..d6297c057 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/FrameTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/FrameTracer.java @@ -362,7 +362,7 @@ public void removeDropFrameListener() { } public interface DropFrameListener { - void dropFrame(int droppedFrame, long jitter, String scene, long lastResume); + void dropFrame(int droppedFrame, long jitter, String scene, long lastResumeTime); } @RequiresApi(api = Build.VERSION_CODES.N) diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/IdleHandlerLagTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/IdleHandlerLagTracer.java index 4ebbdcbd8..a6137be4e 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/IdleHandlerLagTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/IdleHandlerLagTracer.java @@ -119,7 +119,7 @@ private static void detectIdleHandler() { idleHandlerLagHandlerThread.start(); idleHandlerLagHandler = new Handler(idleHandlerLagHandlerThread.getLooper()); } catch (Throwable t) { - t.printStackTrace(); + MatrixLog.e(TAG, "reflect idle handler error = " + t.getMessage()); } } diff --git a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/LooperAnrTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/LooperAnrTracer.java index fb3ac3cf7..9ffa2b345 100644 --- a/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/LooperAnrTracer.java +++ b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/LooperAnrTracer.java @@ -50,8 +50,8 @@ public class LooperAnrTracer extends Tracer { private Handler anrHandler; private Handler lagHandler; private final TraceConfig traceConfig; - private volatile AnrHandleTask anrTask = new AnrHandleTask(); - private volatile LagHandleTask lagTask = new LagHandleTask(); + private final AnrHandleTask anrTask = new AnrHandleTask(); + private final LagHandleTask lagTask = new LagHandleTask(); private boolean isAnrTraceEnable; public LooperAnrTracer(TraceConfig traceConfig) { @@ -74,9 +74,7 @@ public void onDead() { super.onDead(); if (isAnrTraceEnable) { UIThreadMonitor.getMonitor().removeObserver(this); - if (null != anrTask) { - anrTask.getBeginRecord().release(); - } + anrTask.getBeginRecord().release(); anrHandler.removeCallbacksAndMessages(null); lagHandler.removeCallbacksAndMessages(null); } @@ -107,13 +105,9 @@ public void dispatchEnd(long beginNs, long cpuBeginMs, long endNs, long cpuEndMs token, cost, cpuEndMs - cpuBeginMs, Utils.calculateCpuUsage(cpuEndMs - cpuBeginMs, cost)); } - if (null != anrTask) { - anrTask.getBeginRecord().release(); - anrHandler.removeCallbacks(anrTask); - } - if (null != lagTask) { - lagHandler.removeCallbacks(lagTask); - } + anrTask.getBeginRecord().release(); + anrHandler.removeCallbacks(anrTask); + lagHandler.removeCallbacks(lagTask); } class LagHandleTask implements Runnable { From 727db2a60c72c12c1e5f40f52a1b9c2672416faf Mon Sep 17 00:00:00 2001 From: ccloverhe Date: Fri, 10 Dec 2021 17:11:58 +0800 Subject: [PATCH 113/163] fix size get bug --- .../matrix/openglleak/statistics/resource/MemoryInfo.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java index eca10d44f..a7a2190c1 100644 --- a/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java +++ b/matrix/matrix-android/matrix-opengl-leak/src/main/java/com/tencent/matrix/openglleak/statistics/resource/MemoryInfo.java @@ -152,14 +152,17 @@ public FaceInfo[] getFaces() { } public long getSize() { + long actualSize = 0L; if (this.resType == OpenGLInfo.TYPE.TEXTURE) { for (FaceInfo faceInfo : faces) { if (faceInfo != null) { - this.size += faceInfo.getSize(); + actualSize += faceInfo.getSize(); } } + } else { + actualSize = size; } - return size; + return actualSize; } public long getEglContextId() { From 5958384cf12f4591bb184bff7c35f5969c66497a Mon Sep 17 00:00:00 2001 From: leafjia Date: Sat, 11 Dec 2021 11:14:19 +0800 Subject: [PATCH 114/163] support ignoreSoFiles --- .../src/main/cpp/MatrixTraffic.cc | 18 ++++++++++++------ .../tencent/matrix/traffic/TrafficConfig.java | 12 ++++++++++++ .../tencent/matrix/traffic/TrafficPlugin.java | 5 +++-- 3 files changed, 27 insertions(+), 8 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 345bf6c74..c420e2a33 100644 --- a/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc +++ b/matrix/matrix-android/matrix-traffic/src/main/cpp/MatrixTraffic.cc @@ -70,6 +70,7 @@ ssize_t my_recvfrom(int sockfd, void *buf, size_t len, int flags, ssize_t (*original_recvmsg)(int sockfd, struct msghdr *msg, int flags); ssize_t my_recvmsg(int sockfd, struct msghdr *msg, int flags) { + TrafficCollector::enQueueRx(MSG_TYPE_RECVMSG, sockfd, msg->msg_iovlen); return original_recvmsg(sockfd, msg, flags); } @@ -173,7 +174,6 @@ static void hookSocket(bool rxHook, bool txHook) { xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libadbconnection\\.so$", nullptr); 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, ".*libhardcoder\\.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); @@ -181,20 +181,26 @@ static void hookSocket(bool rxHook, bool txHook) { xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libGLES_mali\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libhwui\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libEGL\\.so$", nullptr); - xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libwcdb\\.so$", nullptr); 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, ".*libwechatxlog\\.so$", nullptr); - xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*libmmkv\\.so$", nullptr); xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ".*liblog\\.so$", nullptr); xhook_refresh(true); HOOKED = true; } -static void nativeInitMatrixTraffic(JNIEnv *env, jclass, jboolean rxEnable, jboolean txEnable, jboolean dumpStackTrace) { +static void ignoreSo(JNIEnv *env, jobjectArray ignoreSoFiles) { + for (int i=0; i < env->GetArrayLength(ignoreSoFiles); i++) { + auto ignoreSoFile = (jstring) (env->GetObjectArrayElement(ignoreSoFiles, i)); + const char *ignoreSoFileChars = env->GetStringUTFChars(ignoreSoFile, 0); + xhook_grouped_ignore(HOOK_REQUEST_GROUPID_TRAFFIC, ignoreSoFileChars, nullptr); + } +} + +static void nativeInitMatrixTraffic(JNIEnv *env, jclass, jboolean rxEnable, jboolean txEnable, jboolean dumpStackTrace, jobjectArray ignoreSoFiles) { TrafficCollector::startLoop(dumpStackTrace == JNI_TRUE); + ignoreSo(env, ignoreSoFiles); hookSocket(rxEnable == JNI_TRUE, txEnable == JNI_TRUE); } @@ -202,7 +208,7 @@ template static inline constexpr std::size_t NELEM(const T(&)[sz]) { return sz; } static const JNINativeMethod TRAFFIC_METHODS[] = { - {"nativeInitMatrixTraffic", "(ZZZ)V", (void *) nativeInitMatrixTraffic}, + {"nativeInitMatrixTraffic", "(ZZZ[Ljava/lang/String;)V", (void *) nativeInitMatrixTraffic}, {"nativeGetTrafficInfoMap", "(I)Ljava/util/HashMap;", (void *) nativeGetTrafficInfoMap}, {"nativeClearTrafficInfo", "()V", (void *) nativeClearTrafficInfo}, {"nativeReleaseMatrixTraffic", "()V", (void *) nativeReleaseMatrixTraffic}, 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 7ac6bee7b..5a2b0ac16 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 @@ -1,9 +1,13 @@ package com.tencent.matrix.traffic; +import java.util.ArrayList; +import java.util.List; + public class TrafficConfig { private boolean rxCollectorEnable; private boolean txCollectorEnable; private boolean dumpStackTrace; + private List ignoreSoList = new ArrayList<>(); public TrafficConfig() { @@ -35,4 +39,12 @@ public boolean willDumpStackTrace() { public void setDumpStackTrace(boolean dumpStackTrace) { this.dumpStackTrace = dumpStackTrace; } + + public void addIgnoreSoFile(String soName) { + ignoreSoList.add(soName); + } + + public String[] getIgnoreSoFiles() { + return ignoreSoList.toArray(new String[ignoreSoList.size()]); + } } 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 c0f8ac250..841c57894 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 @@ -35,7 +35,8 @@ public void start() { } super.start(); MatrixLog.i(TAG, "start"); - nativeInitMatrixTraffic(trafficConfig.isRxCollectorEnable(), trafficConfig.isTxCollectorEnable(), trafficConfig.willDumpStackTrace()); + String[] ignoreSoFiles = trafficConfig.getIgnoreSoFiles(); + nativeInitMatrixTraffic(trafficConfig.isRxCollectorEnable(), trafficConfig.isTxCollectorEnable(), trafficConfig.willDumpStackTrace(), ignoreSoFiles); } @@ -62,7 +63,7 @@ public void clearTrafficInfo() { nativeClearTrafficInfo(); } - private static native void nativeInitMatrixTraffic(boolean rxEnable, boolean txEnable, boolean dumpStackTrace); + private static native void nativeInitMatrixTraffic(boolean rxEnable, boolean txEnable, boolean dumpStackTrace, String[] ignoreSoFiles); private static native String nativeGetTrafficInfo(); private static native String nativeGetAllStackTraceTrafficInfo(); private static native void nativeReleaseMatrixTraffic(); From ad0dc9350bd36062bd0740d74cff8fc93320487a Mon Sep 17 00:00:00 2001 From: leafjia Date: Mon, 13 Dec 2021 01:31:52 +0800 Subject: [PATCH 115/163] print longMsg when checks error state --- .../java/com/tencent/matrix/trace/tracer/SignalAnrTracer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 62ef327dd..b335f85dc 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 @@ -252,6 +252,8 @@ private static boolean checkErrorState() { continue; } + MatrixLog.i(TAG, "error sate longMsg = %s", proc.longMsg); + return true; } return false; @@ -280,6 +282,6 @@ public static void printTrace() { private static native void nativePrintTrace(); public interface SignalAnrDetectedListener { - void onAnrDetected(String stackTrace, String mMessageString, long mMessageWhen, boolean fromProcessErrorState); + void onAnrDetected(String stackTrace, String mMessageString, long mMessageWhen, boolean fromProcessErrorState) throws InterruptedException; } } From a0947f31a743710982d16cae9ee51183d2d7e220 Mon Sep 17 00:00:00 2001 From: leafjia Date: Mon, 13 Dec 2021 01:35:38 +0800 Subject: [PATCH 116/163] fix wrong change about onAnrDetected --- .../java/com/tencent/matrix/trace/tracer/SignalAnrTracer.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/tracer/SignalAnrTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/SignalAnrTracer.java index b335f85dc..8632f2cc7 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 @@ -282,6 +282,6 @@ public static void printTrace() { private static native void nativePrintTrace(); public interface SignalAnrDetectedListener { - void onAnrDetected(String stackTrace, String mMessageString, long mMessageWhen, boolean fromProcessErrorState) throws InterruptedException; + void onAnrDetected(String stackTrace, String mMessageString, long mMessageWhen, boolean fromProcessErrorState); } } From 1fe72232ec63cdd8f6de31a7bb225afb3508f1ad Mon Sep 17 00:00:00 2001 From: leafjia Date: Tue, 14 Dec 2021 00:22:41 +0800 Subject: [PATCH 117/163] onAnrDetected callback add cpuset params --- .../matrix/trace/tracer/SignalAnrTracer.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 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 8632f2cc7..0a6ee352d 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 @@ -44,6 +44,9 @@ import org.json.JSONException; import org.json.JSONObject; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; import java.lang.reflect.Field; import java.util.List; @@ -66,6 +69,7 @@ public class SignalAnrTracer extends Tracer { public static boolean hasInstance = false; private static long anrMessageWhen = 0L; private static String anrMessageString = ""; + private static String cpuset = ""; static { System.loadLibrary("trace-canary"); @@ -110,10 +114,24 @@ public void setSignalAnrDetectedListener(SignalAnrDetectedListener listener) { sSignalAnrDetectedListener = listener; } + public static String readCpuSet() { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/cgroup")))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.contains("cpuset") || line.contains("cpu")) { + return line; + } + } + } catch (Throwable t) { + t.printStackTrace(); + } + return ""; + } @RequiresApi(api = Build.VERSION_CODES.M) @Keep private static void onANRDumped() { + cpuset = readCpuSet(); currentForeground = AppForegroundUtil.isInterestingToUser(); boolean needReport = isMainThreadBlocked(); @@ -151,7 +169,7 @@ private static void report(boolean fromProcessErrorState) { try { String stackTrace = Utils.getMainThreadJavaStackTrace(); if (sSignalAnrDetectedListener != null) { - sSignalAnrDetectedListener.onAnrDetected(stackTrace, anrMessageString, anrMessageWhen, fromProcessErrorState); + sSignalAnrDetectedListener.onAnrDetected(stackTrace, anrMessageString, anrMessageWhen, fromProcessErrorState, cpuset); return; } @@ -282,6 +300,6 @@ public static void printTrace() { private static native void nativePrintTrace(); public interface SignalAnrDetectedListener { - void onAnrDetected(String stackTrace, String mMessageString, long mMessageWhen, boolean fromProcessErrorState); + void onAnrDetected(String stackTrace, String mMessageString, long mMessageWhen, boolean fromProcessErrorState, String cpuset); } } From cc59c1b84b7d9a1e7b6f3b12b47306c04ad83e1d Mon Sep 17 00:00:00 2001 From: leafjia Date: Tue, 14 Dec 2021 12:25:03 +0800 Subject: [PATCH 118/163] report cgroup --- .../matrix/trace/tracer/SignalAnrTracer.java | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 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 0a6ee352d..ab7d0dd6d 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 @@ -69,7 +69,7 @@ public class SignalAnrTracer extends Tracer { public static boolean hasInstance = false; private static long anrMessageWhen = 0L; private static String anrMessageString = ""; - private static String cpuset = ""; + private static String cgroup = ""; static { System.loadLibrary("trace-canary"); @@ -114,24 +114,37 @@ public void setSignalAnrDetectedListener(SignalAnrDetectedListener listener) { sSignalAnrDetectedListener = listener; } - public static String readCpuSet() { +// public static String readCpuSet() { +// try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/cgroup")))) { +// String line; +// while ((line = reader.readLine()) != null) { +// if (line.contains("cpuset") || line.contains("cpu")) { +// return line; +// } +// } +// } catch (Throwable t) { +// t.printStackTrace(); +// } +// return ""; +// } + + public static String readCgroup() { + StringBuilder ret = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/cgroup")))) { String line; while ((line = reader.readLine()) != null) { - if (line.contains("cpuset") || line.contains("cpu")) { - return line; - } + ret.append(line).append("\n"); } } catch (Throwable t) { t.printStackTrace(); } - return ""; + return ret.toString(); } @RequiresApi(api = Build.VERSION_CODES.M) @Keep private static void onANRDumped() { - cpuset = readCpuSet(); + cgroup = readCgroup(); currentForeground = AppForegroundUtil.isInterestingToUser(); boolean needReport = isMainThreadBlocked(); @@ -169,7 +182,7 @@ private static void report(boolean fromProcessErrorState) { try { String stackTrace = Utils.getMainThreadJavaStackTrace(); if (sSignalAnrDetectedListener != null) { - sSignalAnrDetectedListener.onAnrDetected(stackTrace, anrMessageString, anrMessageWhen, fromProcessErrorState, cpuset); + sSignalAnrDetectedListener.onAnrDetected(stackTrace, anrMessageString, anrMessageWhen, fromProcessErrorState, cgroup); return; } From d127c93d151f037620e56a7b1433d26982b55cf1 Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 15 Dec 2021 14:13:33 +0800 Subject: [PATCH 119/163] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20eglcontext=20?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=88=A4=E6=96=AD=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix/openglleak/utils/EGLHelper.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) 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 fff23f4ee..5023eb20f 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 @@ -74,4 +74,23 @@ public static void initOpenGL() { GLES20.glFlush(); } + + public static boolean isEglContextAlive(EGLContext context) { + EGLDisplay defaultDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + + int[] eglContextAttribList = new int[]{ + EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, + EGL14.EGL_NONE + }; + + EGLContext testContext = EGL14.eglCreateContext(defaultDisplay, mEglConfig, context, eglContextAttribList, 0); + if (testContext == EGL14.EGL_NO_CONTEXT) { + return false; + } + + EGL14.eglDestroyContext(defaultDisplay, testContext); + EGL14.eglTerminate(defaultDisplay); + + return true; + } } From e78a77be180d88352ec500dede108a0014fbf006 Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 15 Dec 2021 14:42:28 +0800 Subject: [PATCH 120/163] =?UTF-8?q?=E5=88=A4=E6=96=AD=20eglcontext=20?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix/openglleak/utils/EGLHelper.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) 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 5023eb20f..d17c59f7c 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 @@ -10,8 +10,14 @@ import androidx.annotation.RequiresApi; +import com.tencent.matrix.util.MatrixLog; + +import java.lang.reflect.Constructor; + public class EGLHelper { + private static final String TAG = "MicroMsg.EGLHelper"; + private static EGLDisplay mEGLDisplay; private static EGLConfig mEglConfig; private static EGLContext mEglContext; @@ -75,6 +81,24 @@ public static void initOpenGL() { GLES20.glFlush(); } + public static boolean isEglContextAlive(long eglContextNativeHandle) { + EGLContext context = null; + try { + Class clazz = EGLContext.class; + Constructor constructor = clazz.getDeclaredConstructor(new Class[]{long.class}); + constructor.setAccessible(true); + context = (EGLContext) constructor.newInstance(eglContextNativeHandle); + } catch (Exception e) { + MatrixLog.e(TAG, "EGLContext newInstance error"); + } + + if (null == context) { + return false; + } + + return isEglContextAlive(context); + } + public static boolean isEglContextAlive(EGLContext context) { EGLDisplay defaultDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); From 4f7c716c7bb67d6360d730af1f8cf0ad0675992e Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 15 Dec 2021 15:31:19 +0800 Subject: [PATCH 121/163] =?UTF-8?q?opengl=20info=20=E6=B7=BB=E5=8A=A0=20co?= =?UTF-8?q?ntext=20=E7=8A=B6=E6=80=81=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix/openglleak/hook/OpenGLHook.java | 60 +++---------------- .../statistics/resource/OpenGLInfo.java | 37 ++++++++---- .../statistics/resource/ResRecordManager.java | 26 ++++++++ .../matrix/openglleak/utils/EGLHelper.java | 24 +------- 4 files changed, 61 insertions(+), 86 deletions(-) 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 ff223f1ad..505a5d416 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 @@ -137,13 +137,8 @@ public static void onGlGenTextures(int[] ids, final String threadId, final Strin if (ids.length > 0) { final AtomicInteger counter = new AtomicInteger(ids.length); - long eglContextId = 0L; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); - } - for (final int id : ids) { - final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, EGL14.eglGetCurrentContext(), javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { @@ -160,14 +155,8 @@ public void run() { public static void onGlDeleteTextures(int[] ids, String threadId) { if (ids.length > 0) { - - long eglContextId = 0L; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); - } - for (int id : ids) { - final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, eglContextId); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.TEXTURE, id, threadId, EGL14.eglGetCurrentContext()); ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { @@ -186,13 +175,8 @@ public static void onGlGenBuffers(int[] ids, String threadId, String javaStack, if (ids.length > 0) { AtomicInteger counter = new AtomicInteger(ids.length); - long eglContextId = 0L; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); - } - for (int id : ids) { - final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, EGL14.eglGetCurrentContext(), javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { @@ -209,14 +193,8 @@ public void run() { public static void onGlDeleteBuffers(int[] ids, String threadId) { if (ids.length > 0) { - - long eglContextId = 0L; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); - } - for (int id : ids) { - final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, eglContextId); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.BUFFER, id, threadId, EGL14.eglGetCurrentContext()); ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { @@ -235,13 +213,8 @@ public static void onGlGenFramebuffers(int[] ids, String threadId, String javaSt if (ids.length > 0) { AtomicInteger counter = new AtomicInteger(ids.length); - long eglContextId = 0L; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); - } - for (int id : ids) { - final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, EGL14.eglGetCurrentContext(), javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { @@ -258,14 +231,8 @@ public void run() { public static void onGlDeleteFramebuffers(int[] ids, String threadId) { if (ids.length > 0) { - - long eglContextId = 0L; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); - } - for (int id : ids) { - final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, eglContextId); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.FRAME_BUFFERS, id, threadId, EGL14.eglGetCurrentContext()); ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { @@ -284,13 +251,8 @@ public static void onGlGenRenderbuffers(int[] ids, String threadId, String javaS if (ids.length > 0) { AtomicInteger counter = new AtomicInteger(ids.length); - long eglContextId = 0L; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); - } - for (int id : ids) { - final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId, javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, EGL14.eglGetCurrentContext(), javaStack, nativeStackPtr, ActivityRecorder.getInstance().getCurrentActivityInfo(), counter); ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { @@ -307,14 +269,8 @@ public void run() { public static void onGlDeleteRenderbuffers(int[] ids, String threadId) { if (ids.length > 0) { - - long eglContextId = 0L; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - eglContextId = EGL14.eglGetCurrentContext().getNativeHandle(); - } - for (int id : ids) { - final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, eglContextId); + final OpenGLInfo openGLInfo = new OpenGLInfo(OpenGLInfo.TYPE.RENDER_BUFFERS, id, threadId, EGL14.eglGetCurrentContext()); ExecuteCenter.getInstance().post(new Runnable() { @Override public void run() { 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 f3a1321b7..856ce4b22 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 @@ -1,7 +1,8 @@ package com.tencent.matrix.openglleak.statistics.resource; +import android.opengl.EGLContext; +import android.os.Build; import com.tencent.matrix.openglleak.utils.ActivityRecorder; - import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; @@ -9,12 +10,12 @@ public class OpenGLInfo { private String threadId = ""; private final int id; - private final long eglContextNativeHandle; private String javaStack = ""; private String nativeStack = ""; private long nativeStackPtr = 0L; private final TYPE type; private MemoryInfo memoryInfo; + private EGLContext eglContext; private ActivityRecorder.ActivityInfo activityInfo; @@ -27,7 +28,7 @@ public enum TYPE { public OpenGLInfo(OpenGLInfo clone) { this.threadId = clone.threadId; this.id = clone.id; - this.eglContextNativeHandle = clone.eglContextNativeHandle; + this.eglContext = clone.eglContext; this.javaStack = clone.javaStack; this.nativeStack = clone.nativeStack; this.nativeStackPtr = clone.nativeStackPtr; @@ -35,15 +36,14 @@ public OpenGLInfo(OpenGLInfo clone) { this.activityInfo = clone.activityInfo; } - - public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle) { + public OpenGLInfo(TYPE type, int id, String threadId, EGLContext eglContext) { this.threadId = threadId; this.id = id; - this.eglContextNativeHandle = eglContextNativeHandle; + this.eglContext = eglContext; this.type = type; } - public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandle, String javaStack, long nativeStackPtr, ActivityRecorder.ActivityInfo activityInfo, AtomicInteger counter) { + public OpenGLInfo(TYPE type, int id, String threadId, EGLContext eglContext, String javaStack, long nativeStackPtr, ActivityRecorder.ActivityInfo activityInfo, AtomicInteger counter) { this.threadId = threadId; this.javaStack = javaStack; this.nativeStackPtr = nativeStackPtr; @@ -51,14 +51,25 @@ public OpenGLInfo(TYPE type, int id, String threadId, long eglContextNativeHandl this.activityInfo = activityInfo; this.counter = counter; this.id = id; - this.eglContextNativeHandle = eglContextNativeHandle; + this.eglContext = eglContext; } public MemoryInfo getMemoryInfo() { return memoryInfo; } + public EGLContext getEglContext() { + return eglContext; + } + public long getEglContextNativeHandle() { + long eglContextNativeHandle = 0L; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (null != eglContext) { + eglContextNativeHandle = eglContext.getNativeHandle(); + } + } + return eglContextNativeHandle; } @@ -101,6 +112,10 @@ public ActivityRecorder.ActivityInfo getActivityInfo() { return activityInfo; } + public boolean isEglContextAlive() { + return ResRecordManager.getInstance().isEglContextAlive(this); + } + @Override public String toString() { return "OpenGLInfo{" + @@ -108,7 +123,7 @@ public String toString() { ", activityName=" + activityInfo + ", type='" + type.toString() + '\'' + ", threadId='" + threadId + '\'' + - ", eglContextNativeHandle='" + eglContextNativeHandle + '\'' + + ", eglContextNativeHandle='" + getEglContextNativeHandle() + '\'' + ", javaStack='" + javaStack + '\'' + ", nativeStack='" + getNativeStack() + '\'' + ", nativeStackPtr=" + nativeStackPtr + @@ -122,14 +137,14 @@ public boolean equals(Object o) { if (o == null || !(o instanceof OpenGLInfo)) return false; OpenGLInfo that = (OpenGLInfo) o; return id == that.id && - eglContextNativeHandle == that.eglContextNativeHandle && + getEglContextNativeHandle() == that.getEglContextNativeHandle() && threadId.equals(that.threadId) && type == that.type; } @Override public int hashCode() { - return Objects.hash(id, eglContextNativeHandle, threadId, type); + return Objects.hash(id, getEglContextNativeHandle(), threadId, type); } } 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 ba0d2ae88..517840c90 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 @@ -3,6 +3,7 @@ import android.annotation.SuppressLint; import com.tencent.matrix.openglleak.utils.AutoWrapBuilder; +import com.tencent.matrix.openglleak.utils.EGLHelper; import java.io.BufferedWriter; import java.io.File; @@ -24,6 +25,7 @@ public class ResRecordManager { private final List mCallbackList = new LinkedList<>(); private final List mInfoList = new LinkedList<>(); + private final List mReleaseContext = new LinkedList<>(); private ResRecordManager() { @@ -171,6 +173,30 @@ public void clear() { synchronized (mInfoList) { mInfoList.clear(); } + synchronized (mReleaseContext) { + mReleaseContext.clear(); + } + } + + public boolean isEglContextAlive(OpenGLInfo info) { + synchronized (mReleaseContext) { + long eglContextNativeHandle = info.getEglContextNativeHandle(); + if (0L == eglContextNativeHandle) { + return false; + } + + for (long item : mReleaseContext) { + if (item == eglContextNativeHandle) { + return false; + } + } + + boolean ret = EGLHelper.isEglContextAlive(info.getEglContext()); + if (!ret) { + mReleaseContext.add(info.getEglContextNativeHandle()); + } + return ret; + } } public void dumpGLToFile(String filePath) { 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 d17c59f7c..9c94a3359 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 @@ -7,13 +7,8 @@ import android.opengl.EGLSurface; import android.opengl.GLES20; import android.os.Build; - import androidx.annotation.RequiresApi; -import com.tencent.matrix.util.MatrixLog; - -import java.lang.reflect.Constructor; - public class EGLHelper { private static final String TAG = "MicroMsg.EGLHelper"; @@ -81,24 +76,6 @@ public static void initOpenGL() { GLES20.glFlush(); } - public static boolean isEglContextAlive(long eglContextNativeHandle) { - EGLContext context = null; - try { - Class clazz = EGLContext.class; - Constructor constructor = clazz.getDeclaredConstructor(new Class[]{long.class}); - constructor.setAccessible(true); - context = (EGLContext) constructor.newInstance(eglContextNativeHandle); - } catch (Exception e) { - MatrixLog.e(TAG, "EGLContext newInstance error"); - } - - if (null == context) { - return false; - } - - return isEglContextAlive(context); - } - public static boolean isEglContextAlive(EGLContext context) { EGLDisplay defaultDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); @@ -117,4 +94,5 @@ public static boolean isEglContextAlive(EGLContext context) { return true; } + } From 582551cedc957b5426ec86c3a5734c14ff674f3e Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 15 Dec 2021 15:44:04 +0800 Subject: [PATCH 122/163] method rename --- .../openglleak/statistics/resource/OpenGLInfo.java | 4 ++-- .../statistics/resource/ResRecordManager.java | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) 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 856ce4b22..b4de1597f 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 @@ -112,8 +112,8 @@ public ActivityRecorder.ActivityInfo getActivityInfo() { return activityInfo; } - public boolean isEglContextAlive() { - return ResRecordManager.getInstance().isEglContextAlive(this); + public boolean isEglContextReleased() { + return ResRecordManager.getInstance().isEglContextReleased(this); } @Override 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 517840c90..3ba4a4727 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,24 @@ public void clear() { } } - public boolean isEglContextAlive(OpenGLInfo info) { + public boolean isEglContextReleased(OpenGLInfo info) { synchronized (mReleaseContext) { long eglContextNativeHandle = info.getEglContextNativeHandle(); if (0L == eglContextNativeHandle) { - return false; + return true; } for (long item : mReleaseContext) { if (item == eglContextNativeHandle) { - return false; + return true; } } - boolean ret = EGLHelper.isEglContextAlive(info.getEglContext()); - if (!ret) { + boolean alive = EGLHelper.isEglContextAlive(info.getEglContext()); + if (!alive) { mReleaseContext.add(info.getEglContextNativeHandle()); } - return ret; + return !alive; } } From 2f1642c920b76f2d0152d3b82a21a971569c427a Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 15 Dec 2021 15:59:16 +0800 Subject: [PATCH 123/163] =?UTF-8?q?toString=20=E6=B7=BB=E5=8A=A0=20context?= =?UTF-8?q?=20=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matrix/openglleak/statistics/resource/OpenGLInfo.java | 1 + 1 file changed, 1 insertion(+) 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 b4de1597f..4a894e27b 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 @@ -124,6 +124,7 @@ public String toString() { ", type='" + type.toString() + '\'' + ", threadId='" + threadId + '\'' + ", eglContextNativeHandle='" + getEglContextNativeHandle() + '\'' + + ", eglContextReleased='" + isEglContextReleased() + '\'' + ", javaStack='" + javaStack + '\'' + ", nativeStack='" + getNativeStack() + '\'' + ", nativeStackPtr=" + nativeStackPtr + From 88377d44217a9d64f5ea55a6d1d890a62a754770 Mon Sep 17 00:00:00 2001 From: leafjia Date: Wed, 15 Dec 2021 19:59:09 +0800 Subject: [PATCH 124/163] ThreadPriorityTracer onMainThreadPriorityModified callback add priorityBefore --- .../src/main/cpp/MatrixTracer.cc | 14 +++++--------- .../matrix/trace/tracer/ThreadPriorityTracer.java | 8 ++++---- 2 files changed, 9 insertions(+), 13 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 bdf482cb6..713f097fc 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 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -89,15 +90,10 @@ static struct StacktraceJNI { int (*original_setpriority)(int __which, id_t __who, int __priority); int my_setpriority(int __which, id_t __who, int __priority) { - if (__priority <= 0) { - return original_setpriority(__which, __who, __priority); - } - if (__who == 0 && getpid() == gettid()) { - JNIEnv *env = JniInvocation::getEnv(); - env->CallStaticVoidMethod(gJ.ThreadPriorityDetective, gJ.ThreadPriorityDetective_onMainThreadPriorityModified, __priority); - } else if (__who == getpid()) { + if ((__who == 0 && getpid() == gettid()) || __who == getpid()) { + int priorityBefore = getpriority(__which, __who); JNIEnv *env = JniInvocation::getEnv(); - env->CallStaticVoidMethod(gJ.ThreadPriorityDetective, gJ.ThreadPriorityDetective_onMainThreadPriorityModified, __priority); + env->CallStaticVoidMethod(gJ.ThreadPriorityDetective, gJ.ThreadPriorityDetective_onMainThreadPriorityModified, priorityBefore, __priority); } return original_setpriority(__which, __who, __priority); @@ -416,7 +412,7 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { gJ.ThreadPriorityDetective_onMainThreadPriorityModified = - env->GetStaticMethodID(threadPriorityDetectiveCls, "onMainThreadPriorityModified", "(I)V"); + env->GetStaticMethodID(threadPriorityDetectiveCls, "onMainThreadPriorityModified", "(II)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/tracer/ThreadPriorityTracer.java b/matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/tracer/ThreadPriorityTracer.java index ebe36b552..c4687cdb2 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/ThreadPriorityTracer.java @@ -56,11 +56,11 @@ public void setMainThreadPriorityModifiedListener(MainThreadPriorityModifiedList private static native void nativeInitMainThreadPriorityDetective(); @Keep - private static void onMainThreadPriorityModified(int priority) { + private static void onMainThreadPriorityModified(int priorityBefore, int priorityAfter) { try { if (sMainThreadPriorityModifiedListener != null) { - sMainThreadPriorityModifiedListener.onMainThreadPriorityModified(priority); + sMainThreadPriorityModifiedListener.onMainThreadPriorityModified(priorityBefore, priorityAfter); return; } @@ -75,7 +75,7 @@ private static void onMainThreadPriorityModified(int priority) { jsonObject = DeviceUtil.getDeviceInfo(jsonObject, Matrix.with().getApplication()); jsonObject.put(SharePluginInfo.ISSUE_STACK_TYPE, Constants.Type.PRIORITY_MODIFIED); jsonObject.put(SharePluginInfo.ISSUE_THREAD_STACK, stackTrace); - jsonObject.put(SharePluginInfo.ISSUE_PROCESS_PRIORITY, priority); + jsonObject.put(SharePluginInfo.ISSUE_PROCESS_PRIORITY, priorityAfter); Issue issue = new Issue(); issue.setTag(SharePluginInfo.TAG_PLUGIN_EVIL_METHOD); @@ -121,7 +121,7 @@ private static void onMainThreadTimerSlackModified(long timerSlack) { } public interface MainThreadPriorityModifiedListener { - void onMainThreadPriorityModified(int priority); + void onMainThreadPriorityModified(int priorityBefore, int priorityAfter); void onMainThreadTimerSlackModified(long timerSlack); } From bf24297dd37155734a131aab06db6ec60242614c Mon Sep 17 00:00:00 2001 From: leafjia Date: Wed, 15 Dec 2021 20:12:41 +0800 Subject: [PATCH 125/163] dump stacktrace as soon as possible when happens anr --- .../com/tencent/matrix/trace/tracer/SignalAnrTracer.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 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 ab7d0dd6d..899bce1da 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 @@ -70,6 +70,7 @@ public class SignalAnrTracer extends Tracer { private static long anrMessageWhen = 0L; private static String anrMessageString = ""; private static String cgroup = ""; + private static String stackTrace = ""; static { System.loadLibrary("trace-canary"); @@ -143,7 +144,8 @@ public static String readCgroup() { @RequiresApi(api = Build.VERSION_CODES.M) @Keep - private static void onANRDumped() { + private synchronized static void onANRDumped() { + stackTrace = Utils.getMainThreadJavaStackTrace(); cgroup = readCgroup(); currentForeground = AppForegroundUtil.isInterestingToUser(); boolean needReport = isMainThreadBlocked(); @@ -178,9 +180,8 @@ private static void onPrintTrace() { } } - private static void report(boolean fromProcessErrorState) { + private synchronized static void report(boolean fromProcessErrorState) { try { - String stackTrace = Utils.getMainThreadJavaStackTrace(); if (sSignalAnrDetectedListener != null) { sSignalAnrDetectedListener.onAnrDetected(stackTrace, anrMessageString, anrMessageWhen, fromProcessErrorState, cgroup); return; From c5a555fb37839612dc3e83119e98df405a773ea2 Mon Sep 17 00:00:00 2001 From: leafjia Date: Wed, 15 Dec 2021 20:15:32 +0800 Subject: [PATCH 126/163] add log --- .../java/com/tencent/matrix/trace/tracer/SignalAnrTracer.java | 1 + 1 file changed, 1 insertion(+) 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 899bce1da..5dd69b91e 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 @@ -146,6 +146,7 @@ public static String readCgroup() { @Keep private synchronized static void onANRDumped() { stackTrace = Utils.getMainThreadJavaStackTrace(); + MatrixLog.i(TAG, "onANRDumped, stackTrace = %s", stackTrace); cgroup = readCgroup(); currentForeground = AppForegroundUtil.isInterestingToUser(); boolean needReport = isMainThreadBlocked(); From 2eecd3a78df590b52a84c85be94110639a5aff74 Mon Sep 17 00:00:00 2001 From: opdeng Date: Wed, 15 Dec 2021 21:24:19 +0800 Subject: [PATCH 127/163] =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=89=80=E6=9C=89=20?= =?UTF-8?q?item?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../openglleak/statistics/resource/OpenGLInfo.java | 1 + .../statistics/resource/ResRecordManager.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+) 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 4a894e27b..5708a42e1 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 @@ -34,6 +34,7 @@ public OpenGLInfo(OpenGLInfo clone) { this.nativeStackPtr = clone.nativeStackPtr; this.type = clone.type; this.activityInfo = clone.activityInfo; + this.memoryInfo = clone.memoryInfo; } public OpenGLInfo(TYPE type, int id, String threadId, EGLContext eglContext) { 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 3ba4a4727..f078479d8 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 @@ -199,6 +199,20 @@ public boolean isEglContextReleased(OpenGLInfo info) { } } + public List getAllItem() { + List retList = new LinkedList<>(); + + synchronized (mInfoList) { + for (OpenGLInfo item : mInfoList) { + if (null != item) { + retList.add(item); + } + } + } + + return retList; + } + public void dumpGLToFile(String filePath) { File targetFile = new File(filePath); From ed99dc3dac8f087a0881fa0e163c0f1f94ec8901 Mon Sep 17 00:00:00 2001 From: opdeng Date: Thu, 16 Dec 2021 11:14:12 +0800 Subject: [PATCH 128/163] crash fix --- .../com/tencent/matrix/openglleak/utils/EGLHelper.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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 9c94a3359..ec074efd0 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 @@ -77,20 +77,17 @@ public static void initOpenGL() { } public static boolean isEglContextAlive(EGLContext context) { - EGLDisplay defaultDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); - int[] eglContextAttribList = new int[]{ EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE }; - EGLContext testContext = EGL14.eglCreateContext(defaultDisplay, mEglConfig, context, eglContextAttribList, 0); + EGLContext testContext = EGL14.eglCreateContext(mEGLDisplay, mEglConfig, context, eglContextAttribList, 0); if (testContext == EGL14.EGL_NO_CONTEXT) { return false; } - EGL14.eglDestroyContext(defaultDisplay, testContext); - EGL14.eglTerminate(defaultDisplay); + EGL14.eglDestroyContext(mEGLDisplay, testContext); return true; } From 7d3bba32a4c7c7b7b58d4cd39442f7723fc1496a Mon Sep 17 00:00:00 2001 From: leafjia Date: Thu, 16 Dec 2021 11:40:08 +0800 Subject: [PATCH 129/163] remove unused code --- .../matrix/trace/tracer/SignalAnrTracer.java | 14 -------------- 1 file changed, 14 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 5dd69b91e..bbecfdfa0 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 @@ -115,20 +115,6 @@ public void setSignalAnrDetectedListener(SignalAnrDetectedListener listener) { sSignalAnrDetectedListener = listener; } -// public static String readCpuSet() { -// try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/cgroup")))) { -// String line; -// while ((line = reader.readLine()) != null) { -// if (line.contains("cpuset") || line.contains("cpu")) { -// return line; -// } -// } -// } catch (Throwable t) { -// t.printStackTrace(); -// } -// return ""; -// } - public static String readCgroup() { StringBuilder ret = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/self/cgroup")))) { From dbb29bb7849ed7f59ebeb88555e004f7940eb764 Mon Sep 17 00:00:00 2001 From: leafjia Date: Thu, 16 Dec 2021 13:37:11 +0800 Subject: [PATCH 130/163] do not catch onMainThreadPriorityModified exception --- .../matrix/trace/tracer/ThreadPriorityTracer.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) 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/ThreadPriorityTracer.java index c4687cdb2..a07041629 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/ThreadPriorityTracer.java @@ -57,13 +57,11 @@ public void setMainThreadPriorityModifiedListener(MainThreadPriorityModifiedList @Keep private static void onMainThreadPriorityModified(int priorityBefore, int priorityAfter) { + if (sMainThreadPriorityModifiedListener != null) { + sMainThreadPriorityModifiedListener.onMainThreadPriorityModified(priorityBefore, priorityAfter); + return; + } try { - - if (sMainThreadPriorityModifiedListener != null) { - sMainThreadPriorityModifiedListener.onMainThreadPriorityModified(priorityBefore, priorityAfter); - return; - } - TracePlugin plugin = Matrix.with().getPluginByClass(TracePlugin.class); if (null == plugin) { return; From fb86085a1c61ab680ccff7bd21fec06fda889cbc Mon Sep 17 00:00:00 2001 From: aurorani Date: Thu, 16 Dec 2021 15:35:06 +0800 Subject: [PATCH 131/163] feat: Add analyzing state getter API. --- .../com/tencent/matrix/resource/ResourcePlugin.java | 4 ++++ .../matrix/resource/processor/BaseLeakProcessor.java | 12 ++++++++++++ 2 files changed, 16 insertions(+) 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 78c2f51ef..0220739a8 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 @@ -24,6 +24,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.processor.BaseLeakProcessor; import com.tencent.matrix.resource.watcher.ActivityLifeCycleCallbacksAdapter; import com.tencent.matrix.resource.watcher.ActivityRefWatcher; import com.tencent.matrix.util.MatrixLog; @@ -116,4 +117,7 @@ public ResourceConfig getConfig() { return mConfig; } + public boolean isAnalyzing() { + return BaseLeakProcessor.isAnalyzing(); + } } 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 ea5313ac6..b108fe289 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 @@ -78,7 +78,18 @@ public ActivityRefWatcher getWatcher() { public void onDestroy() { } + private static volatile boolean mAnalyzing = false; + + public static boolean isAnalyzing() { + return mAnalyzing; + } + + private static void setAnalyzing(boolean analyzing) { + mAnalyzing = analyzing; + } + protected ActivityLeakResult analyze(File hprofFile, String referenceKey) { + setAnalyzing(true); final HeapSnapshot heapSnapshot; ActivityLeakResult result; String manufacture = Matrix.with().getPluginByClass(ResourcePlugin.class).getConfig().getManufacture(); @@ -89,6 +100,7 @@ protected ActivityLeakResult analyze(File hprofFile, String referenceKey) { } catch (IOException e) { result = ActivityLeakResult.failure(e, 0); } + setAnalyzing(false); return result; } From 4bbc73ec428959ca7da4fa3eed36f6b747e589be Mon Sep 17 00:00:00 2001 From: aurorani Date: Thu, 16 Dec 2021 19:02:05 +0800 Subject: [PATCH 132/163] fix: Update manual dump activity in Matrix sample. --- .../matrix/resource/ManualDumpActivity.java | 47 +++++++------------ .../main/res/layout/activity_manual_dump.xml | 24 ++++++++-- .../app/src/main/res/values/strings.xml | 1 + 3 files changed, 37 insertions(+), 35 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 aef55fa14..bb589d5e6 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 @@ -2,9 +2,10 @@ import android.app.Activity; import android.os.Bundle; + import androidx.annotation.Nullable; -import android.util.Log; -import android.view.View; + +import android.widget.TextView; import com.tencent.matrix.resource.config.SharePluginInfo; import com.tencent.matrix.resource.processor.ManualDumpProcessor; @@ -17,38 +18,24 @@ public class ManualDumpActivity extends Activity { private static final String TAG = "ManualDumpActivity"; - private String mRefString; - private String mLeakedActivity; - private String mLeakProcess; - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_manual_dump); - mLeakedActivity = getIntent().getStringExtra(SharePluginInfo.ISSUE_ACTIVITY_NAME); - mRefString = getIntent().getStringExtra(SharePluginInfo.ISSUE_REF_KEY); - mLeakProcess = getIntent().getStringExtra(SharePluginInfo.ISSUE_LEAK_PROCESS); - } - - public void dump(View view) { - new Thread(new Runnable() { - @Override - public void run() { - ManualDumpProcessor.ManualDumpProcessorHelper.dumpAndAnalyse(ManualDumpActivity.this, mLeakProcess, mLeakedActivity, mRefString, new ManualDumpProcessor.IResultListener() { - - @Override - public void onSuccess(String hprof, String leakReference) { - Log.d(TAG, "onSuccess: " + hprof); - Log.d(TAG, "onSuccess: "+ leakReference); - } - - @Override - public void onFailed() { - - } - }); - } - }).start(); + ((TextView) findViewById(R.id.leak_activity)) + .setText(getIntent().getStringExtra(SharePluginInfo.ISSUE_ACTIVITY_NAME)); + ((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); + } } } diff --git a/samples/sample-android/app/src/main/res/layout/activity_manual_dump.xml b/samples/sample-android/app/src/main/res/layout/activity_manual_dump.xml index aa4c8c341..00acbeec1 100644 --- a/samples/sample-android/app/src/main/res/layout/activity_manual_dump.xml +++ b/samples/sample-android/app/src/main/res/layout/activity_manual_dump.xml @@ -1,21 +1,35 @@ + tools:text="Leak Activity"/> -