Home | History | Annotate | Download | only in applications
      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.ActivityManager;
     20 import android.content.Context;
     21 import android.content.pm.PackageManager;
     22 import android.os.Bundle;
     23 import android.os.ParcelFileDescriptor;
     24 import android.os.RemoteException;
     25 import android.os.ServiceManager;
     26 import android.os.SystemClock;
     27 import android.os.UserManager;
     28 import android.preference.Preference;
     29 import android.preference.PreferenceFragment;
     30 import android.preference.PreferenceGroup;
     31 import android.preference.PreferenceScreen;
     32 import android.text.format.Formatter;
     33 import android.util.Log;
     34 import android.util.SparseArray;
     35 import android.util.TimeUtils;
     36 import android.view.Menu;
     37 import android.view.MenuInflater;
     38 import android.view.MenuItem;
     39 import android.view.SubMenu;
     40 import com.android.internal.app.IProcessStats;
     41 import com.android.internal.app.ProcessMap;
     42 import com.android.internal.app.ProcessStats;
     43 import com.android.internal.util.MemInfoReader;
     44 import com.android.settings.R;
     45 import com.android.settings.SettingsActivity;
     46 import com.android.settings.Utils;
     47 
     48 import java.io.IOException;
     49 import java.io.InputStream;
     50 import java.util.ArrayList;
     51 import java.util.Collections;
     52 import java.util.Comparator;
     53 
     54 public class ProcessStatsUi extends PreferenceFragment
     55         implements LinearColorBar.OnRegionTappedListener {
     56     static final String TAG = "ProcessStatsUi";
     57     static final boolean DEBUG = false;
     58 
     59     private static final String KEY_APP_LIST = "app_list";
     60     private static final String KEY_MEM_STATUS = "mem_status";
     61 
     62     private static final int NUM_DURATIONS = 4;
     63 
     64     private static final int MENU_STATS_REFRESH = Menu.FIRST;
     65     private static final int MENU_DURATION = Menu.FIRST + 1;
     66     private static final int MENU_SHOW_SYSTEM = MENU_DURATION + NUM_DURATIONS;
     67     private static final int MENU_USE_USS = MENU_SHOW_SYSTEM + 1;
     68     private static final int MENU_TYPE_BACKGROUND = MENU_USE_USS + 1;
     69     private static final int MENU_TYPE_FOREGROUND = MENU_TYPE_BACKGROUND + 1;
     70     private static final int MENU_TYPE_CACHED = MENU_TYPE_FOREGROUND + 1;
     71     private static final int MENU_HELP = MENU_TYPE_CACHED + 1;
     72 
     73     static final int MAX_ITEMS_TO_LIST = 60;
     74 
     75     final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
     76         @Override
     77         public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
     78             if (lhs.mWeight < rhs.mWeight) {
     79                 return 1;
     80             } else if (lhs.mWeight > rhs.mWeight) {
     81                 return -1;
     82             } else if (lhs.mDuration < rhs.mDuration) {
     83                 return 1;
     84             } else if (lhs.mDuration > rhs.mDuration) {
     85                 return -1;
     86             }
     87             return 0;
     88         }
     89     };
     90 
     91     private static ProcessStats sStatsXfer;
     92 
     93     IProcessStats mProcessStats;
     94     UserManager mUm;
     95     ProcessStats mStats;
     96     int mMemState;
     97 
     98     private long mDuration;
     99     private long mLastDuration;
    100     private boolean mShowSystem;
    101     private boolean mUseUss;
    102     private int mStatsType;
    103     private int mMemRegion;
    104 
    105     private MenuItem[] mDurationMenus = new MenuItem[NUM_DURATIONS];
    106     private MenuItem mShowSystemMenu;
    107     private MenuItem mUseUssMenu;
    108     private MenuItem mTypeBackgroundMenu;
    109     private MenuItem mTypeForegroundMenu;
    110     private MenuItem mTypeCachedMenu;
    111 
    112     private PreferenceGroup mAppListGroup;
    113     private Preference mMemStatusPref;
    114 
    115     long mMaxWeight;
    116     long mTotalTime;
    117 
    118     long[] mMemTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT];
    119     double[] mMemStateWeights = new double[ProcessStats.STATE_COUNT];
    120     double mMemCachedWeight;
    121     double mMemFreeWeight;
    122     double mMemZRamWeight;
    123     double mMemKernelWeight;
    124     double mMemNativeWeight;
    125     double mMemTotalWeight;
    126 
    127     // The actual duration value to use for each duration option.  Note these
    128     // are lower than the actual duration, since our durations are computed in
    129     // batches of 3 hours so we want to allow the time we use to be slightly
    130     // smaller than the actual time selected instead of bumping up to 3 hours
    131     // beyond it.
    132     private static final long DURATION_QUANTUM = ProcessStats.COMMIT_PERIOD;
    133     private static long[] sDurations = new long[] {
    134         3*60*60*1000 - DURATION_QUANTUM/2, 6*60*60*1000 - DURATION_QUANTUM/2,
    135         12*60*60*1000 - DURATION_QUANTUM/2, 24*60*60*1000 - DURATION_QUANTUM/2
    136     };
    137     private static int[] sDurationLabels = new int[] {
    138             R.string.menu_duration_3h, R.string.menu_duration_6h,
    139             R.string.menu_duration_12h, R.string.menu_duration_1d
    140     };
    141 
    142     @Override
    143     public void onCreate(Bundle icicle) {
    144         super.onCreate(icicle);
    145 
    146         if (icicle != null) {
    147             mStats = sStatsXfer;
    148         }
    149 
    150         addPreferencesFromResource(R.xml.process_stats_summary);
    151         mProcessStats = IProcessStats.Stub.asInterface(
    152                 ServiceManager.getService(ProcessStats.SERVICE_NAME));
    153         mUm = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
    154         mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
    155         mMemStatusPref = mAppListGroup.findPreference(KEY_MEM_STATUS);
    156         mDuration = icicle != null ? icicle.getLong("duration", sDurations[0]) : sDurations[0];
    157         mShowSystem = icicle != null ? icicle.getBoolean("show_system") : false;
    158         mUseUss = icicle != null ? icicle.getBoolean("use_uss") : false;
    159         mStatsType = icicle != null ? icicle.getInt("stats_type", MENU_TYPE_BACKGROUND)
    160                 : MENU_TYPE_BACKGROUND;
    161         mMemRegion = icicle != null ? icicle.getInt("mem_region", LinearColorBar.REGION_GREEN)
    162                 : LinearColorBar.REGION_GREEN;
    163         setHasOptionsMenu(true);
    164     }
    165 
    166     @Override
    167     public void onResume() {
    168         super.onResume();
    169         refreshStats();
    170     }
    171 
    172     @Override
    173     public void onPause() {
    174         super.onPause();
    175     }
    176 
    177     @Override
    178     public void onSaveInstanceState(Bundle outState) {
    179         super.onSaveInstanceState(outState);
    180         outState.putLong("duration", mDuration);
    181         outState.putBoolean("show_system", mShowSystem);
    182         outState.putBoolean("use_uss", mUseUss);
    183         outState.putInt("stats_type", mStatsType);
    184         outState.putInt("mem_region", mMemRegion);
    185     }
    186 
    187     @Override
    188     public void onDestroy() {
    189         super.onDestroy();
    190         if (getActivity().isChangingConfigurations()) {
    191             sStatsXfer = mStats;
    192         }
    193     }
    194 
    195     @Override
    196     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
    197         if (preference instanceof LinearColorPreference) {
    198             Bundle args = new Bundle();
    199             args.putLongArray(ProcessStatsMemDetail.EXTRA_MEM_TIMES, mMemTimes);
    200             args.putDoubleArray(ProcessStatsMemDetail.EXTRA_MEM_STATE_WEIGHTS, mMemStateWeights);
    201             args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_CACHED_WEIGHT, mMemCachedWeight);
    202             args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_FREE_WEIGHT, mMemFreeWeight);
    203             args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_ZRAM_WEIGHT, mMemZRamWeight);
    204             args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_KERNEL_WEIGHT, mMemKernelWeight);
    205             args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_NATIVE_WEIGHT, mMemNativeWeight);
    206             args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_TOTAL_WEIGHT, mMemTotalWeight);
    207             args.putBoolean(ProcessStatsMemDetail.EXTRA_USE_USS, mUseUss);
    208             args.putLong(ProcessStatsMemDetail.EXTRA_TOTAL_TIME, mTotalTime);
    209             ((SettingsActivity) getActivity()).startPreferencePanel(
    210                     ProcessStatsMemDetail.class.getName(), args, R.string.mem_details_title,
    211                     null, null, 0);
    212             return true;
    213         }
    214 
    215         if (!(preference instanceof ProcessStatsPreference)) {
    216             return false;
    217         }
    218 
    219         ProcessStatsPreference pgp = (ProcessStatsPreference) preference;
    220         Bundle args = new Bundle();
    221         args.putParcelable(ProcessStatsDetail.EXTRA_ENTRY, pgp.getEntry());
    222         args.putBoolean(ProcessStatsDetail.EXTRA_USE_USS, mUseUss);
    223         args.putLong(ProcessStatsDetail.EXTRA_MAX_WEIGHT, mMaxWeight);
    224         args.putLong(ProcessStatsDetail.EXTRA_TOTAL_TIME, mTotalTime);
    225         ((SettingsActivity) getActivity()).startPreferencePanel(
    226                 ProcessStatsDetail.class.getName(), args, R.string.details_title, null, null, 0);
    227 
    228         return super.onPreferenceTreeClick(preferenceScreen, preference);
    229     }
    230 
    231     @Override
    232     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    233         MenuItem refresh = menu.add(0, MENU_STATS_REFRESH, 0, R.string.menu_stats_refresh)
    234                 .setIcon(R.drawable.ic_menu_refresh_holo_dark)
    235                 .setAlphabeticShortcut('r');
    236         refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
    237                 MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    238         SubMenu subMenu = menu.addSubMenu(R.string.menu_proc_stats_duration);
    239         for (int i=0; i<NUM_DURATIONS; i++) {
    240             mDurationMenus[i] = subMenu.add(0, MENU_DURATION+i, 0, sDurationLabels[i])
    241                             .setCheckable(true);
    242         }
    243         mShowSystemMenu = menu.add(0, MENU_SHOW_SYSTEM, 0, R.string.menu_show_system)
    244                 .setAlphabeticShortcut('s')
    245                 .setCheckable(true);
    246         mUseUssMenu = menu.add(0, MENU_USE_USS, 0, R.string.menu_use_uss)
    247                 .setAlphabeticShortcut('u')
    248                 .setCheckable(true);
    249         subMenu = menu.addSubMenu(R.string.menu_proc_stats_type);
    250         mTypeBackgroundMenu = subMenu.add(0, MENU_TYPE_BACKGROUND, 0,
    251                 R.string.menu_proc_stats_type_background)
    252                 .setAlphabeticShortcut('b')
    253                 .setCheckable(true);
    254         mTypeForegroundMenu = subMenu.add(0, MENU_TYPE_FOREGROUND, 0,
    255                 R.string.menu_proc_stats_type_foreground)
    256                 .setAlphabeticShortcut('f')
    257                 .setCheckable(true);
    258         mTypeCachedMenu = subMenu.add(0, MENU_TYPE_CACHED, 0,
    259                 R.string.menu_proc_stats_type_cached)
    260                 .setCheckable(true);
    261 
    262         updateMenus();
    263 
    264         /*
    265         String helpUrl;
    266         if (!TextUtils.isEmpty(helpUrl = getResources().getString(R.string.help_url_battery))) {
    267             final MenuItem help = menu.add(0, MENU_HELP, 0, R.string.help_label);
    268             HelpUtils.prepareHelpMenuItem(getActivity(), help, helpUrl);
    269         }
    270         */
    271     }
    272 
    273     void updateMenus() {
    274         int closestIndex = 0;
    275         long closestDelta = Math.abs(sDurations[0]-mDuration);
    276         for (int i=1; i<NUM_DURATIONS; i++) {
    277             long delta = Math.abs(sDurations[i]-mDuration);
    278             if (delta < closestDelta) {
    279                 closestDelta = delta;
    280                 closestIndex = i;
    281             }
    282         }
    283         for (int i=0; i<NUM_DURATIONS; i++) {
    284             if (mDurationMenus[i] != null) {
    285                 mDurationMenus[i].setChecked(i == closestIndex);
    286             }
    287         }
    288         mDuration = sDurations[closestIndex];
    289         if (mShowSystemMenu != null) {
    290             mShowSystemMenu.setChecked(mShowSystem);
    291             mShowSystemMenu.setEnabled(mStatsType == MENU_TYPE_BACKGROUND);
    292         }
    293         if (mUseUssMenu != null) {
    294             mUseUssMenu.setChecked(mUseUss);
    295         }
    296         if (mTypeBackgroundMenu != null) {
    297             mTypeBackgroundMenu.setChecked(mStatsType == MENU_TYPE_BACKGROUND);
    298         }
    299         if (mTypeForegroundMenu != null) {
    300             mTypeForegroundMenu.setChecked(mStatsType == MENU_TYPE_FOREGROUND);
    301         }
    302         if (mTypeCachedMenu != null) {
    303             mTypeCachedMenu.setChecked(mStatsType == MENU_TYPE_CACHED);
    304         }
    305     }
    306 
    307     @Override
    308     public boolean onOptionsItemSelected(MenuItem item) {
    309         final int id = item.getItemId();
    310         switch (id) {
    311             case MENU_STATS_REFRESH:
    312                 mStats = null;
    313                 refreshStats();
    314                 return true;
    315             case MENU_SHOW_SYSTEM:
    316                 mShowSystem = !mShowSystem;
    317                 refreshStats();
    318                 return true;
    319             case MENU_USE_USS:
    320                 mUseUss = !mUseUss;
    321                 refreshStats();
    322                 return true;
    323             case MENU_TYPE_BACKGROUND:
    324             case MENU_TYPE_FOREGROUND:
    325             case MENU_TYPE_CACHED:
    326                 mStatsType = item.getItemId();
    327                 refreshStats();
    328                 return true;
    329             default:
    330                 if (id >= MENU_DURATION && id < (MENU_DURATION+NUM_DURATIONS)) {
    331                     mDuration = sDurations[id-MENU_DURATION];
    332                     refreshStats();
    333                 }
    334                 return false;
    335         }
    336     }
    337 
    338     @Override
    339     public void onRegionTapped(int region) {
    340         if (mMemRegion != region) {
    341             mMemRegion = region;
    342             refreshStats();
    343         }
    344     }
    345 
    346     private void addNotAvailableMessage() {
    347         Preference notAvailable = new Preference(getActivity());
    348         notAvailable.setTitle(R.string.power_usage_not_available);
    349         mAppListGroup.addPreference(notAvailable);
    350     }
    351 
    352     public static final int[] BACKGROUND_AND_SYSTEM_PROC_STATES = new int[] {
    353             ProcessStats.STATE_PERSISTENT, ProcessStats.STATE_IMPORTANT_FOREGROUND,
    354             ProcessStats.STATE_IMPORTANT_BACKGROUND, ProcessStats.STATE_BACKUP,
    355             ProcessStats.STATE_HEAVY_WEIGHT, ProcessStats.STATE_SERVICE,
    356             ProcessStats.STATE_SERVICE_RESTARTING, ProcessStats.STATE_RECEIVER
    357     };
    358 
    359     public static final int[] FOREGROUND_PROC_STATES = new int[] {
    360             ProcessStats.STATE_TOP
    361     };
    362 
    363     public static final int[] CACHED_PROC_STATES = new int[] {
    364             ProcessStats.STATE_CACHED_ACTIVITY, ProcessStats.STATE_CACHED_ACTIVITY_CLIENT,
    365             ProcessStats.STATE_CACHED_EMPTY
    366     };
    367 
    368     public static final int[] RED_MEM_STATES = new int[] {
    369             ProcessStats.ADJ_MEM_FACTOR_CRITICAL
    370     };
    371 
    372     public static final int[] YELLOW_MEM_STATES = new int[] {
    373             ProcessStats.ADJ_MEM_FACTOR_CRITICAL, ProcessStats.ADJ_MEM_FACTOR_LOW,
    374             ProcessStats.ADJ_MEM_FACTOR_MODERATE
    375     };
    376 
    377     private String makeDuration(long time) {
    378         StringBuilder sb = new StringBuilder(32);
    379         TimeUtils.formatDuration(time, sb);
    380         return sb.toString();
    381     }
    382 
    383     private void refreshStats() {
    384         updateMenus();
    385 
    386         if (mStats == null || mLastDuration != mDuration) {
    387             load();
    388         }
    389 
    390         int[] stats;
    391         int statsLabel;
    392         if (mStatsType == MENU_TYPE_FOREGROUND) {
    393             stats = FOREGROUND_PROC_STATES;
    394             statsLabel = R.string.process_stats_type_foreground;
    395         } else if (mStatsType == MENU_TYPE_CACHED) {
    396             stats = CACHED_PROC_STATES;
    397             statsLabel = R.string.process_stats_type_cached;
    398         } else {
    399             stats = mShowSystem ? BACKGROUND_AND_SYSTEM_PROC_STATES
    400                     : ProcessStats.BACKGROUND_PROC_STATES;
    401             statsLabel = R.string.process_stats_type_background;
    402         }
    403 
    404         mAppListGroup.removeAll();
    405         mAppListGroup.setOrderingAsAdded(false);
    406 
    407         final long elapsedTime = mStats.mTimePeriodEndRealtime-mStats.mTimePeriodStartRealtime;
    408 
    409         mMemStatusPref.setOrder(-2);
    410         mAppListGroup.addPreference(mMemStatusPref);
    411         String durationString = Utils.formatElapsedTime(getActivity(), elapsedTime, false);
    412         CharSequence memString;
    413         CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states);
    414         if (mMemState >= 0 && mMemState < memStatesStr.length) {
    415             memString = memStatesStr[mMemState];
    416         } else {
    417             memString = "?";
    418         }
    419         mMemStatusPref.setTitle(getActivity().getString(R.string.process_stats_total_duration,
    420                 getActivity().getString(statsLabel), durationString));
    421         mMemStatusPref.setSummary(getActivity().getString(R.string.process_stats_memory_status,
    422                         memString));
    423         /*
    424         mMemStatusPref.setTitle(DateFormat.format(DateFormat.getBestDateTimePattern(
    425                 getActivity().getResources().getConfiguration().locale,
    426                 "MMMM dd, yyyy h:mm a"), mStats.mTimePeriodStartClock));
    427         */
    428         /*
    429         BatteryHistoryPreference hist = new BatteryHistoryPreference(getActivity(), mStats);
    430         hist.setOrder(-1);
    431         mAppListGroup.addPreference(hist);
    432         */
    433 
    434         long now = SystemClock.uptimeMillis();
    435 
    436         final PackageManager pm = getActivity().getPackageManager();
    437 
    438         mTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations,
    439                 mStats.mMemFactor, mStats.mStartTime, now);
    440         if (DEBUG) Log.d(TAG, "Total time of stats: " + makeDuration(mTotalTime));
    441 
    442         for (int i=0; i<mMemTimes.length; i++) {
    443             mMemTimes[i] = 0;
    444         }
    445         for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) {
    446             for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) {
    447                 int state = imem+iscreen;
    448                 mMemTimes[imem] += mStats.mMemFactorDurations[state];
    449             }
    450         }
    451 
    452         long memTotalTime;
    453         int[] memStates;
    454 
    455         LinearColorPreference colors = new LinearColorPreference(getActivity());
    456         colors.setOrder(-1);
    457         switch (mMemRegion) {
    458             case LinearColorBar.REGION_RED:
    459                 memTotalTime = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL];
    460                 memStates = RED_MEM_STATES;
    461                 break;
    462             case LinearColorBar.REGION_YELLOW:
    463                 memTotalTime = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL]
    464                         + mMemTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]
    465                         + mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE];
    466                 memStates = YELLOW_MEM_STATES;
    467                 break;
    468             default:
    469                 memTotalTime = mTotalTime;
    470                 memStates = ProcessStats.ALL_MEM_ADJ;
    471                 break;
    472         }
    473         colors.setColoredRegions(LinearColorBar.REGION_RED);
    474 
    475         // Compute memory badness for chart color.
    476         int[] badColors = com.android.settings.Utils.BADNESS_COLORS;
    477         long timeGood = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL];
    478         timeGood += (mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]*2)/3;
    479         timeGood += mMemTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]/3;
    480         float memBadness = ((float)timeGood)/mTotalTime;
    481         int badnessColor = badColors[1 + Math.round(memBadness*(badColors.length-2))];
    482         colors.setColors(badnessColor, badnessColor, badnessColor);
    483 
    484         // We are now going to scale the mMemTimes to match the total elapsed time.
    485         // These are in uptime, so they will often be smaller than the elapsed time,
    486         // but if the user taps on the bar we want to show the times to them.  It is confusing
    487         // to see them be smaller than what we told them the measured duration is, so just
    488         // scaling them up with make things look reasonable with them none the wiser.
    489         for (int i=0; i<ProcessStats.ADJ_MEM_FACTOR_COUNT; i++) {
    490             mMemTimes[i] = (long)((mMemTimes[i]*(double)elapsedTime)/mTotalTime);
    491         }
    492 
    493         ProcessStats.TotalMemoryUseCollection totalMem = new ProcessStats.TotalMemoryUseCollection(
    494                 ProcessStats.ALL_SCREEN_ADJ, memStates);
    495         mStats.computeTotalMemoryUse(totalMem, now);
    496         double freeWeight = totalMem.sysMemFreeWeight + totalMem.sysMemCachedWeight;
    497         double usedWeight = totalMem.sysMemKernelWeight + totalMem.sysMemNativeWeight
    498                 + totalMem.sysMemZRamWeight;
    499         double backgroundWeight = 0, persBackgroundWeight = 0;
    500         mMemCachedWeight = totalMem.sysMemCachedWeight;
    501         mMemFreeWeight = totalMem.sysMemFreeWeight;
    502         mMemZRamWeight = totalMem.sysMemZRamWeight;
    503         mMemKernelWeight = totalMem.sysMemKernelWeight;
    504         mMemNativeWeight = totalMem.sysMemNativeWeight;
    505         for (int i=0; i<ProcessStats.STATE_COUNT; i++) {
    506             if (i == ProcessStats.STATE_SERVICE_RESTARTING) {
    507                 // These don't really run.
    508                 mMemStateWeights[i] = 0;
    509             } else {
    510                 mMemStateWeights[i] = totalMem.processStateWeight[i];
    511                 if (i >= ProcessStats.STATE_HOME) {
    512                     freeWeight += totalMem.processStateWeight[i];
    513                 } else {
    514                     usedWeight += totalMem.processStateWeight[i];
    515                 }
    516                 if (i >= ProcessStats.STATE_IMPORTANT_FOREGROUND) {
    517                     backgroundWeight += totalMem.processStateWeight[i];
    518                     persBackgroundWeight += totalMem.processStateWeight[i];
    519                 }
    520                 if (i == ProcessStats.STATE_PERSISTENT) {
    521                     persBackgroundWeight += totalMem.processStateWeight[i];
    522                 }
    523             }
    524         }
    525         if (DEBUG) {
    526             Log.i(TAG, "Used RAM: " + Formatter.formatShortFileSize(getActivity(),
    527                     (long)((usedWeight * 1024) / memTotalTime)));
    528             Log.i(TAG, "Free RAM: " + Formatter.formatShortFileSize(getActivity(),
    529                     (long)((freeWeight * 1024) / memTotalTime)));
    530             Log.i(TAG, "Total RAM: " + Formatter.formatShortFileSize(getActivity(),
    531                     (long)(((freeWeight+usedWeight) * 1024) / memTotalTime)));
    532             Log.i(TAG, "Background+Cached RAM: " + Formatter.formatShortFileSize(getActivity(),
    533                     (long)((backgroundWeight * 1024) / memTotalTime)));
    534         }
    535         mMemTotalWeight = freeWeight + usedWeight;
    536 
    537         // For computing the ratio to show, we want to count the baseline cached RAM we
    538         // need (at which point we start killing processes) as used RAM, so that if we
    539         // reach the point of thrashing due to no RAM for any background processes we
    540         // report that as RAM being full.  To do this, we need to first convert the weights
    541         // back to actual RAM...  and since the RAM values we compute here won't exactly
    542         // match the real physical RAM, scale those to the actual physical RAM.  No problem!
    543         double usedRam = (usedWeight*1024)/memTotalTime;
    544         double freeRam = (freeWeight*1024)/memTotalTime;
    545         double totalRam = usedRam + freeRam;
    546         MemInfoReader memReader = new MemInfoReader();
    547         memReader.readMemInfo();
    548         double realTotalRam = memReader.getTotalSize();
    549         double totalScale = realTotalRam / totalRam;
    550         double realUsedRam = usedRam * totalScale;
    551         double realFreeRam = freeRam * totalScale;
    552         if (DEBUG) {
    553             Log.i(TAG, "Scaled Used RAM: " + Formatter.formatShortFileSize(getActivity(),
    554                     (long)realUsedRam));
    555             Log.i(TAG, "Scaled Free RAM: " + Formatter.formatShortFileSize(getActivity(),
    556                     (long)realFreeRam));
    557         }
    558         ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
    559         ((ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(
    560                 memInfo);
    561         if (memInfo.hiddenAppThreshold >= realFreeRam) {
    562             realUsedRam = realFreeRam;
    563             realFreeRam = 0;
    564         } else {
    565             realUsedRam += memInfo.hiddenAppThreshold;
    566             realFreeRam -= memInfo.hiddenAppThreshold;
    567         }
    568         if (DEBUG) {
    569             Log.i(TAG, "Adj Scaled Used RAM: " + Formatter.formatShortFileSize(getActivity(),
    570                     (long)realUsedRam));
    571             Log.i(TAG, "Adj Scaled Free RAM: " + Formatter.formatShortFileSize(getActivity(),
    572                     (long)realFreeRam));
    573         }
    574 
    575         float usedRatio = (float)(realUsedRam/(realFreeRam+realUsedRam));
    576         colors.setRatios(usedRatio, 0, 1-usedRatio);
    577 
    578         if (false) {
    579             colors.setOnRegionTappedListener(this);
    580             switch (mMemRegion) {
    581                 case LinearColorBar.REGION_RED:
    582                     colors.setColoredRegions(LinearColorBar.REGION_RED);
    583                     memTotalTime = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL];
    584                     memStates = RED_MEM_STATES;
    585                     break;
    586                 case LinearColorBar.REGION_YELLOW:
    587                     colors.setColoredRegions(LinearColorBar.REGION_RED
    588                             | LinearColorBar.REGION_YELLOW);
    589                     memTotalTime = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL]
    590                             + mMemTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]
    591                             + mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE];
    592                     memStates = YELLOW_MEM_STATES;
    593                     break;
    594                 default:
    595                     colors.setColoredRegions(LinearColorBar.REGION_ALL);
    596                     memTotalTime = mTotalTime;
    597                     memStates = ProcessStats.ALL_MEM_ADJ;
    598                     break;
    599             }
    600             colors.setRatios(mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL] / (float)mTotalTime,
    601                     (mMemTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]
    602                             + mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]) / (float)mTotalTime,
    603                     mMemTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL] / (float)mTotalTime);
    604         }
    605 
    606         mAppListGroup.addPreference(colors);
    607 
    608         ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
    609                 ProcessStats.ALL_SCREEN_ADJ, memStates, stats);
    610 
    611         ArrayList<ProcStatsEntry> entries = new ArrayList<ProcStatsEntry>();
    612 
    613         /*
    614         ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked(
    615                 ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ,
    616                 ProcessStats.BACKGROUND_PROC_STATES, now, null);
    617         for (int i=0, N=(rawProcs != null ? rawProcs.size() : 0); i<N; i++) {
    618             procs.add(new ProcStatsEntry(rawProcs.get(i), totals));
    619         }
    620         */
    621 
    622         if (DEBUG) Log.d(TAG, "-------------------- PULLING PROCESSES");
    623 
    624         final ProcessMap<ProcStatsEntry> entriesMap = new ProcessMap<ProcStatsEntry>();
    625         for (int ipkg=0, N=mStats.mPackages.getMap().size(); ipkg<N; ipkg++) {
    626             final SparseArray<SparseArray<ProcessStats.PackageState>> pkgUids
    627                     = mStats.mPackages.getMap().valueAt(ipkg);
    628             for (int iu=0; iu<pkgUids.size(); iu++) {
    629                 final SparseArray<ProcessStats.PackageState> vpkgs = pkgUids.valueAt(iu);
    630                 for (int iv=0; iv<vpkgs.size(); iv++) {
    631                     final ProcessStats.PackageState st = vpkgs.valueAt(iv);
    632                     for (int iproc=0; iproc<st.mProcesses.size(); iproc++) {
    633                         final ProcessStats.ProcessState pkgProc = st.mProcesses.valueAt(iproc);
    634                         final ProcessStats.ProcessState proc = mStats.mProcesses.get(pkgProc.mName,
    635                                 pkgProc.mUid);
    636                         if (proc == null) {
    637                             Log.w(TAG, "No process found for pkg " + st.mPackageName
    638                                     + "/" + st.mUid + " proc name " + pkgProc.mName);
    639                             continue;
    640                         }
    641                         ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid);
    642                         if (ent == null) {
    643                             ent = new ProcStatsEntry(proc, st.mPackageName, totals, mUseUss,
    644                                     mStatsType == MENU_TYPE_BACKGROUND);
    645                             if (ent.mDuration > 0) {
    646                                 if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
    647                                         + proc.mUid + ": time=" + makeDuration(ent.mDuration) + " ("
    648                                         + ((((double)ent.mDuration) / memTotalTime) * 100) + "%)"
    649                                         + " pss=" + ent.mAvgPss);
    650                                 entriesMap.put(proc.mName, proc.mUid, ent);
    651                                 entries.add(ent);
    652                             }
    653                         }  else {
    654                             ent.addPackage(st.mPackageName);
    655                         }
    656                     }
    657                 }
    658             }
    659         }
    660 
    661         if (DEBUG) Log.d(TAG, "-------------------- MAPPING SERVICES");
    662 
    663         // Add in service info.
    664         if (mStatsType == MENU_TYPE_BACKGROUND) {
    665             for (int ip=0, N=mStats.mPackages.getMap().size(); ip<N; ip++) {
    666                 SparseArray<SparseArray<ProcessStats.PackageState>> uids
    667                         = mStats.mPackages.getMap().valueAt(ip);
    668                 for (int iu=0; iu<uids.size(); iu++) {
    669                     SparseArray<ProcessStats.PackageState> vpkgs = uids.valueAt(iu);
    670                     for (int iv=0; iv<vpkgs.size(); iv++) {
    671                         ProcessStats.PackageState ps = vpkgs.valueAt(iv);
    672                         for (int is=0, NS=ps.mServices.size(); is<NS; is++) {
    673                             ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
    674                             if (ss.mProcessName != null) {
    675                                 ProcStatsEntry ent = entriesMap.get(ss.mProcessName, uids.keyAt(iu));
    676                                 if (ent != null) {
    677                                     if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName
    678                                             + "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc "
    679                                             + ss.mProcessName);
    680                                     ent.addService(ss);
    681                                 } else {
    682                                     Log.w(TAG, "No process " + ss.mProcessName + "/" + uids.keyAt(iu)
    683                                             + " for service " + ss.mName);
    684                                 }
    685                             }
    686                         }
    687                     }
    688                 }
    689             }
    690         }
    691 
    692         /*
    693         SparseArray<ArrayMap<String, ProcStatsEntry>> processes
    694                 = new SparseArray<ArrayMap<String, ProcStatsEntry>>();
    695         for (int ip=0, N=mStats.mProcesses.getMap().size(); ip<N; ip++) {
    696             SparseArray<ProcessStats.ProcessState> uids = mStats.mProcesses.getMap().valueAt(ip);
    697             for (int iu=0; iu<uids.size(); iu++) {
    698                 ProcessStats.ProcessState st = uids.valueAt(iu);
    699                 ProcStatsEntry ent = new ProcStatsEntry(st, totals, mUseUss,
    700                         mStatsType == MENU_TYPE_BACKGROUND);
    701                 if (ent.mDuration > 0) {
    702                     if (DEBUG) Log.d(TAG, "Adding proc " + st.mName + "/" + st.mUid + ": time="
    703                             + makeDuration(ent.mDuration) + " ("
    704                             + ((((double)ent.mDuration) / memTotalTime) * 100) + "%)");
    705                     procs.add(ent);
    706                     ArrayMap<String, ProcStatsEntry> uidProcs = processes.get(ent.mUid);
    707                     if (uidProcs == null) {
    708                         uidProcs = new ArrayMap<String, ProcStatsEntry>();
    709                         processes.put(ent.mUid, uidProcs);
    710                     }
    711                     uidProcs.put(ent.mName, ent);
    712                 }
    713             }
    714         }
    715         */
    716 
    717         Collections.sort(entries, sEntryCompare);
    718 
    719         long maxWeight = 1;
    720         for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) {
    721             ProcStatsEntry proc = entries.get(i);
    722             if (maxWeight < proc.mWeight) {
    723                 maxWeight = proc.mWeight;
    724             }
    725         }
    726         if (mStatsType == MENU_TYPE_BACKGROUND) {
    727             mMaxWeight = (long)(mShowSystem ? persBackgroundWeight : backgroundWeight);
    728             if (mMaxWeight < maxWeight) {
    729                 mMaxWeight = maxWeight;
    730             }
    731             if (DEBUG) {
    732                 Log.i(TAG, "Bar max RAM: " + Formatter.formatShortFileSize(getActivity(),
    733                         (mMaxWeight * 1024) / memTotalTime));
    734             }
    735         } else {
    736             mMaxWeight = maxWeight;
    737         }
    738 
    739         if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI");
    740 
    741         // Find where we should stop.  Because we have two properties we are looking at,
    742         // we need to go from the back looking for the first place either holds.
    743         int end = entries != null ? entries.size()-1 : -1;
    744         while (end >= 0) {
    745             ProcStatsEntry proc = entries.get(end);
    746             final double percentOfWeight = (((double)proc.mWeight) / mMaxWeight) * 100;
    747             final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100;
    748             if (percentOfWeight >= 1 || percentOfTime >= 25) {
    749                 break;
    750             }
    751             end--;
    752         }
    753         for (int i=0; i<=end; i++) {
    754             ProcStatsEntry proc = entries.get(i);
    755             final double percentOfWeight = (((double)proc.mWeight) / mMaxWeight) * 100;
    756             final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100;
    757             ProcessStatsPreference pref = new ProcessStatsPreference(getActivity());
    758             pref.init(null, proc);
    759             proc.evaluateTargetPackage(pm, mStats, totals, sEntryCompare, mUseUss,
    760                     mStatsType == MENU_TYPE_BACKGROUND);
    761             proc.retrieveUiData(pm);
    762             pref.setTitle(proc.mUiLabel);
    763             if (proc.mUiTargetApp != null) {
    764                 pref.setIcon(proc.mUiTargetApp.loadIcon(pm));
    765             }
    766             pref.setOrder(i);
    767             pref.setPercent(percentOfWeight, percentOfTime);
    768             mAppListGroup.addPreference(pref);
    769             if (mStatsType == MENU_TYPE_BACKGROUND) {
    770                 if (DEBUG) {
    771                     Log.i(TAG, "App " + proc.mUiLabel + ": weightedRam="
    772                             + Formatter.formatShortFileSize(getActivity(),
    773                                     (proc.mWeight * 1024) / memTotalTime)
    774                             + ", avgRam=" + Formatter.formatShortFileSize(getActivity(),
    775                                     (proc.mAvgPss*1024)));
    776                 }
    777 
    778             }
    779             if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) {
    780                 if (DEBUG) Log.d(TAG, "Done with UI, hit item limit!");
    781                 break;
    782             }
    783         }
    784     }
    785 
    786     private void load() {
    787         try {
    788             mLastDuration = mDuration;
    789             mMemState = mProcessStats.getCurrentMemoryState();
    790             ParcelFileDescriptor pfd = mProcessStats.getStatsOverTime(mDuration);
    791             mStats = new ProcessStats(false);
    792             InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
    793             mStats.read(is);
    794             try {
    795                 is.close();
    796             } catch (IOException e) {
    797             }
    798             if (mStats.mReadError != null) {
    799                 Log.w(TAG, "Failure reading process stats: " + mStats.mReadError);
    800             }
    801         } catch (RemoteException e) {
    802             Log.e(TAG, "RemoteException:", e);
    803         }
    804     }
    805 }
    806