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.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 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 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 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 88 private void updateMenu() { 89 mMenuMax.setVisible(!mShowMax); 90 mMenuAvg.setVisible(mShowMax); 91 } 92 93 @Override 94 protected int getMetricsCategory() { 95 return MetricsEvent.APPLICATIONS_PROCESS_STATS_UI; 96 } 97 98 @Override 99 public void onSaveInstanceState(Bundle outState) { 100 super.onSaveInstanceState(outState); 101 } 102 103 @Override 104 public boolean onPreferenceTreeClick(Preference preference) { 105 if (!(preference instanceof ProcessStatsPreference)) { 106 return false; 107 } 108 ProcessStatsPreference pgp = (ProcessStatsPreference) preference; 109 MemInfo memInfo = mStatsManager.getMemInfo(); 110 launchMemoryDetail((SettingsActivity) getActivity(), memInfo, pgp.getEntry(), true); 111 112 return super.onPreferenceTreeClick(preference); 113 } 114 115 /** 116 * All states in which we consider a process to be actively running (rather than 117 * something that can be freely killed to reclaim RAM). Note this also includes 118 * the HOME state, because we prioritize home over all cached processes even when 119 * it is in the background, so it is effectively always running from the perspective 120 * of the information we want to show the user here. 121 */ 122 public static final int[] BACKGROUND_AND_SYSTEM_PROC_STATES = new int[] { 123 ProcessStats.STATE_PERSISTENT, ProcessStats.STATE_IMPORTANT_FOREGROUND, 124 ProcessStats.STATE_IMPORTANT_BACKGROUND, ProcessStats.STATE_BACKUP, 125 ProcessStats.STATE_HEAVY_WEIGHT, ProcessStats.STATE_SERVICE, 126 ProcessStats.STATE_SERVICE_RESTARTING, ProcessStats.STATE_RECEIVER, 127 ProcessStats.STATE_HOME 128 }; 129 130 public static final int[] FOREGROUND_PROC_STATES = new int[] { 131 ProcessStats.STATE_TOP 132 }; 133 134 public static final int[] CACHED_PROC_STATES = new int[] { 135 ProcessStats.STATE_CACHED_ACTIVITY, ProcessStats.STATE_CACHED_ACTIVITY_CLIENT, 136 ProcessStats.STATE_CACHED_EMPTY 137 }; 138 139 public static String makeDuration(long time) { 140 StringBuilder sb = new StringBuilder(32); 141 TimeUtils.formatDuration(time, sb); 142 return sb.toString(); 143 } 144 145 @Override 146 public void refreshUi() { 147 mAppListGroup.removeAll(); 148 mAppListGroup.setOrderingAsAdded(false); 149 mAppListGroup.setTitle(mShowMax ? R.string.maximum_memory_use 150 : R.string.average_memory_use); 151 152 final Context context = getActivity(); 153 MemInfo memInfo = mStatsManager.getMemInfo(); 154 155 List<ProcStatsPackageEntry> pkgEntries = mStatsManager.getEntries(); 156 157 // Update everything and get the absolute maximum of memory usage for scaling. 158 for (int i=0, N=pkgEntries.size(); i<N; i++) { 159 ProcStatsPackageEntry pkg = pkgEntries.get(i); 160 pkg.updateMetrics(); 161 } 162 163 Collections.sort(pkgEntries, mShowMax ? sMaxPackageEntryCompare : sPackageEntryCompare); 164 165 // Now collect the per-process information into applications, so that applications 166 // running as multiple processes will have only one entry representing all of them. 167 168 if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI"); 169 170 double maxMemory = mShowMax ? memInfo.realTotalRam 171 : memInfo.usedWeight * memInfo.weightToRam; 172 for (int i = 0; i < pkgEntries.size(); i++) { 173 ProcStatsPackageEntry pkg = pkgEntries.get(i); 174 ProcessStatsPreference pref = new ProcessStatsPreference(getPrefContext()); 175 pkg.retrieveUiData(context, mPm); 176 pref.init(pkg, mPm, maxMemory, memInfo.weightToRam, 177 memInfo.totalScale, !mShowMax); 178 pref.setOrder(i); 179 mAppListGroup.addPreference(pref); 180 } 181 } 182 183 final static Comparator<ProcStatsPackageEntry> sPackageEntryCompare 184 = new Comparator<ProcStatsPackageEntry>() { 185 @Override 186 public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { 187 double rhsWeight = Math.max(rhs.mRunWeight, rhs.mBgWeight); 188 double lhsWeight = Math.max(lhs.mRunWeight, lhs.mBgWeight); 189 if (lhsWeight == rhsWeight) { 190 return 0; 191 } 192 return lhsWeight < rhsWeight ? 1 : -1; 193 } 194 }; 195 196 final static Comparator<ProcStatsPackageEntry> sMaxPackageEntryCompare 197 = new Comparator<ProcStatsPackageEntry>() { 198 @Override 199 public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { 200 double rhsMax = Math.max(rhs.mMaxBgMem, rhs.mMaxRunMem); 201 double lhsMax = Math.max(lhs.mMaxBgMem, lhs.mMaxRunMem); 202 if (lhsMax == rhsMax) { 203 return 0; 204 } 205 return lhsMax < rhsMax ? 1 : -1; 206 } 207 }; 208 } 209