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