diff options
| author | 2023-12-18 12:02:06 -0500 | |
|---|---|---|
| committer | 2023-12-18 12:03:24 -0500 | |
| commit | 6e69995fec23ab1310fb60d74bf271a229437654 (patch) | |
| tree | a61c8461529ebf64ce8a9c4f1298de625db2e4e4 | |
| parent | 66d088a29e0e0190334612858b5db2bfc2053288 (diff) | |
Remove GarbageMonitorModule
This module is not in use as it was providing bad data.
Fixes: 237065162
Fixes: 243569195
Test: build
Test: atest com.android.systemui.qs
Flag: None
Change-Id: I6fd106b1aea2cb3733c366c758463d50d8faa0d7
12 files changed, 5 insertions, 1020 deletions
diff --git a/packages/SystemUI/res/drawable/ic_memory.xml b/packages/SystemUI/res/drawable/ic_memory.xml deleted file mode 100644 index ada36c58ff1d..000000000000 --- a/packages/SystemUI/res/drawable/ic_memory.xml +++ /dev/null @@ -1,28 +0,0 @@ -<!-- -Copyright (C) 2018 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:pathData="M16.0,5.0l-8.0,0.0l0.0,14.0l8.0,0.0z" - android:fillAlpha="0.5" - android:fillColor="#000000"/> - <path - android:pathData="M6,9 L6,7 L4,7 L4,5 L6,5 C6,3.9 6.9,3 8,3 L16,3 C17.1,3 18,3.9 18,5 L20,5 L20,7 L18,7 L18,9 L20,9 L20,11 L18,11 L18,13 L20,13 L20,15 L18,15 L18,17 L20,17 L20,19 L18,19 C18,20.1 17.1,21 16,21 L8,21 C6.9,21 6,20.1 6,19 L4,19 L4,17 L6,17 L6,15 L4,15 L4,13 L6,13 L6,11 L4,11 L4,9 L6,9 Z M16,19 L16,5 L8,5 L8,19 L16,19 Z" - android:fillColor="#000000"/> -</vector> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index deed6c8c7f25..bf666fb1b8c2 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -480,9 +480,6 @@ This name is in the ComponentName flattened format (package/class) --> <string name="config_remoteCopyPackage" translatable="false"></string> - <!-- On debuggable builds, alert the user if SystemUI PSS goes over this number (in kb) --> - <integer name="watch_heap_limit">256000</integer> - <!-- SystemUI Plugins that can be loaded on user builds. --> <string-array name="config_pluginAllowlist" translatable="false"> <item>com.android.systemui</item> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index e10925d551e2..f4b25a701825 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2397,10 +2397,6 @@ <!-- URl of the webpage that explains battery saver. --> <string name="help_uri_battery_saver_learn_more_link_target" translatable="false"></string> - <!-- Name for a quick settings tile, used only by platform developers, to extract the SystemUI process memory and send it to another - app for debugging. Will not be seen by users. [CHAR LIMIT=20] --> - <string name="heap_dump_tile_name">Dump SysUI Heap</string> - <!-- Title for the privacy indicators dialog, only appears as part of a11y descriptions [CHAR LIMIT=NONE] --> <string name="ongoing_privacy_dialog_a11y_title">In use</string> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java index 1ab64b76b0dc..ba3357c8b591 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java @@ -17,12 +17,10 @@ package com.android.systemui.qs; import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; -import android.os.Build; import android.provider.Settings; -import com.android.systemui.res.R; import com.android.systemui.plugins.qs.QSTile; -import com.android.systemui.util.leak.GarbageMonitor; +import com.android.systemui.res.R; import java.util.ArrayList; import java.util.Arrays; @@ -44,10 +42,6 @@ public interface QSHost { final String defaultTileList = res.getString(R.string.quick_settings_tiles_default); tiles.addAll(Arrays.asList(defaultTileList.split(","))); - if (Build.IS_DEBUGGABLE - && GarbageMonitor.ADD_MEMORY_TILE_TO_DEFAULT_ON_DEBUGGABLE_BUILDS) { - tiles.add(GarbageMonitor.MemoryTile.TILE_SPEC); - } return tiles; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index 2af7ae0614ac..47b062430ca5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -23,7 +23,6 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; -import android.os.Build; import android.provider.Settings; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; @@ -33,7 +32,6 @@ import android.widget.Button; import androidx.annotation.Nullable; -import com.android.systemui.res.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.qs.QSTile; @@ -42,8 +40,8 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon; +import com.android.systemui.res.R; import com.android.systemui.settings.UserTracker; -import com.android.systemui.util.leak.GarbageMonitor; import java.util.ArrayList; import java.util.Arrays; @@ -114,9 +112,6 @@ public class TileQueryHelper { possibleTiles.add(spec); } } - if (Build.IS_DEBUGGABLE && !current.contains(GarbageMonitor.MemoryTile.TILE_SPEC)) { - possibleTiles.add(GarbageMonitor.MemoryTile.TILE_SPEC); - } final ArrayList<QSTile> tilesToAdd = new ArrayList<>(); possibleTiles.remove("cell"); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 17e6375967fc..bdcbac09a254 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -14,7 +14,6 @@ package com.android.systemui.qs.tileimpl; -import android.os.Build; import android.util.Log; import androidx.annotation.Nullable; @@ -25,15 +24,14 @@ import com.android.systemui.plugins.qs.QSFactory; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.external.CustomTile; -import com.android.systemui.util.leak.GarbageMonitor; - -import dagger.Lazy; import java.util.Map; import javax.inject.Inject; import javax.inject.Provider; +import dagger.Lazy; + /** * A factory that creates Quick Settings tiles based on a tileSpec * @@ -79,9 +77,7 @@ public class QSFactoryImpl implements QSFactory { @Nullable protected QSTileImpl createTileInternal(String tileSpec) { // Stock tiles. - if (mTileMap.containsKey(tileSpec) - // We should not return a Garbage Monitory Tile if the build is not Debuggable - && (!tileSpec.equals(GarbageMonitor.MemoryTile.TILE_SPEC) || Build.IS_DEBUGGABLE)) { + if (mTileMap.containsKey(tileSpec)) { return mTileMap.get(tileSpec).get(); } diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java b/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java deleted file mode 100644 index 82153600e473..000000000000 --- a/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2017 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 - */ - -package com.android.systemui.util.leak; - -import android.content.ClipData; -import android.content.ClipDescription; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.util.Log; - -import androidx.core.content.FileProvider; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -/** - * Utility class for dumping, compressing, sending, and serving heap dump files. - * - * <p>Unlike the Internet, this IS a big truck you can dump something on. - */ -public class DumpTruck { - private static final String FILEPROVIDER_AUTHORITY = "com.android.systemui.fileprovider"; - private static final String FILEPROVIDER_PATH = "leak"; - - private static final String TAG = "DumpTruck"; - private static final int BUFSIZ = 1024 * 1024; // 1MB - - private final Context context; - private final GarbageMonitor mGarbageMonitor; - private Uri hprofUri; - private long rss; - final StringBuilder body = new StringBuilder(); - - public DumpTruck(Context context, GarbageMonitor garbageMonitor) { - this.context = context; - mGarbageMonitor = garbageMonitor; - } - - /** - * Capture memory for the given processes and zip them up for sharing. - * - * @param pids - * @return this, for chaining - */ - public DumpTruck captureHeaps(List<Long> pids) { - final File dumpDir = new File(context.getCacheDir(), FILEPROVIDER_PATH); - dumpDir.mkdirs(); - hprofUri = null; - - body.setLength(0); - body.append("Build: ").append(Build.DISPLAY).append("\n\nProcesses:\n"); - - final ArrayList<String> paths = new ArrayList<String>(); - final int myPid = android.os.Process.myPid(); - - for (Long pidL : pids) { - final int pid = pidL.intValue(); - body.append(" pid ").append(pid); - GarbageMonitor.ProcessMemInfo info = mGarbageMonitor.getMemInfo(pid); - if (info != null) { - body.append(":") - .append(" up=") - .append(info.getUptime()) - .append(" rss=") - .append(info.currentRss); - rss = info.currentRss; - } - if (pid == myPid) { - final String path = - new File(dumpDir, String.format("heap-%d.ahprof", pid)).getPath(); - Log.v(TAG, "Dumping memory info for process " + pid + " to " + path); - try { - android.os.Debug.dumpHprofData(path); // will block - paths.add(path); - body.append(" (hprof attached)"); - } catch (IOException e) { - Log.e(TAG, "error dumping memory:", e); - body.append("\n** Could not dump heap: \n").append(e.toString()).append("\n"); - } - } - body.append("\n"); - } - - try { - final String zipfile = - new File(dumpDir, String.format("hprof-%d.zip", System.currentTimeMillis())) - .getCanonicalPath(); - if (DumpTruck.zipUp(zipfile, paths)) { - final File pathFile = new File(zipfile); - hprofUri = FileProvider.getUriForFile(context, FILEPROVIDER_AUTHORITY, pathFile); - Log.v(TAG, "Heap dump accessible at URI: " + hprofUri); - } - } catch (IOException e) { - Log.e(TAG, "unable to zip up heapdumps", e); - body.append("\n** Could not zip up files: \n").append(e.toString()).append("\n"); - } - - return this; - } - - /** - * Get the Uri of the current heap dump. Be sure to call captureHeaps first. - * - * @return Uri to the dump served by the SystemUI file provider - */ - public Uri getDumpUri() { - return hprofUri; - } - - /** - * Get an ACTION_SEND intent suitable for startActivity() or attaching to a Notification. - * - * @return share intent - */ - public Intent createShareIntent() { - Intent shareIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); - shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - shareIntent.putExtra(Intent.EXTRA_SUBJECT, - String.format("SystemUI memory dump (rss=%dM)", rss / 1024)); - - shareIntent.putExtra(Intent.EXTRA_TEXT, body.toString()); - - if (hprofUri != null) { - final ArrayList<Uri> uriList = new ArrayList<>(); - uriList.add(hprofUri); - shareIntent.setType("application/zip"); - shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uriList); - - // Include URI in ClipData also, so that grantPermission picks it up. - // We don't use setData here because some apps interpret this as "to:". - ClipData clipdata = new ClipData(new ClipDescription("content", - new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}), - new ClipData.Item(hprofUri)); - shareIntent.setClipData(clipdata); - shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - } - return shareIntent; - } - - private static boolean zipUp(String zipfilePath, ArrayList<String> paths) { - try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipfilePath))) { - final byte[] buf = new byte[BUFSIZ]; - - for (String filename : paths) { - try (InputStream is = new BufferedInputStream(new FileInputStream(filename))) { - ZipEntry entry = new ZipEntry(filename); - zos.putNextEntry(entry); - int len; - while (0 < (len = is.read(buf, 0, BUFSIZ))) { - zos.write(buf, 0, len); - } - zos.closeEntry(); - } - } - return true; - } catch (IOException e) { - Log.e(TAG, "error zipping up profile data", e); - } - return false; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java deleted file mode 100644 index de392d3f444f..000000000000 --- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Copyright (C) 2017 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 - */ - -package com.android.systemui.util.leak; - -import static android.service.quicksettings.Tile.STATE_ACTIVE; -import static android.telephony.ims.feature.ImsFeature.STATE_UNAVAILABLE; - -import static com.android.internal.logging.MetricsLogger.VIEW_UNKNOWN; - -import android.annotation.Nullable; -import android.app.ActivityManager; -import android.content.Context; -import android.content.Intent; -import android.content.res.ColorStateList; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.os.Process; -import android.os.SystemProperties; -import android.provider.Settings; -import android.text.format.DateUtils; -import android.util.Log; -import android.util.LongSparseArray; -import android.view.View; - -import com.android.internal.logging.MetricsLogger; -import com.android.systemui.CoreStartable; -import com.android.systemui.Dumpable; -import com.android.systemui.res.R; -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.dagger.qualifiers.Background; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dump.DumpManager; -import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.plugins.qs.QSTile; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.qs.QSHost; -import com.android.systemui.qs.QsEventLogger; -import com.android.systemui.qs.logging.QSLogger; -import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor; -import com.android.systemui.qs.tileimpl.QSTileImpl; -import com.android.systemui.util.concurrency.DelayableExecutor; -import com.android.systemui.util.concurrency.MessageRouter; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - -/** - * Suite of tools to periodically inspect the System UI heap and possibly prompt the user to - * capture heap dumps and report them. Includes the implementation of the "Dump SysUI Heap" - * quick settings tile. - */ -@SysUISingleton -public class GarbageMonitor implements Dumpable { - // Feature switches - // ================ - - // Whether to use TrackedGarbage to trigger LeakReporter. Off by default unless you set the - // appropriate sysprop on a userdebug device. - public static final boolean LEAK_REPORTING_ENABLED = Build.IS_DEBUGGABLE - && SystemProperties.getBoolean("debug.enable_leak_reporting", false); - public static final String FORCE_ENABLE_LEAK_REPORTING = "sysui_force_enable_leak_reporting"; - - // Heap tracking: watch the current memory levels and update the MemoryTile if available. - // On for all userdebug devices. - public static final boolean HEAP_TRACKING_ENABLED = Build.IS_DEBUGGABLE; - - // Tell QSTileHost.java to toss this into the default tileset? - public static final boolean ADD_MEMORY_TILE_TO_DEFAULT_ON_DEBUGGABLE_BUILDS = true; - - // whether to use ActivityManager.setHeapLimit (and post a notification to the user asking - // to dump the heap). Off by default unless you set the appropriate sysprop on userdebug - private static final boolean ENABLE_AM_HEAP_LIMIT = Build.IS_DEBUGGABLE - && SystemProperties.getBoolean("debug.enable_sysui_heap_limit", false); - - // Tuning params - // ============= - - // threshold for setHeapLimit(), in KB (overrides R.integer.watch_heap_limit) - private static final String SETTINGS_KEY_AM_HEAP_LIMIT = "systemui_am_heap_limit"; - - private static final long GARBAGE_INSPECTION_INTERVAL = - 15 * DateUtils.MINUTE_IN_MILLIS; // 15 min - private static final long HEAP_TRACK_INTERVAL = 1 * DateUtils.MINUTE_IN_MILLIS; // 1 min - private static final int HEAP_TRACK_HISTORY_LEN = 720; // 12 hours - - private static final int DO_GARBAGE_INSPECTION = 1000; - private static final int DO_HEAP_TRACK = 3000; - - static final int GARBAGE_ALLOWANCE = 5; - - private static final String TAG = "GarbageMonitor"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private final MessageRouter mMessageRouter; - private final TrackedGarbage mTrackedGarbage; - private final LeakReporter mLeakReporter; - private final Context mContext; - private final DelayableExecutor mDelayableExecutor; - private MemoryTile mQSTile; - private final DumpTruck mDumpTruck; - - private final LongSparseArray<ProcessMemInfo> mData = new LongSparseArray<>(); - private final ArrayList<Long> mPids = new ArrayList<>(); - - private long mHeapLimit; - - /** - */ - @Inject - public GarbageMonitor( - Context context, - @Background DelayableExecutor delayableExecutor, - @Background MessageRouter messageRouter, - LeakDetector leakDetector, - LeakReporter leakReporter, - DumpManager dumpManager) { - mContext = context.getApplicationContext(); - - mDelayableExecutor = delayableExecutor; - mMessageRouter = messageRouter; - mMessageRouter.subscribeTo(DO_GARBAGE_INSPECTION, this::doGarbageInspection); - mMessageRouter.subscribeTo(DO_HEAP_TRACK, this::doHeapTrack); - - mTrackedGarbage = leakDetector.getTrackedGarbage(); - mLeakReporter = leakReporter; - - mDumpTruck = new DumpTruck(mContext, this); - - dumpManager.registerDumpable(getClass().getSimpleName(), this); - - if (ENABLE_AM_HEAP_LIMIT) { - mHeapLimit = Settings.Global.getInt(context.getContentResolver(), - SETTINGS_KEY_AM_HEAP_LIMIT, - mContext.getResources().getInteger(R.integer.watch_heap_limit)); - } - } - - public void startLeakMonitor() { - if (mTrackedGarbage == null) { - return; - } - - mMessageRouter.sendMessage(DO_GARBAGE_INSPECTION); - } - - public void startHeapTracking() { - startTrackingProcess( - android.os.Process.myPid(), mContext.getPackageName(), System.currentTimeMillis()); - mMessageRouter.sendMessage(DO_HEAP_TRACK); - } - - private boolean gcAndCheckGarbage() { - if (mTrackedGarbage.countOldGarbage() > GARBAGE_ALLOWANCE) { - Runtime.getRuntime().gc(); - return true; - } - return false; - } - - void reinspectGarbageAfterGc() { - int count = mTrackedGarbage.countOldGarbage(); - if (count > GARBAGE_ALLOWANCE) { - mLeakReporter.dumpLeak(count); - } - } - - public ProcessMemInfo getMemInfo(int pid) { - return mData.get(pid); - } - - public List<Long> getTrackedProcesses() { - return mPids; - } - - public void startTrackingProcess(long pid, String name, long start) { - synchronized (mPids) { - if (mPids.contains(pid)) return; - - mPids.add(pid); - logPids(); - - mData.put(pid, new ProcessMemInfo(pid, name, start)); - } - } - - private void logPids() { - if (DEBUG) { - StringBuffer sb = new StringBuffer("Now tracking processes: "); - for (int i = 0; i < mPids.size(); i++) { - final int p = mPids.get(i).intValue(); - sb.append(" "); - } - Log.v(TAG, sb.toString()); - } - } - - private void update() { - synchronized (mPids) { - for (int i = 0; i < mPids.size(); i++) { - final int pid = mPids.get(i).intValue(); - // rssValues contains [VmRSS, RssFile, RssAnon, VmSwap]. - long[] rssValues = Process.getRss(pid); - if (rssValues == null && rssValues.length == 0) { - if (DEBUG) Log.e(TAG, "update: Process.getRss() didn't provide any values."); - break; - } - long rss = rssValues[0]; - final ProcessMemInfo info = mData.get(pid); - info.rss[info.head] = info.currentRss = rss; - info.head = (info.head + 1) % info.rss.length; - if (info.currentRss > info.max) info.max = info.currentRss; - if (info.currentRss == 0) { - if (DEBUG) Log.v(TAG, "update: pid " + pid + " has rss=0, it probably died"); - mData.remove(pid); - } - } - for (int i = mPids.size() - 1; i >= 0; i--) { - final long pid = mPids.get(i).intValue(); - if (mData.get(pid) == null) { - mPids.remove(i); - logPids(); - } - } - } - if (mQSTile != null) mQSTile.update(); - } - - private void setTile(MemoryTile tile) { - mQSTile = tile; - if (tile != null) tile.update(); - } - - private static String formatBytes(long b) { - String[] SUFFIXES = {"B", "K", "M", "G", "T"}; - int i; - for (i = 0; i < SUFFIXES.length; i++) { - if (b < 1024) break; - b /= 1024; - } - return b + SUFFIXES[i]; - } - - private Intent dumpHprofAndGetShareIntent() { - return mDumpTruck.captureHeaps(getTrackedProcesses()).createShareIntent(); - } - - @Override - public void dump(PrintWriter pw, @Nullable String[] args) { - pw.println("GarbageMonitor params:"); - pw.println(String.format(" mHeapLimit=%d KB", mHeapLimit)); - pw.println(String.format(" GARBAGE_INSPECTION_INTERVAL=%d (%.1f mins)", - GARBAGE_INSPECTION_INTERVAL, - (float) GARBAGE_INSPECTION_INTERVAL / DateUtils.MINUTE_IN_MILLIS)); - final float htiMins = HEAP_TRACK_INTERVAL / DateUtils.MINUTE_IN_MILLIS; - pw.println(String.format(" HEAP_TRACK_INTERVAL=%d (%.1f mins)", - HEAP_TRACK_INTERVAL, - htiMins)); - pw.println(String.format(" HEAP_TRACK_HISTORY_LEN=%d (%.1f hr total)", - HEAP_TRACK_HISTORY_LEN, - (float) HEAP_TRACK_HISTORY_LEN * htiMins / 60f)); - - pw.println("GarbageMonitor tracked processes:"); - - for (long pid : mPids) { - final ProcessMemInfo pmi = mData.get(pid); - if (pmi != null) { - pmi.dump(pw, args); - } - } - } - - - private static class MemoryIconDrawable extends Drawable { - long rss, limit; - final Drawable baseIcon; - final Paint paint = new Paint(); - final float dp; - - MemoryIconDrawable(Context context) { - baseIcon = context.getDrawable(R.drawable.ic_memory).mutate(); - dp = context.getResources().getDisplayMetrics().density; - paint.setColor(Color.WHITE); - } - - public void setRss(long rss) { - if (rss != this.rss) { - this.rss = rss; - invalidateSelf(); - } - } - - public void setLimit(long limit) { - if (limit != this.limit) { - this.limit = limit; - invalidateSelf(); - } - } - - @Override - public void draw(Canvas canvas) { - baseIcon.draw(canvas); - - if (limit > 0 && rss > 0) { - float frac = Math.min(1f, (float) rss / limit); - - final Rect bounds = getBounds(); - canvas.translate(bounds.left + 8 * dp, bounds.top + 5 * dp); - //android:pathData="M16.0,5.0l-8.0,0.0l0.0,14.0l8.0,0.0z" - canvas.drawRect(0, 14 * dp * (1 - frac), 8 * dp + 1, 14 * dp + 1, paint); - } - } - - @Override - public void setBounds(int left, int top, int right, int bottom) { - super.setBounds(left, top, right, bottom); - baseIcon.setBounds(left, top, right, bottom); - } - - @Override - public int getIntrinsicHeight() { - return baseIcon.getIntrinsicHeight(); - } - - @Override - public int getIntrinsicWidth() { - return baseIcon.getIntrinsicWidth(); - } - - @Override - public void setAlpha(int i) { - baseIcon.setAlpha(i); - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - baseIcon.setColorFilter(colorFilter); - paint.setColorFilter(colorFilter); - } - - @Override - public void setTint(int tint) { - super.setTint(tint); - baseIcon.setTint(tint); - } - - @Override - public void setTintList(ColorStateList tint) { - super.setTintList(tint); - baseIcon.setTintList(tint); - } - - @Override - public void setTintMode(PorterDuff.Mode tintMode) { - super.setTintMode(tintMode); - baseIcon.setTintMode(tintMode); - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - } - - private static class MemoryGraphIcon extends QSTile.Icon { - long rss, limit; - - public void setRss(long rss) { - this.rss = rss; - } - - public void setHeapLimit(long limit) { - this.limit = limit; - } - - @Override - public Drawable getDrawable(Context context) { - final MemoryIconDrawable drawable = new MemoryIconDrawable(context); - drawable.setRss(rss); - drawable.setLimit(limit); - return drawable; - } - } - - public static class MemoryTile extends QSTileImpl<QSTile.State> { - public static final String TILE_SPEC = "dbg:mem"; - - private final GarbageMonitor gm; - private ProcessMemInfo pmi; - private boolean dumpInProgress; - private final PanelInteractor mPanelInteractor; - - @Inject - public MemoryTile( - QSHost host, - QsEventLogger uiEventLogger, - @Background Looper backgroundLooper, - @Main Handler mainHandler, - FalsingManager falsingManager, - MetricsLogger metricsLogger, - StatusBarStateController statusBarStateController, - ActivityStarter activityStarter, - QSLogger qsLogger, - GarbageMonitor monitor, - PanelInteractor panelInteractor - ) { - super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, - statusBarStateController, activityStarter, qsLogger); - gm = monitor; - mPanelInteractor = panelInteractor; - } - - @Override - public State newTileState() { - return new QSTile.State(); - } - - @Override - public Intent getLongClickIntent() { - return new Intent(); - } - - @Override - protected void handleClick(@Nullable View view) { - if (dumpInProgress) return; - - dumpInProgress = true; - refreshState(); - new Thread("HeapDumpThread") { - @Override - public void run() { - try { - // wait for animations & state changes - Thread.sleep(500); - } catch (InterruptedException ignored) { } - final Intent shareIntent = gm.dumpHprofAndGetShareIntent(); - mHandler.post(() -> { - dumpInProgress = false; - refreshState(); - mPanelInteractor.collapsePanels(); - mActivityStarter.postStartActivityDismissingKeyguard(shareIntent, 0); - }); - } - }.start(); - } - - @Override - public int getMetricsCategory() { - return VIEW_UNKNOWN; - } - - @Override - public void handleSetListening(boolean listening) { - super.handleSetListening(listening); - if (gm != null) gm.setTile(listening ? this : null); - - final ActivityManager am = mContext.getSystemService(ActivityManager.class); - if (listening && gm.mHeapLimit > 0) { - am.setWatchHeapLimit(1024 * gm.mHeapLimit); // why is this in bytes? - } else { - am.clearWatchHeapLimit(); - } - } - - @Override - public CharSequence getTileLabel() { - return getState().label; - } - - @Override - protected void handleUpdateState(State state, Object arg) { - pmi = gm.getMemInfo(Process.myPid()); - final MemoryGraphIcon icon = new MemoryGraphIcon(); - icon.setHeapLimit(gm.mHeapLimit); - state.state = dumpInProgress ? STATE_UNAVAILABLE : STATE_ACTIVE; - state.label = dumpInProgress - ? "Dumping..." - : mContext.getString(R.string.heap_dump_tile_name); - if (pmi != null) { - icon.setRss(pmi.currentRss); - state.secondaryLabel = - String.format( - "rss: %s / %s", - formatBytes(pmi.currentRss * 1024), - formatBytes(gm.mHeapLimit * 1024)); - } else { - icon.setRss(0); - state.secondaryLabel = null; - } - state.icon = icon; - } - - public void update() { - refreshState(); - } - - public long getRss() { - return pmi != null ? pmi.currentRss : 0; - } - - public long getHeapLimit() { - return gm != null ? gm.mHeapLimit : 0; - } - } - - /** */ - public static class ProcessMemInfo implements Dumpable { - public long pid; - public String name; - public long startTime; - public long currentRss; - public long[] rss = new long[HEAP_TRACK_HISTORY_LEN]; - public long max = 1; - public int head = 0; - - public ProcessMemInfo(long pid, String name, long start) { - this.pid = pid; - this.name = name; - this.startTime = start; - } - - public long getUptime() { - return System.currentTimeMillis() - startTime; - } - - @Override - public void dump(PrintWriter pw, @Nullable String[] args) { - pw.print("{ \"pid\": "); - pw.print(pid); - pw.print(", \"name\": \""); - pw.print(name.replace('"', '-')); - pw.print("\", \"start\": "); - pw.print(startTime); - pw.print(", \"rss\": ["); - // write rss values starting from the oldest, which is rss[head], wrapping around to - // rss[(head-1) % rss.length] - for (int i = 0; i < rss.length; i++) { - if (i > 0) pw.print(","); - pw.print(rss[(head + i) % rss.length]); - } - pw.println("] }"); - } - } - - /** */ - @SysUISingleton - public static class Service implements CoreStartable, Dumpable { - private final Context mContext; - private final GarbageMonitor mGarbageMonitor; - - @Inject - public Service(Context context, GarbageMonitor garbageMonitor) { - mContext = context; - mGarbageMonitor = garbageMonitor; - } - - @Override - public void start() { - boolean forceEnable = - Settings.Secure.getInt( - mContext.getContentResolver(), FORCE_ENABLE_LEAK_REPORTING, 0) - != 0; - if (LEAK_REPORTING_ENABLED || forceEnable) { - mGarbageMonitor.startLeakMonitor(); - } - if (HEAP_TRACKING_ENABLED || forceEnable) { - mGarbageMonitor.startHeapTracking(); - } - } - - @Override - public void dump(PrintWriter pw, @Nullable String[] args) { - if (mGarbageMonitor != null) mGarbageMonitor.dump(pw, args); - } - } - - private void doGarbageInspection(int id) { - if (gcAndCheckGarbage()) { - mDelayableExecutor.executeDelayed(this::reinspectGarbageAfterGc, 100); - } - - mMessageRouter.cancelMessages(DO_GARBAGE_INSPECTION); - mMessageRouter.sendMessageDelayed(DO_GARBAGE_INSPECTION, GARBAGE_INSPECTION_INTERVAL); - } - - private void doHeapTrack(int id) { - update(); - mMessageRouter.cancelMessages(DO_HEAP_TRACK); - mMessageRouter.sendMessageDelayed(DO_HEAP_TRACK, HEAP_TRACK_INTERVAL); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitorModule.kt b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitorModule.kt deleted file mode 100644 index e975200e4d52..000000000000 --- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitorModule.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2021 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. - */ - -package com.android.systemui.util.leak - -import com.android.systemui.CoreStartable -import com.android.systemui.qs.tileimpl.QSTileImpl -import dagger.Binds -import dagger.Module -import dagger.multibindings.ClassKey -import dagger.multibindings.IntoMap -import dagger.multibindings.StringKey - -@Module -interface GarbageMonitorModule { - /** Inject into GarbageMonitor.Service. */ - @Binds - @IntoMap - @ClassKey(GarbageMonitor::class) - fun bindGarbageMonitorService(sysui: GarbageMonitor.Service): CoreStartable - - @Binds - @IntoMap - @StringKey(GarbageMonitor.MemoryTile.TILE_SPEC) - fun bindMemoryTile(memoryTile: GarbageMonitor.MemoryTile): QSTileImpl<*> -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 5e2423a8b373..ef7798e545d3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -447,10 +447,6 @@ public class QSTileHostTest extends SysuiTestCase { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1,spec1"); List<String> specs = QSTileHost.loadTileSpecs(mContext, "default"); - - // Remove spurious tiles, like dbg:mem - specs.removeIf(spec -> !"spec1".equals(spec)); - assertEquals(1, specs.size()); } @Test @@ -458,10 +454,6 @@ public class QSTileHostTest extends SysuiTestCase { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1"); List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1"); - - // Remove spurious tiles, like dbg:mem - specs.removeIf(spec -> !"spec1".equals(spec)); - assertEquals(1, specs.size()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt index 067218a9c983..5201e5d9ccf7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt @@ -50,7 +50,6 @@ import com.android.systemui.qs.tiles.RotationLockTile import com.android.systemui.qs.tiles.ScreenRecordTile import com.android.systemui.qs.tiles.UiModeNightTile import com.android.systemui.qs.tiles.WorkModeTile -import com.android.systemui.util.leak.GarbageMonitor import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -117,7 +116,6 @@ class QSFactoryImplTest : SysuiTestCase() { @Mock private lateinit var dataSaverTile: DataSaverTile @Mock private lateinit var nightDisplayTile: NightDisplayTile @Mock private lateinit var nfcTile: NfcTile - @Mock private lateinit var memoryTile: GarbageMonitor.MemoryTile @Mock private lateinit var darkModeTile: UiModeNightTile @Mock private lateinit var screenRecordTile: ScreenRecordTile @Mock private lateinit var reduceBrightColorsTile: ReduceBrightColorsTile diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/GarbageMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/GarbageMonitorTest.java deleted file mode 100644 index a2b016f22473..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/util/leak/GarbageMonitorTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2017 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 - */ - -package com.android.systemui.util.leak; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.testing.AndroidTestingRunner; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.dump.DumpManager; -import com.android.systemui.util.concurrency.FakeExecutor; -import com.android.systemui.util.concurrency.MessageRouterImpl; -import com.android.systemui.util.time.FakeSystemClock; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -public class GarbageMonitorTest extends SysuiTestCase { - - @Mock private LeakReporter mLeakReporter; - @Mock private TrackedGarbage mTrackedGarbage; - @Mock private DumpManager mDumpManager; - private GarbageMonitor mGarbageMonitor; - private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - mGarbageMonitor = - new GarbageMonitor( - mContext, - mFakeExecutor, - new MessageRouterImpl(mFakeExecutor), - new LeakDetector(null, mTrackedGarbage, null, mDumpManager), - mLeakReporter, - mDumpManager); - } - - @Test - public void testALittleGarbage_doesntDump() { - when(mTrackedGarbage.countOldGarbage()).thenReturn(GarbageMonitor.GARBAGE_ALLOWANCE); - - mGarbageMonitor.reinspectGarbageAfterGc(); - - verify(mLeakReporter, never()).dumpLeak(anyInt()); - } - - @Test - public void testTransientGarbage_doesntDump() { - when(mTrackedGarbage.countOldGarbage()).thenReturn(GarbageMonitor.GARBAGE_ALLOWANCE + 1); - - // Start the leak monitor. Nothing gets reported immediately. - mGarbageMonitor.startLeakMonitor(); - mFakeExecutor.runAllReady(); - verify(mLeakReporter, never()).dumpLeak(anyInt()); - - // Garbage gets reset to 0 before the leak reporte actually gets called. - when(mTrackedGarbage.countOldGarbage()).thenReturn(0); - mFakeExecutor.advanceClockToLast(); - mFakeExecutor.runAllReady(); - - // Therefore nothing gets dumped. - verify(mLeakReporter, never()).dumpLeak(anyInt()); - } - - @Test - public void testLotsOfPersistentGarbage_dumps() { - when(mTrackedGarbage.countOldGarbage()).thenReturn(GarbageMonitor.GARBAGE_ALLOWANCE + 1); - - mGarbageMonitor.reinspectGarbageAfterGc(); - - verify(mLeakReporter).dumpLeak(GarbageMonitor.GARBAGE_ALLOWANCE + 1); - } - - @Test - public void testLotsOfPersistentGarbage_dumpsAfterAtime() { - when(mTrackedGarbage.countOldGarbage()).thenReturn(GarbageMonitor.GARBAGE_ALLOWANCE + 1); - - // Start the leak monitor. Nothing gets reported immediately. - mGarbageMonitor.startLeakMonitor(); - mFakeExecutor.runAllReady(); - verify(mLeakReporter, never()).dumpLeak(anyInt()); - - mFakeExecutor.advanceClockToLast(); - mFakeExecutor.runAllReady(); - - verify(mLeakReporter).dumpLeak(GarbageMonitor.GARBAGE_ALLOWANCE + 1); - } -}
\ No newline at end of file |