Add details screen to proc stats.

Lets you see the actual RAM use and % running time, a list of
all of the services that are associated with it (kind-of, not
working correctly for those that share processes), and most
importantly a glorious FORCE STOP button.

Change-Id: I34ac30c88f1187227a8a7809ae103118c8b9a865
This commit is contained in:
Dianne Hackborn
2013-09-04 15:47:59 -07:00
parent 35ec3b7fa3
commit 0448673834
6 changed files with 566 additions and 116 deletions

View File

@@ -16,11 +16,22 @@
package com.android.settings.applications;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.app.ProcessStats;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public final class ProcStatsEntry implements Parcelable {
private static final String TAG = "ProcStatsEntry";
public final class ProcStatsEntry {
final String mPackage;
final int mUid;
final String mName;
@@ -29,7 +40,14 @@ public final class ProcStatsEntry {
final long mAvgPss;
final long mWeight;
ArrayList<Service> mServices;
String mBestTargetPackage;
ArrayList<Service> mServices = new ArrayList<Service>(2);
public ApplicationInfo mUiTargetApp;
public String mUiLabel;
public String mUiBaseLabel;
public String mUiPackage;
public ProcStatsEntry(ProcessStats.ProcessState proc,
ProcessStats.ProcessDataCollection tmpTotals) {
@@ -43,18 +61,156 @@ public final class ProcStatsEntry {
mWeight = mDuration * mAvgPss;
}
public ProcStatsEntry(Parcel in) {
mPackage = in.readString();
mUid = in.readInt();
mName = in.readString();
mUnique = in.readInt() != 0;
mDuration = in.readLong();
mAvgPss = in.readLong();
mWeight = in.readLong();
mBestTargetPackage = in.readString();
in.readTypedList(mServices, Service.CREATOR);
}
public void evaluateTargetPackage(ProcessStats stats,
ProcessStats.ProcessDataCollection totals, Comparator<ProcStatsEntry> compare) {
mBestTargetPackage = null;
if (mUnique) {
mBestTargetPackage = mPackage;
addServices(stats.getPackageStateLocked(mPackage, mUid));
} else {
// See if there is one significant package that was running here.
ArrayList<ProcStatsEntry> subProcs = new ArrayList<ProcStatsEntry>();
for (int ipkg=0, NPKG=stats.mPackages.getMap().size(); ipkg<NPKG; ipkg++) {
SparseArray<ProcessStats.PackageState> uids
= stats.mPackages.getMap().valueAt(ipkg);
for (int iu=0, NU=uids.size(); iu<NU; iu++) {
if (uids.keyAt(iu) != mUid) {
continue;
}
ProcessStats.PackageState pkgState = uids.valueAt(iu);
boolean match = false;
for (int iproc=0, NPROC=pkgState.mProcesses.size(); iproc<NPROC; iproc++) {
ProcessStats.ProcessState subProc =
pkgState.mProcesses.valueAt(iproc);
if (subProc.mName.equals(mName)) {
match = true;
subProcs.add(new ProcStatsEntry(subProc, totals));
}
}
if (match) {
addServices(stats.getPackageStateLocked(mPackage, mUid));
}
}
}
if (subProcs.size() > 1) {
Collections.sort(subProcs, compare);
if (subProcs.get(0).mWeight > (subProcs.get(1).mWeight*3)) {
mBestTargetPackage = subProcs.get(0).mPackage;
}
}
}
}
public void retrieveUiData(PackageManager pm) {
mUiTargetApp = null;
mUiLabel = mUiBaseLabel = mName;
mUiPackage = mBestTargetPackage;
if (mUiPackage != null) {
// Only one app associated with this process.
try {
mUiTargetApp = pm.getApplicationInfo(mUiPackage,
PackageManager.GET_DISABLED_COMPONENTS |
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
PackageManager.GET_UNINSTALLED_PACKAGES);
String name = mUiBaseLabel = mUiTargetApp.loadLabel(pm).toString();
if (mName.equals(mUiPackage)) {
mUiLabel = name;
} else {
if (mName.startsWith(mUiPackage)) {
int off = mUiPackage.length();
if (mName.length() > off) {
off++;
}
mUiLabel = name + " (" + mName.substring(off) + ")";
} else {
mUiLabel = name + " (" + mName + ")";
}
}
} catch (PackageManager.NameNotFoundException e) {
}
}
if (mUiTargetApp == null) {
String[] packages = pm.getPackagesForUid(mUid);
if (packages != null) {
for (String curPkg : packages) {
try {
final PackageInfo pi = pm.getPackageInfo(curPkg,
PackageManager.GET_DISABLED_COMPONENTS |
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
PackageManager.GET_UNINSTALLED_PACKAGES);
if (pi.sharedUserLabel != 0) {
mUiTargetApp = pi.applicationInfo;
final CharSequence nm = pm.getText(curPkg,
pi.sharedUserLabel, pi.applicationInfo);
if (nm != null) {
mUiBaseLabel = nm.toString();
mUiLabel = mUiBaseLabel + " (" + mName + ")";
} else {
mUiBaseLabel = mUiTargetApp.loadLabel(pm).toString();
mUiLabel = mUiBaseLabel + " (" + mName + ")";
}
break;
}
} catch (PackageManager.NameNotFoundException e) {
}
}
} else {
// no current packages for this uid, typically because of uninstall
Log.i(TAG, "No package for uid " + mUid);
}
}
}
public void addServices(ProcessStats.PackageState pkgState) {
for (int isvc=0, NSVC=pkgState.mServices.size(); isvc<NSVC; isvc++) {
ProcessStats.ServiceState svc = pkgState.mServices.valueAt(isvc);
// XXX can't tell what process it is in!
if (mServices == null) {
mServices = new ArrayList<Service>();
}
mServices.add(new Service(svc));
}
}
public static final class Service {
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPackage);
dest.writeInt(mUid);
dest.writeString(mName);
dest.writeInt(mUnique ? 1 : 0);
dest.writeLong(mDuration);
dest.writeLong(mAvgPss);
dest.writeLong(mWeight);
dest.writeString(mBestTargetPackage);
dest.writeTypedList(mServices);
}
public static final Parcelable.Creator<ProcStatsEntry> CREATOR
= new Parcelable.Creator<ProcStatsEntry>() {
public ProcStatsEntry createFromParcel(Parcel in) {
return new ProcStatsEntry(in);
}
public ProcStatsEntry[] newArray(int size) {
return new ProcStatsEntry[size];
}
};
public static final class Service implements Parcelable {
final String mPackage;
final String mName;
final long mDuration;
@@ -62,15 +218,51 @@ public final class ProcStatsEntry {
public Service(ProcessStats.ServiceState service) {
mPackage = service.mPackage;
mName = service.mName;
mDuration = ProcessStats.dumpSingleServiceTime(null, null, service,
long startDuration = ProcessStats.dumpSingleServiceTime(null, null, service,
ProcessStats.ServiceState.SERVICE_STARTED,
ProcessStats.STATE_NOTHING, 0, 0)
+ ProcessStats.dumpSingleServiceTime(null, null, service,
ProcessStats.STATE_NOTHING, 0, 0);
long bindDuration = ProcessStats.dumpSingleServiceTime(null, null, service,
ProcessStats.ServiceState.SERVICE_BOUND,
ProcessStats.STATE_NOTHING, 0, 0)
+ ProcessStats.dumpSingleServiceTime(null, null, service,
ProcessStats.STATE_NOTHING, 0, 0);
long execDuration = ProcessStats.dumpSingleServiceTime(null, null, service,
ProcessStats.ServiceState.SERVICE_EXEC,
ProcessStats.STATE_NOTHING, 0, 0);
if (bindDuration > startDuration) {
startDuration = bindDuration;
}
if (execDuration > startDuration) {
startDuration = execDuration;
}
mDuration = startDuration;
}
public Service(Parcel in) {
mPackage = in.readString();
mName = in.readString();
mDuration = in.readLong();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPackage);
dest.writeString(mName);
dest.writeLong(mDuration);
}
public static final Parcelable.Creator<Service> CREATOR
= new Parcelable.Creator<Service>() {
public Service createFromParcel(Parcel in) {
return new Service(in);
}
public Service[] newArray(int size) {
return new Service[size];
}
};
}
}

View File

@@ -0,0 +1,258 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
import android.preference.PreferenceActivity;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.settings.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import static com.android.settings.Utils.prepareCustomPreferencesList;
public class ProcessStatsDetail extends Fragment implements Button.OnClickListener {
private static final String TAG = "ProcessStatsDetail";
public static final int ACTION_FORCE_STOP = 1;
public static final String EXTRA_ENTRY = "entry";
public static final String EXTRA_MAX_WEIGHT = "max_weight";
public static final String EXTRA_TOTAL_TIME = "total_time";
private PackageManager mPm;
private DevicePolicyManager mDpm;
private ProcStatsEntry mEntry;
private long mMaxWeight;
private long mTotalTime;
private View mRootView;
private TextView mTitleView;
private ViewGroup mTwoButtonsPanel;
private Button mForceStopButton;
private Button mReportButton;
private ViewGroup mDetailsParent;
private ViewGroup mServicesParent;
public static String makePercentString(Resources res, long amount, long total) {
final double percent = (((double)amount) / total) * 100;
return res.getString(R.string.percentage, (int) Math.ceil(percent));
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mPm = getActivity().getPackageManager();
mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
final Bundle args = getArguments();
mEntry = (ProcStatsEntry)args.getParcelable(EXTRA_ENTRY);
mEntry.retrieveUiData(mPm);
mMaxWeight = args.getLong(EXTRA_MAX_WEIGHT);
mTotalTime = args.getLong(EXTRA_TOTAL_TIME);
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.process_stats_details, container, false);
prepareCustomPreferencesList(container, view, view, false);
mRootView = view;
createDetails();
return view;
}
@Override
public void onResume() {
super.onResume();
checkForceStop();
}
@Override
public void onPause() {
super.onPause();
}
private void createDetails() {
final double percentOfWeight = (((double)mEntry.mWeight) / mMaxWeight) * 100;
int appLevel = (int) Math.ceil(percentOfWeight);
String appLevelText = makePercentString(getResources(), mEntry.mDuration, mTotalTime);
// Set all values in the header.
final TextView summary = (TextView) mRootView.findViewById(android.R.id.summary);
summary.setText(mEntry.mName);
summary.setVisibility(View.VISIBLE);
mTitleView = (TextView) mRootView.findViewById(android.R.id.title);
mTitleView.setText(mEntry.mUiBaseLabel);
final TextView text1 = (TextView)mRootView.findViewById(android.R.id.text1);
text1.setText(appLevelText);
final ProgressBar progress = (ProgressBar) mRootView.findViewById(android.R.id.progress);
progress.setProgress(appLevel);
final ImageView icon = (ImageView) mRootView.findViewById(android.R.id.icon);
if (mEntry.mUiTargetApp != null) {
icon.setImageDrawable(mEntry.mUiTargetApp.loadIcon(mPm));
}
mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel);
mForceStopButton = (Button)mRootView.findViewById(R.id.right_button);
mReportButton = (Button)mRootView.findViewById(R.id.left_button);
mForceStopButton.setEnabled(false);
mReportButton.setVisibility(View.INVISIBLE);
mDetailsParent = (ViewGroup)mRootView.findViewById(R.id.details);
mServicesParent = (ViewGroup)mRootView.findViewById(R.id.services);
fillDetailsSection();
fillServicesSection();
if (mEntry.mUid >= android.os.Process.FIRST_APPLICATION_UID) {
mForceStopButton.setText(R.string.force_stop);
mForceStopButton.setTag(ACTION_FORCE_STOP);
mForceStopButton.setOnClickListener(this);
mTwoButtonsPanel.setVisibility(View.VISIBLE);
} else {
mTwoButtonsPanel.setVisibility(View.GONE);
}
}
public void onClick(View v) {
doAction((Integer) v.getTag());
}
private void doAction(int action) {
PreferenceActivity pa = (PreferenceActivity)getActivity();
switch (action) {
case ACTION_FORCE_STOP:
killProcesses();
break;
}
}
private void addDetailsItem(ViewGroup parent, CharSequence label, CharSequence value) {
LayoutInflater inflater = getActivity().getLayoutInflater();
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text,
null);
parent.addView(item);
TextView labelView = (TextView) item.findViewById(R.id.label);
TextView valueView = (TextView) item.findViewById(R.id.value);
labelView.setText(label);
valueView.setText(value);
}
private void fillDetailsSection() {
addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_ram_use),
Formatter.formatShortFileSize(getActivity(), mEntry.mAvgPss * 1024));
addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_run_time),
makePercentString(getResources(), mEntry.mDuration, mTotalTime));
}
final static Comparator<ProcStatsEntry.Service> sServiceCompare
= new Comparator<ProcStatsEntry.Service>() {
@Override
public int compare(ProcStatsEntry.Service lhs, ProcStatsEntry.Service rhs) {
if (lhs.mDuration < rhs.mDuration) {
return 1;
} else if (lhs.mDuration > rhs.mDuration) {
return -1;
}
return 0;
}
};
private void fillServicesSection() {
LayoutInflater inflater = getActivity().getLayoutInflater();
if (mEntry.mServices.size() > 0) {
ArrayList<ProcStatsEntry.Service> services =
(ArrayList<ProcStatsEntry.Service>)mEntry.mServices.clone();
Collections.sort(services, sServiceCompare);
for (int i=0; i<services.size(); i++) {
ProcStatsEntry.Service service = services.get(i);
String label = service.mName;
int tail = label.lastIndexOf('.');
if (tail >= 0 && tail < (label.length()-1)) {
label = label.substring(tail+1);
}
long duration = service.mDuration;
final double percentOfTime = (((double)duration) / mTotalTime) * 100;
addDetailsItem(mServicesParent, label, getActivity().getResources().getString(
R.string.percentage, (int) Math.ceil(percentOfTime)));
}
}
}
private void killProcesses() {
ActivityManager am = (ActivityManager)getActivity().getSystemService(
Context.ACTIVITY_SERVICE);
am.forceStopPackage(mEntry.mUiPackage);
checkForceStop();
}
private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED);
}
};
private void checkForceStop() {
if (mEntry.mUiPackage == null || mEntry.mUid < Process.FIRST_APPLICATION_UID) {
mForceStopButton.setEnabled(false);
return;
}
if (mDpm.packageHasActiveAdmins(mEntry.mUiPackage)) {
mForceStopButton.setEnabled(false);
return;
}
try {
ApplicationInfo info = mPm.getApplicationInfo(mEntry.mUiPackage, 0);
if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
mForceStopButton.setEnabled(true);
}
} catch (PackageManager.NameNotFoundException e) {
}
Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
Uri.fromParts("package", mEntry.mUiPackage, null));
intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mEntry.mUiPackage });
intent.putExtra(Intent.EXTRA_UID, mEntry.mUid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, mEntry.mUid);
getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
Activity.RESULT_CANCELED, null, null);
}
}

