ProcessStatsUi.java revision b1e33884190732a58bfbfe659898e02d41fe39f4
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 17package com.android.settings.applications; 18 19import android.content.Context; 20import android.content.pm.PackageManager; 21import android.os.Bundle; 22import android.os.ParcelFileDescriptor; 23import android.os.RemoteException; 24import android.os.ServiceManager; 25import android.os.SystemClock; 26import android.os.UserManager; 27import android.preference.Preference; 28import android.preference.PreferenceActivity; 29import android.preference.PreferenceFragment; 30import android.preference.PreferenceGroup; 31import android.preference.PreferenceScreen; 32import android.util.Log; 33import android.util.SparseArray; 34import android.util.TimeUtils; 35import android.view.Menu; 36import android.view.MenuInflater; 37import android.view.MenuItem; 38import android.view.SubMenu; 39import com.android.internal.app.IProcessStats; 40import com.android.internal.app.ProcessMap; 41import com.android.internal.app.ProcessStats; 42import com.android.settings.R; 43import com.android.settings.fuelgauge.Utils; 44 45import java.io.IOException; 46import java.io.InputStream; 47import java.util.ArrayList; 48import java.util.Collections; 49import java.util.Comparator; 50 51public class ProcessStatsUi extends PreferenceFragment 52 implements LinearColorBar.OnRegionTappedListener { 53 static final String TAG = "ProcessStatsUi"; 54 static final boolean DEBUG = false; 55 56 private static final String KEY_APP_LIST = "app_list"; 57 private static final String KEY_MEM_STATUS = "mem_status"; 58 59 private static final int NUM_DURATIONS = 4; 60 61 private static final int MENU_STATS_REFRESH = Menu.FIRST; 62 private static final int MENU_DURATION = Menu.FIRST + 1; 63 private static final int MENU_SHOW_SYSTEM = MENU_DURATION + NUM_DURATIONS; 64 private static final int MENU_USE_USS = MENU_SHOW_SYSTEM + 1; 65 private static final int MENU_TYPE_BACKGROUND = MENU_USE_USS + 1; 66 private static final int MENU_TYPE_FOREGROUND = MENU_TYPE_BACKGROUND + 1; 67 private static final int MENU_TYPE_CACHED = MENU_TYPE_FOREGROUND + 1; 68 private static final int MENU_HELP = MENU_TYPE_CACHED + 1; 69 70 static final int MAX_ITEMS_TO_LIST = 60; 71 72 final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() { 73 @Override 74 public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) { 75 if (lhs.mWeight < rhs.mWeight) { 76 return 1; 77 } else if (lhs.mWeight > rhs.mWeight) { 78 return -1; 79 } else if (lhs.mDuration < rhs.mDuration) { 80 return 1; 81 } else if (lhs.mDuration > rhs.mDuration) { 82 return -1; 83 } 84 return 0; 85 } 86 }; 87 88 private static ProcessStats sStatsXfer; 89 90 IProcessStats mProcessStats; 91 UserManager mUm; 92 ProcessStats mStats; 93 int mMemState; 94 95 private long mDuration; 96 private long mLastDuration; 97 private boolean mShowSystem; 98 private boolean mUseUss; 99 private int mStatsType; 100 private int mMemRegion; 101 102 private MenuItem[] mDurationMenus = new MenuItem[NUM_DURATIONS]; 103 private MenuItem mShowSystemMenu; 104 private MenuItem mUseUssMenu; 105 private MenuItem mTypeBackgroundMenu; 106 private MenuItem mTypeForegroundMenu; 107 private MenuItem mTypeCachedMenu; 108 109 private PreferenceGroup mAppListGroup; 110 private Preference mMemStatusPref; 111 112 long mMaxWeight; 113 long mTotalTime; 114 115 // The actual duration value to use for each duration option. Note these 116 // are lower than the actual duration, since our durations are computed in 117 // batches of 3 hours so we want to allow the time we use to be slightly 118 // smaller than the actual time selected instead of bumping up to 3 hours 119 // beyond it. 120 private static final long DURATION_QUANTUM = ProcessStats.COMMIT_PERIOD; 121 private static long[] sDurations = new long[] { 122 3*60*60*1000 - DURATION_QUANTUM/2, 6*60*60*1000 - DURATION_QUANTUM/2, 123 12*60*60*1000 - DURATION_QUANTUM/2, 24*60*60*1000 - DURATION_QUANTUM/2 124 }; 125 private static int[] sDurationLabels = new int[] { 126 R.string.menu_duration_3h, R.string.menu_duration_6h, 127 R.string.menu_duration_12h, R.string.menu_duration_1d 128 }; 129 130 @Override 131 public void onCreate(Bundle icicle) { 132 super.onCreate(icicle); 133 134 if (icicle != null) { 135 mStats = sStatsXfer; 136 } 137 138 addPreferencesFromResource(R.xml.process_stats_summary); 139 mProcessStats = IProcessStats.Stub.asInterface( 140 ServiceManager.getService(ProcessStats.SERVICE_NAME)); 141 mUm = (UserManager)getActivity().getSystemService(Context.USER_SERVICE); 142 mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST); 143 mMemStatusPref = mAppListGroup.findPreference(KEY_MEM_STATUS); 144 mDuration = icicle != null ? icicle.getLong("duration", sDurations[0]) : sDurations[0]; 145 mShowSystem = icicle != null ? icicle.getBoolean("show_system") : false; 146 mUseUss = icicle != null ? icicle.getBoolean("use_uss") : false; 147 mStatsType = icicle != null ? icicle.getInt("stats_type", MENU_TYPE_BACKGROUND) 148 : MENU_TYPE_BACKGROUND; 149 mMemRegion = icicle != null ? icicle.getInt("mem_region", LinearColorBar.REGION_GREEN) 150 : LinearColorBar.REGION_GREEN; 151 setHasOptionsMenu(true); 152 } 153 154 @Override 155 public void onResume() { 156 super.onResume(); 157 refreshStats(); 158 } 159 160 @Override 161 public void onPause() { 162 super.onPause(); 163 } 164 165 @Override 166 public void onSaveInstanceState(Bundle outState) { 167 super.onSaveInstanceState(outState); 168 outState.putLong("duration", mDuration); 169 outState.putBoolean("show_system", mShowSystem); 170 outState.putBoolean("use_uss", mUseUss); 171 outState.putInt("stats_type", mStatsType); 172 outState.putInt("mem_region", mMemRegion); 173 } 174 175 @Override 176 public void onDestroy() { 177 super.onDestroy(); 178 if (getActivity().isChangingConfigurations()) { 179 sStatsXfer = mStats; 180 } 181 } 182 183 @Override 184 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 185 if (!(preference instanceof ProcessStatsPreference)) { 186 return false; 187 } 188 189 ProcessStatsPreference pgp = (ProcessStatsPreference) preference; 190 Bundle args = new Bundle(); 191 args.putParcelable(ProcessStatsDetail.EXTRA_ENTRY, pgp.getEntry()); 192 args.putBoolean(ProcessStatsDetail.EXTRA_USE_USS, mUseUss); 193 args.putLong(ProcessStatsDetail.EXTRA_MAX_WEIGHT, mMaxWeight); 194 args.putLong(ProcessStatsDetail.EXTRA_TOTAL_TIME, mTotalTime); 195 ((PreferenceActivity) getActivity()).startPreferencePanel( 196 ProcessStatsDetail.class.getName(), args, R.string.details_title, null, null, 0); 197 198 return super.onPreferenceTreeClick(preferenceScreen, preference); 199 } 200 201 @Override 202 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 203 MenuItem refresh = menu.add(0, MENU_STATS_REFRESH, 0, R.string.menu_stats_refresh) 204 .setIcon(R.drawable.ic_menu_refresh_holo_dark) 205 .setAlphabeticShortcut('r'); 206 refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | 207 MenuItem.SHOW_AS_ACTION_WITH_TEXT); 208 SubMenu subMenu = menu.addSubMenu(R.string.menu_proc_stats_duration); 209 for (int i=0; i<NUM_DURATIONS; i++) { 210 mDurationMenus[i] = subMenu.add(0, MENU_DURATION+i, 0, sDurationLabels[i]) 211 .setCheckable(true); 212 } 213 mShowSystemMenu = menu.add(0, MENU_SHOW_SYSTEM, 0, R.string.menu_show_system) 214 .setAlphabeticShortcut('s') 215 .setCheckable(true); 216 mUseUssMenu = menu.add(0, MENU_USE_USS, 0, R.string.menu_use_uss) 217 .setAlphabeticShortcut('u') 218 .setCheckable(true); 219 subMenu = menu.addSubMenu(R.string.menu_proc_stats_type); 220 mTypeBackgroundMenu = subMenu.add(0, MENU_TYPE_BACKGROUND, 0, 221 R.string.menu_proc_stats_type_background) 222 .setAlphabeticShortcut('b') 223 .setCheckable(true); 224 mTypeForegroundMenu = subMenu.add(0, MENU_TYPE_FOREGROUND, 0, 225 R.string.menu_proc_stats_type_foreground) 226 .setAlphabeticShortcut('f') 227 .setCheckable(true); 228 mTypeCachedMenu = subMenu.add(0, MENU_TYPE_CACHED, 0, 229 R.string.menu_proc_stats_type_cached) 230 .setCheckable(true); 231 232 updateMenus(); 233 234 /* 235 String helpUrl; 236 if (!TextUtils.isEmpty(helpUrl = getResources().getString(R.string.help_url_battery))) { 237 final MenuItem help = menu.add(0, MENU_HELP, 0, R.string.help_label); 238 HelpUtils.prepareHelpMenuItem(getActivity(), help, helpUrl); 239 } 240 */ 241 } 242 243 void updateMenus() { 244 int closestIndex = 0; 245 long closestDelta = Math.abs(sDurations[0]-mDuration); 246 for (int i=1; i<NUM_DURATIONS; i++) { 247 long delta = Math.abs(sDurations[i]-mDuration); 248 if (delta < closestDelta) { 249 closestDelta = delta; 250 closestIndex = i; 251 } 252 } 253 for (int i=0; i<NUM_DURATIONS; i++) { 254 if (mDurationMenus[i] != null) { 255 mDurationMenus[i].setChecked(i == closestIndex); 256 } 257 } 258 mDuration = sDurations[closestIndex]; 259 if (mShowSystemMenu != null) { 260 mShowSystemMenu.setChecked(mShowSystem); 261 mShowSystemMenu.setEnabled(mStatsType == MENU_TYPE_BACKGROUND); 262 } 263 if (mUseUssMenu != null) { 264 mUseUssMenu.setChecked(mUseUss); 265 } 266 if (mTypeBackgroundMenu != null) { 267 mTypeBackgroundMenu.setChecked(mStatsType == MENU_TYPE_BACKGROUND); 268 } 269 if (mTypeForegroundMenu != null) { 270 mTypeForegroundMenu.setChecked(mStatsType == MENU_TYPE_FOREGROUND); 271 } 272 if (mTypeCachedMenu != null) { 273 mTypeCachedMenu.setChecked(mStatsType == MENU_TYPE_CACHED); 274 } 275 } 276 277 @Override 278 public boolean onOptionsItemSelected(MenuItem item) { 279 final int id = item.getItemId(); 280 switch (id) { 281 case MENU_STATS_REFRESH: 282 mStats = null; 283 refreshStats(); 284 return true; 285 case MENU_SHOW_SYSTEM: 286 mShowSystem = !mShowSystem; 287 refreshStats(); 288 return true; 289 case MENU_USE_USS: 290 mUseUss = !mUseUss; 291 refreshStats(); 292 return true; 293 case MENU_TYPE_BACKGROUND: 294 case MENU_TYPE_FOREGROUND: 295 case MENU_TYPE_CACHED: 296 mStatsType = item.getItemId(); 297 refreshStats(); 298 return true; 299 default: 300 if (id >= MENU_DURATION && id < (MENU_DURATION+NUM_DURATIONS)) { 301 mDuration = sDurations[id-MENU_DURATION]; 302 refreshStats(); 303 } 304 return false; 305 } 306 } 307 308 @Override 309 public void onRegionTapped(int region) { 310 if (mMemRegion != region) { 311 mMemRegion = region; 312 refreshStats(); 313 } 314 } 315 316 private void addNotAvailableMessage() { 317 Preference notAvailable = new Preference(getActivity()); 318 notAvailable.setTitle(R.string.power_usage_not_available); 319 mAppListGroup.addPreference(notAvailable); 320 } 321 322 public static final int[] BACKGROUND_AND_SYSTEM_PROC_STATES = new int[] { 323 ProcessStats.STATE_PERSISTENT, ProcessStats.STATE_IMPORTANT_FOREGROUND, 324 ProcessStats.STATE_IMPORTANT_BACKGROUND, ProcessStats.STATE_BACKUP, 325 ProcessStats.STATE_HEAVY_WEIGHT, ProcessStats.STATE_SERVICE, 326 ProcessStats.STATE_SERVICE_RESTARTING, ProcessStats.STATE_RECEIVER 327 }; 328 329 public static final int[] FOREGROUND_PROC_STATES = new int[] { 330 ProcessStats.STATE_TOP 331 }; 332 333 public static final int[] CACHED_PROC_STATES = new int[] { 334 ProcessStats.STATE_CACHED_ACTIVITY, ProcessStats.STATE_CACHED_ACTIVITY_CLIENT, 335 ProcessStats.STATE_CACHED_EMPTY 336 }; 337 338 public static final int[] RED_MEM_STATES = new int[] { 339 ProcessStats.ADJ_MEM_FACTOR_CRITICAL 340 }; 341 342 public static final int[] YELLOW_MEM_STATES = new int[] { 343 ProcessStats.ADJ_MEM_FACTOR_CRITICAL, ProcessStats.ADJ_MEM_FACTOR_LOW, 344 ProcessStats.ADJ_MEM_FACTOR_MODERATE 345 }; 346 347 private String makeDuration(long time) { 348 StringBuilder sb = new StringBuilder(32); 349 TimeUtils.formatDuration(time, sb); 350 return sb.toString(); 351 } 352 353 private void refreshStats() { 354 updateMenus(); 355 356 if (mStats == null || mLastDuration != mDuration) { 357 load(); 358 } 359 360 int[] stats; 361 int statsLabel; 362 if (mStatsType == MENU_TYPE_FOREGROUND) { 363 stats = FOREGROUND_PROC_STATES; 364 statsLabel = R.string.process_stats_type_foreground; 365 } else if (mStatsType == MENU_TYPE_CACHED) { 366 stats = CACHED_PROC_STATES; 367 statsLabel = R.string.process_stats_type_cached; 368 } else { 369 stats = mShowSystem ? BACKGROUND_AND_SYSTEM_PROC_STATES 370 : ProcessStats.BACKGROUND_PROC_STATES; 371 statsLabel = R.string.process_stats_type_background; 372 } 373 374 mAppListGroup.removeAll(); 375 mAppListGroup.setOrderingAsAdded(false); 376 377 mMemStatusPref.setOrder(-2); 378 mAppListGroup.addPreference(mMemStatusPref); 379 String durationString = Utils.formatElapsedTime(getActivity(), 380 mStats.mTimePeriodEndRealtime-mStats.mTimePeriodStartRealtime, false); 381 CharSequence memString; 382 CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states); 383 if (mMemState >= 0 && mMemState < memStatesStr.length) { 384 memString = memStatesStr[mMemState]; 385 } else { 386 memString = "?"; 387 } 388 mMemStatusPref.setTitle(getActivity().getString(R.string.process_stats_total_duration, 389 getActivity().getString(statsLabel), durationString)); 390 mMemStatusPref.setSummary(getActivity().getString(R.string.process_stats_memory_status, 391 memString)); 392 /* 393 mMemStatusPref.setTitle(DateFormat.format(DateFormat.getBestDateTimePattern( 394 getActivity().getResources().getConfiguration().locale, 395 "MMMM dd, yyyy h:mm a"), mStats.mTimePeriodStartClock)); 396 */ 397 /* 398 BatteryHistoryPreference hist = new BatteryHistoryPreference(getActivity(), mStats); 399 hist.setOrder(-1); 400 mAppListGroup.addPreference(hist); 401 */ 402 403 long now = SystemClock.uptimeMillis(); 404 405 final PackageManager pm = getActivity().getPackageManager(); 406 407 mTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations, 408 mStats.mMemFactor, mStats.mStartTime, now); 409 if (DEBUG) Log.d(TAG, "Total time of stats: " + makeDuration(mTotalTime)); 410 411 long[] memTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT]; 412 for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) { 413 for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) { 414 int state = imem+iscreen; 415 memTimes[imem] += mStats.mMemFactorDurations[state]; 416 } 417 } 418 419 long memTotalTime; 420 int[] memStates; 421 422 LinearColorPreference colors = new LinearColorPreference(getActivity()); 423 colors.setOrder(-1); 424 colors.setOnRegionTappedListener(this); 425 switch (mMemRegion) { 426 case LinearColorBar.REGION_RED: 427 colors.setColoredRegions(LinearColorBar.REGION_RED); 428 memTotalTime = memTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL]; 429 memStates = RED_MEM_STATES; 430 break; 431 case LinearColorBar.REGION_YELLOW: 432 colors.setColoredRegions(LinearColorBar.REGION_RED 433 | LinearColorBar.REGION_YELLOW); 434 memTotalTime = memTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL] 435 + memTimes[ProcessStats.ADJ_MEM_FACTOR_LOW] 436 + memTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]; 437 memStates = YELLOW_MEM_STATES; 438 break; 439 default: 440 colors.setColoredRegions(LinearColorBar.REGION_ALL); 441 memTotalTime = mTotalTime; 442 memStates = ProcessStats.ALL_MEM_ADJ; 443 break; 444 } 445 colors.setRatios(memTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL] / (float)mTotalTime, 446 (memTimes[ProcessStats.ADJ_MEM_FACTOR_LOW] 447 + memTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]) / (float)mTotalTime, 448 memTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL] / (float)mTotalTime); 449 mAppListGroup.addPreference(colors); 450 451 ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection( 452 ProcessStats.ALL_SCREEN_ADJ, memStates, stats); 453 454 ArrayList<ProcStatsEntry> entries = new ArrayList<ProcStatsEntry>(); 455 456 /* 457 ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked( 458 ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ, 459 ProcessStats.BACKGROUND_PROC_STATES, now, null); 460 for (int i=0, N=(rawProcs != null ? rawProcs.size() : 0); i<N; i++) { 461 procs.add(new ProcStatsEntry(rawProcs.get(i), totals)); 462 } 463 */ 464 465 if (DEBUG) Log.d(TAG, "-------------------- PULLING PROCESSES"); 466 467 final ProcessMap<ProcStatsEntry> entriesMap = new ProcessMap<ProcStatsEntry>(); 468 for (int ipkg=0, N=mStats.mPackages.getMap().size(); ipkg<N; ipkg++) { 469 final SparseArray<ProcessStats.PackageState> pkgUids 470 = mStats.mPackages.getMap().valueAt(ipkg); 471 for (int iu=0; iu<pkgUids.size(); iu++) { 472 final ProcessStats.PackageState st = pkgUids.valueAt(iu); 473 for (int iproc=0; iproc<st.mProcesses.size(); iproc++) { 474 final ProcessStats.ProcessState pkgProc = st.mProcesses.valueAt(iproc); 475 final ProcessStats.ProcessState proc = mStats.mProcesses.get(pkgProc.mName, 476 pkgProc.mUid); 477 if (proc == null) { 478 Log.w(TAG, "No process found for pkg " + st.mPackageName 479 + "/" + st.mUid + " proc name " + pkgProc.mName); 480 continue; 481 } 482 ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid); 483 if (ent == null) { 484 ent = new ProcStatsEntry(proc, st.mPackageName, totals, mUseUss, 485 mStatsType == MENU_TYPE_BACKGROUND); 486 if (ent.mDuration > 0) { 487 if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/" 488 + proc.mUid + ": time=" + makeDuration(ent.mDuration) + " (" 489 + ((((double)ent.mDuration) / memTotalTime) * 100) + "%)" 490 + " pss=" + ent.mAvgPss); 491 entriesMap.put(proc.mName, proc.mUid, ent); 492 entries.add(ent); 493 } 494 } else { 495 ent.addPackage(st.mPackageName); 496 } 497 } 498 } 499 } 500 501 if (DEBUG) Log.d(TAG, "-------------------- MAPPING SERVICES"); 502 503 // Add in service info. 504 if (mStatsType == MENU_TYPE_BACKGROUND) { 505 for (int ip=0, N=mStats.mPackages.getMap().size(); ip<N; ip++) { 506 SparseArray<ProcessStats.PackageState> uids = mStats.mPackages.getMap().valueAt(ip); 507 for (int iu=0; iu<uids.size(); iu++) { 508 ProcessStats.PackageState ps = uids.valueAt(iu); 509 for (int is=0, NS=ps.mServices.size(); is<NS; is++) { 510 ProcessStats.ServiceState ss = ps.mServices.valueAt(is); 511 if (ss.mProcessName != null) { 512 ProcStatsEntry ent = entriesMap.get(ss.mProcessName, uids.keyAt(iu)); 513 if (ent != null) { 514 if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName 515 + "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc " 516 + ss.mProcessName); 517 ent.addService(ss); 518 } else { 519 Log.w(TAG, "No process " + ss.mProcessName + "/" + uids.keyAt(iu) 520 + " for service " + ss.mName); 521 } 522 } 523 } 524 } 525 } 526 } 527 528 /* 529 SparseArray<ArrayMap<String, ProcStatsEntry>> processes 530 = new SparseArray<ArrayMap<String, ProcStatsEntry>>(); 531 for (int ip=0, N=mStats.mProcesses.getMap().size(); ip<N; ip++) { 532 SparseArray<ProcessStats.ProcessState> uids = mStats.mProcesses.getMap().valueAt(ip); 533 for (int iu=0; iu<uids.size(); iu++) { 534 ProcessStats.ProcessState st = uids.valueAt(iu); 535 ProcStatsEntry ent = new ProcStatsEntry(st, totals, mUseUss, 536 mStatsType == MENU_TYPE_BACKGROUND); 537 if (ent.mDuration > 0) { 538 if (DEBUG) Log.d(TAG, "Adding proc " + st.mName + "/" + st.mUid + ": time=" 539 + makeDuration(ent.mDuration) + " (" 540 + ((((double)ent.mDuration) / memTotalTime) * 100) + "%)"); 541 procs.add(ent); 542 ArrayMap<String, ProcStatsEntry> uidProcs = processes.get(ent.mUid); 543 if (uidProcs == null) { 544 uidProcs = new ArrayMap<String, ProcStatsEntry>(); 545 processes.put(ent.mUid, uidProcs); 546 } 547 uidProcs.put(ent.mName, ent); 548 } 549 } 550 } 551 */ 552 553 Collections.sort(entries, sEntryCompare); 554 555 long maxWeight = 1; 556 for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) { 557 ProcStatsEntry proc = entries.get(i); 558 if (maxWeight < proc.mWeight) { 559 maxWeight = proc.mWeight; 560 } 561 } 562 mMaxWeight = maxWeight; 563 564 if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI"); 565 566 for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) { 567 ProcStatsEntry proc = entries.get(i); 568 final double percentOfWeight = (((double)proc.mWeight) / maxWeight) * 100; 569 final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100; 570 if (percentOfWeight < 1 && percentOfTime < 33) { 571 if (DEBUG) Log.d(TAG, "Skipping " + proc.mName + " weight=" + percentOfWeight 572 + " time=" + percentOfTime); 573 continue; 574 } 575 ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null, proc); 576 proc.evaluateTargetPackage(pm, mStats, totals, sEntryCompare, mUseUss, 577 mStatsType == MENU_TYPE_BACKGROUND); 578 proc.retrieveUiData(pm); 579 pref.setTitle(proc.mUiLabel); 580 if (proc.mUiTargetApp != null) { 581 pref.setIcon(proc.mUiTargetApp.loadIcon(pm)); 582 } 583 pref.setOrder(i); 584 pref.setPercent(percentOfWeight, percentOfTime); 585 mAppListGroup.addPreference(pref); 586 if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) { 587 if (DEBUG) Log.d(TAG, "Done with UI, hit item limit!"); 588 break; 589 } 590 } 591 } 592 593 private void load() { 594 try { 595 mLastDuration = mDuration; 596 mMemState = mProcessStats.getCurrentMemoryState(); 597 ParcelFileDescriptor pfd = mProcessStats.getStatsOverTime(mDuration); 598 mStats = new ProcessStats(false); 599 InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 600 mStats.read(is); 601 try { 602 is.close(); 603 } catch (IOException e) { 604 } 605 if (mStats.mReadError != null) { 606 Log.w(TAG, "Failure reading process stats: " + mStats.mReadError); 607 } 608 } catch (RemoteException e) { 609 Log.e(TAG, "RemoteException:", e); 610 } 611 } 612} 613