1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.applications; 18 19 import android.app.settings.SettingsEnums; 20 import android.content.Context; 21 import android.content.pm.PackageManager; 22 import android.os.Bundle; 23 import android.util.Log; 24 import android.util.TimeUtils; 25 import android.view.Menu; 26 import android.view.MenuInflater; 27 import android.view.MenuItem; 28 29 import androidx.preference.Preference; 30 import androidx.preference.PreferenceGroup; 31 32 import com.android.internal.app.procstats.ProcessStats; 33 import com.android.settings.R; 34 import com.android.settings.SettingsActivity; 35 import com.android.settings.applications.ProcStatsData.MemInfo; 36 37 import java.util.Collections; 38 import java.util.Comparator; 39 import java.util.List; 40 41 public class ProcessStatsUi extends ProcessStatsBase { 42 static final String TAG = "ProcessStatsUi"; 43 static final boolean DEBUG = false; 44 45 private static final String KEY_APP_LIST = "app_list"; 46 47 private static final int MENU_SHOW_AVG = Menu.FIRST; 48 private static final int MENU_SHOW_MAX = Menu.FIRST + 1; 49 50 private PreferenceGroup mAppListGroup; 51 private PackageManager mPm; 52 53 private boolean mShowMax; 54 private MenuItem mMenuAvg; 55 private MenuItem mMenuMax; 56 57 @Override onCreate(Bundle icicle)58 public void onCreate(Bundle icicle) { 59 super.onCreate(icicle); 60 61 mPm = getActivity().getPackageManager(); 62 63 addPreferencesFromResource(R.xml.process_stats_ui); 64 mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST); 65 setHasOptionsMenu(true); 66 } 67 68 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)69 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 70 super.onCreateOptionsMenu(menu, inflater); 71 mMenuAvg = menu.add(0, MENU_SHOW_AVG, 0, R.string.sort_avg_use); 72 mMenuMax = menu.add(0, MENU_SHOW_MAX, 0, R.string.sort_max_use); 73 updateMenu(); 74 } 75 76 @Override onOptionsItemSelected(MenuItem item)77 public boolean onOptionsItemSelected(MenuItem item) { 78 switch (item.getItemId()) { 79 case MENU_SHOW_AVG: 80 case MENU_SHOW_MAX: 81 mShowMax = !mShowMax; 82 refreshUi(); 83 updateMenu(); 84 return true; 85 } 86 return super.onOptionsItemSelected(item); 87 } 88 updateMenu()89 private void updateMenu() { 90 mMenuMax.setVisible(!mShowMax); 91 mMenuAvg.setVisible(mShowMax); 92 } 93 94 @Override getMetricsCategory()95 public int getMetricsCategory() { 96 return SettingsEnums.APPLICATIONS_PROCESS_STATS_UI; 97 } 98 99 @Override getHelpResource()100 public int getHelpResource() { 101 return R.string.help_uri_process_stats_apps; 102 } 103 104 @Override onSaveInstanceState(Bundle outState)105 public void onSaveInstanceState(Bundle outState) { 106 super.onSaveInstanceState(outState); 107 } 108 109 @Override onPreferenceTreeClick(Preference preference)110 public boolean onPreferenceTreeClick(Preference preference) { 111 if (!(preference instanceof ProcessStatsPreference)) { 112 return false; 113 } 114 ProcessStatsPreference pgp = (ProcessStatsPreference) preference; 115 MemInfo memInfo = mStatsManager.getMemInfo(); 116 launchMemoryDetail((SettingsActivity) getActivity(), memInfo, pgp.getEntry(), true); 117 118 return super.onPreferenceTreeClick(preference); 119 } 120 121 /** 122 * All states in which we consider a process to be actively running (rather than 123 * something that can be freely killed to reclaim RAM). Note this also includes 124 * the HOME state, because we prioritize home over all cached processes even when 125 * it is in the background, so it is effectively always running from the perspective 126 * of the information we want to show the user here. 127 */ 128 public static final int[] BACKGROUND_AND_SYSTEM_PROC_STATES = new int[] { 129 ProcessStats.STATE_PERSISTENT, ProcessStats.STATE_IMPORTANT_FOREGROUND, 130 ProcessStats.STATE_IMPORTANT_BACKGROUND, ProcessStats.STATE_BACKUP, 131 ProcessStats.STATE_HEAVY_WEIGHT, ProcessStats.STATE_SERVICE, 132 ProcessStats.STATE_SERVICE_RESTARTING, ProcessStats.STATE_RECEIVER, 133 ProcessStats.STATE_HOME 134 }; 135 136 public static final int[] FOREGROUND_PROC_STATES = new int[] { 137 ProcessStats.STATE_TOP 138 }; 139 140 public static final int[] CACHED_PROC_STATES = new int[] { 141 ProcessStats.STATE_CACHED_ACTIVITY, ProcessStats.STATE_CACHED_ACTIVITY_CLIENT, 142 ProcessStats.STATE_CACHED_EMPTY 143 }; 144 makeDuration(long time)145 public static String makeDuration(long time) { 146 StringBuilder sb = new StringBuilder(32); 147 TimeUtils.formatDuration(time, sb); 148 return sb.toString(); 149 } 150 151 @Override refreshUi()152 public void refreshUi() { 153 mAppListGroup.removeAll(); 154 mAppListGroup.setOrderingAsAdded(false); 155 mAppListGroup.setTitle(mShowMax ? R.string.maximum_memory_use 156 : R.string.average_memory_use); 157 158 final Context context = getActivity(); 159 MemInfo memInfo = mStatsManager.getMemInfo(); 160 161 List<ProcStatsPackageEntry> pkgEntries = mStatsManager.getEntries(); 162 163 // Update everything and get the absolute maximum of memory usage for scaling. 164 for (int i=0, N=pkgEntries.size(); i<N; i++) { 165 ProcStatsPackageEntry pkg = pkgEntries.get(i); 166 pkg.updateMetrics(); 167 } 168 169 Collections.sort(pkgEntries, mShowMax ? sMaxPackageEntryCompare : sPackageEntryCompare); 170 171 // Now collect the per-process information into applications, so that applications 172 // running as multiple processes will have only one entry representing all of them. 173 174 if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI"); 175 176 double maxMemory = mShowMax ? memInfo.realTotalRam 177 : memInfo.usedWeight * memInfo.weightToRam; 178 for (int i = 0; i < pkgEntries.size(); i++) { 179 ProcStatsPackageEntry pkg = pkgEntries.get(i); 180 ProcessStatsPreference pref = new ProcessStatsPreference(getPrefContext()); 181 pkg.retrieveUiData(context, mPm); 182 pref.init(pkg, mPm, maxMemory, memInfo.weightToRam, 183 memInfo.totalScale, !mShowMax); 184 pref.setOrder(i); 185 mAppListGroup.addPreference(pref); 186 } 187 } 188 189 final static Comparator<ProcStatsPackageEntry> sPackageEntryCompare 190 = new Comparator<ProcStatsPackageEntry>() { 191 @Override 192 public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { 193 double rhsWeight = Math.max(rhs.mRunWeight, rhs.mBgWeight); 194 double lhsWeight = Math.max(lhs.mRunWeight, lhs.mBgWeight); 195 if (lhsWeight == rhsWeight) { 196 return 0; 197 } 198 return lhsWeight < rhsWeight ? 1 : -1; 199 } 200 }; 201 202 final static Comparator<ProcStatsPackageEntry> sMaxPackageEntryCompare 203 = new Comparator<ProcStatsPackageEntry>() { 204 @Override 205 public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { 206 double rhsMax = Math.max(rhs.mMaxBgMem, rhs.mMaxRunMem); 207 double lhsMax = Math.max(lhs.mMaxBgMem, lhs.mMaxRunMem); 208 if (lhsMax == rhsMax) { 209 return 0; 210 } 211 return lhsMax < rhsMax ? 1 : -1; 212 } 213 }; 214 } 215