View File

@@ -27,15 +27,21 @@ import android.widget.TextView;
import com.android.settings.R;
public class ProcessStatsPreference extends Preference {
private final ProcStatsEntry mEntry;
private int mProgress;
private CharSequence mProgressText;
public ProcessStatsPreference(Context context, Drawable icon) {
public ProcessStatsPreference(Context context, Drawable icon, ProcStatsEntry entry) {
super(context);
mEntry = entry;
setLayoutResource(R.layout.app_percentage_item);
setIcon(icon != null ? icon : new ColorDrawable(0));
}
public ProcStatsEntry getEntry() {
return mEntry;
}
public void setPercent(double percentOfWeight, double percentOfTime) {
mProgress = (int) Math.ceil(percentOfWeight);
mProgressText = getContext().getResources().getString(

View File

@@ -17,8 +17,6 @@
package com.android.settings.applications;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Parcel;
@@ -28,10 +26,10 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.text.format.DateFormat;
import android.util.Log;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -83,6 +81,7 @@ public class ProcessStatsUi extends PreferenceFragment {
private PreferenceGroup mAppListGroup;
private Preference mMemStatusPref;
long mMaxWeight;
long mTotalTime;
@Override
@@ -127,11 +126,13 @@ public class ProcessStatsUi extends PreferenceFragment {
return false;
}
/*
PreferenceActivity pa = (PreferenceActivity)getActivity();
pa.startPreferencePanel(PowerUsageDetail.class.getName(), args,
R.string.details_title, null, null, 0);
*/
ProcessStatsPreference pgp = (ProcessStatsPreference) preference;
Bundle args = new Bundle();
args.putParcelable(ProcessStatsDetail.EXTRA_ENTRY, pgp.getEntry());
args.putLong(ProcessStatsDetail.EXTRA_MAX_WEIGHT, mMaxWeight);
args.putLong(ProcessStatsDetail.EXTRA_TOTAL_TIME, mTotalTime);
((PreferenceActivity) getActivity()).startPreferencePanel(
ProcessStatsDetail.class.getName(), args, R.string.details_title, null, null, 0);
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
@@ -263,108 +264,19 @@ public class ProcessStatsUi extends PreferenceFragment {
maxWeight = proc.mWeight;
}
}
mMaxWeight = maxWeight;
for (int i=0, N=(procs != null ? procs.size() : 0); i<N; i++) {
ProcStatsEntry proc = procs.get(i);
final double percentOfWeight = (((double)proc.mWeight) / maxWeight) * 100;
final double percentOfTime = (((double)proc.mDuration) / mTotalTime) * 100;
if (percentOfWeight < 1) continue;
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null);
ApplicationInfo targetApp = null;
String label = proc.mName;
String pkgName = null;
if (proc.mUnique) {
pkgName = proc.mPackage;
proc.addServices(mStats.getPackageStateLocked(proc.mPackage, proc.mUid));
} else {
// See if there is one significant package that was running here.
ArrayList<ProcStatsEntry> subProcs = new ArrayList<ProcStatsEntry>();
for (int ipkg=0, NPKG=mStats.mPackages.getMap().size(); ipkg<NPKG; ipkg++) {
SparseArray<ProcessStats.PackageState> uids
= mStats.mPackages.getMap().valueAt(ipkg);
for (int iu=0, NU=uids.size(); iu<NU; iu++) {
if (uids.keyAt(iu) != proc.mUid) {
continue;
}
ProcessStats.PackageState pkgState = uids.valueAt(iu);
boolean match = false;
for (int iproc=0, NPROC=pkgState.mProcesses.size(); iproc<NPROC; iproc++) {
ProcessStats.ProcessState subProc =
pkgState.mProcesses.valueAt(iproc);
if (subProc.mName.equals(proc.mName)) {
match = true;
subProcs.add(new ProcStatsEntry(subProc, totals));
}
}
if (match) {
proc.addServices(mStats.getPackageStateLocked(proc.mPackage,
proc.mUid));
}
}
}
if ( subProcs.size() > 1) {
Collections.sort(subProcs, sEntryCompare);
if (subProcs.get(0).mWeight > (subProcs.get(1).mWeight*3)) {
pkgName = subProcs.get(0).mPackage;
}
}
}
if (pkgName != null) {
// Only one app associated with this process.
try {
targetApp = pm.getApplicationInfo(pkgName,
PackageManager.GET_DISABLED_COMPONENTS |
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
PackageManager.GET_UNINSTALLED_PACKAGES);
String name = targetApp.loadLabel(pm).toString();
if (proc.mName.equals(pkgName)) {
label = name;
} else {
if (proc.mName.startsWith(pkgName)) {
int off = pkgName.length();
if (proc.mName.length() > off) {
off++;
}
label = name + " (" + proc.mName.substring(off) + ")";
} else {
label = name + " (" + proc.mName + ")";
}
}
} catch (PackageManager.NameNotFoundException e) {
}
}
if (targetApp == null) {
String[] packages = pm.getPackagesForUid(proc.mUid);
if (packages != null) {
for (String curPkg : packages) {
try {
final PackageInfo pi = pm.getPackageInfo(curPkg,
PackageManager.GET_DISABLED_COMPONENTS |
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
PackageManager.GET_UNINSTALLED_PACKAGES);
if (pi.sharedUserLabel != 0) {
targetApp = pi.applicationInfo;
final CharSequence nm = pm.getText(curPkg,
pi.sharedUserLabel, pi.applicationInfo);
if (nm != null) {
label = nm.toString() + " (" + proc.mName + ")";
} else {
label = targetApp.loadLabel(pm).toString() + " ("
+ proc.mName + ")";
}
break;
}
} catch (PackageManager.NameNotFoundException e) {
}
}
} else {
// no current packages for this uid, typically because of uninstall
Log.i(TAG, "No package for uid " + proc.mUid);
}
}
pref.setTitle(label);
if (targetApp != null) {
pref.setIcon(targetApp.loadIcon(pm));
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null, proc);
proc.evaluateTargetPackage(mStats, totals, sEntryCompare);
proc.retrieveUiData(pm);
pref.setTitle(proc.mUiLabel);
if (proc.mUiTargetApp != null) {
pref.setIcon(proc.mUiTargetApp.loadIcon(pm));
}
pref.setOrder(i);
pref.setPercent(percentOfWeight, percentOfTime);