Fix issue #10948509: Crash in procstats when there is no data

Also make us much better about determining which app to blame for
a particular running process, organize the display of services by
their owning app, apply some new heuristics for deciding what goes
in the process list so that we can still display interesting processes
when we haven't collected pss data for them yet, etc.

Change-Id: I7e87225d3dabc66cf3ff020b5db48401b14aaf47
This commit is contained in:
Dianne Hackborn
2013-09-29 17:07:49 -07:00
parent bc2c3db8f9
commit 5635594c38
5 changed files with 288 additions and 95 deletions

View File

@@ -801,7 +801,8 @@
<activity android:name="Settings$AppOpsSummaryActivity" <activity android:name="Settings$AppOpsSummaryActivity"
android:label="@string/app_ops_settings" android:label="@string/app_ops_settings"
android:taskAffinity="" android:taskAffinity=""
android:excludeFromRecents="true"> android:excludeFromRecents="true"
android:enabled="false">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<action android:name="android.settings.APP_OPS_SETTINGS" /> <action android:name="android.settings.APP_OPS_SETTINGS" />

View File

@@ -21,8 +21,8 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.util.SparseArray;
import com.android.internal.app.ProcessStats; import com.android.internal.app.ProcessStats;
import java.util.ArrayList; import java.util.ArrayList;
@@ -31,11 +31,12 @@ import java.util.Comparator;
public final class ProcStatsEntry implements Parcelable { public final class ProcStatsEntry implements Parcelable {
private static final String TAG = "ProcStatsEntry"; private static final String TAG = "ProcStatsEntry";
private static boolean DEBUG = ProcessStatsUi.DEBUG;
final String mPackage; final String mPackage;
final int mUid; final int mUid;
final String mName; final String mName;
final boolean mUnique; final ArrayList<String> mPackages = new ArrayList<String>();
final long mDuration; final long mDuration;
final long mAvgPss; final long mAvgPss;
final long mMaxPss; final long mMaxPss;
@@ -45,33 +46,35 @@ public final class ProcStatsEntry implements Parcelable {
String mBestTargetPackage; String mBestTargetPackage;
ArrayList<Service> mServices = new ArrayList<Service>(2); ArrayMap<String, ArrayList<Service>> mServices = new ArrayMap<String, ArrayList<Service>>(1);
public ApplicationInfo mUiTargetApp; public ApplicationInfo mUiTargetApp;
public String mUiLabel; public String mUiLabel;
public String mUiBaseLabel; public String mUiBaseLabel;
public String mUiPackage; public String mUiPackage;
public ProcStatsEntry(ProcessStats.ProcessState proc, public ProcStatsEntry(ProcessStats.ProcessState proc, String packageName,
ProcessStats.ProcessDataCollection tmpTotals, boolean useUss, boolean weightWithTime) { ProcessStats.ProcessDataCollection tmpTotals, boolean useUss, boolean weightWithTime) {
ProcessStats.computeProcessData(proc, tmpTotals, 0); ProcessStats.computeProcessData(proc, tmpTotals, 0);
mPackage = proc.mPackage; mPackage = proc.mPackage;
mUid = proc.mUid; mUid = proc.mUid;
mName = proc.mName; mName = proc.mName;
mUnique = proc.mCommonProcess == proc; mPackages.add(packageName);
mDuration = tmpTotals.totalTime; mDuration = tmpTotals.totalTime;
mAvgPss = tmpTotals.avgPss; mAvgPss = tmpTotals.avgPss;
mMaxPss = tmpTotals.maxPss; mMaxPss = tmpTotals.maxPss;
mAvgUss = tmpTotals.avgUss; mAvgUss = tmpTotals.avgUss;
mMaxUss = tmpTotals.maxUss; mMaxUss = tmpTotals.maxUss;
mWeight = (weightWithTime ? mDuration : 1) * (useUss ? mAvgUss : mAvgPss); mWeight = (weightWithTime ? mDuration : 1) * (useUss ? mAvgUss : mAvgPss);
if (DEBUG) Log.d(TAG, "New proc entry " + proc.mName + ": dur=" + mDuration
+ " avgpss=" + mAvgPss + " weight=" + mWeight);
} }
public ProcStatsEntry(Parcel in) { public ProcStatsEntry(Parcel in) {
mPackage = in.readString(); mPackage = in.readString();
mUid = in.readInt(); mUid = in.readInt();
mName = in.readString(); mName = in.readString();
mUnique = in.readInt() != 0; in.readStringList(mPackages);
mDuration = in.readLong(); mDuration = in.readLong();
mAvgPss = in.readLong(); mAvgPss = in.readLong();
mMaxPss = in.readLong(); mMaxPss = in.readLong();
@@ -79,40 +82,118 @@ public final class ProcStatsEntry implements Parcelable {
mMaxUss = in.readLong(); mMaxUss = in.readLong();
mWeight = in.readLong(); mWeight = in.readLong();
mBestTargetPackage = in.readString(); mBestTargetPackage = in.readString();
in.readTypedList(mServices, Service.CREATOR); final int N = in.readInt();
if (N > 0) {
mServices.ensureCapacity(N);
for (int i=0; i<N; i++) {
String key = in.readString();
ArrayList<Service> value = new ArrayList<Service>();
in.readTypedList(value, Service.CREATOR);
mServices.append(key, value);
}
}
} }
public void evaluateTargetPackage(ProcessStats stats, ProcessStats.ProcessDataCollection totals, public void addPackage(String packageName) {
Comparator<ProcStatsEntry> compare, boolean useUss, boolean weightWithTime) { mPackages.add(packageName);
}
public void evaluateTargetPackage(PackageManager pm, ProcessStats stats,
ProcessStats.ProcessDataCollection totals, Comparator<ProcStatsEntry> compare,
boolean useUss, boolean weightWithTime) {
mBestTargetPackage = null; mBestTargetPackage = null;
if (mUnique) { if (mPackages.size() == 1) {
mBestTargetPackage = mPackage; if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": single pkg " + mPackages.get(0));
mBestTargetPackage = mPackages.get(0);
} else { } else {
// See if there is one significant package that was running here. // See if there is one significant package that was running here.
ArrayList<ProcStatsEntry> subProcs = new ArrayList<ProcStatsEntry>(); ArrayList<ProcStatsEntry> subProcs = new ArrayList<ProcStatsEntry>();
for (int ipkg=0, NPKG=stats.mPackages.getMap().size(); ipkg<NPKG; ipkg++) { for (int ipkg=0; ipkg<mPackages.size(); ipkg++) {
SparseArray<ProcessStats.PackageState> uids ProcessStats.PackageState pkgState = stats.mPackages.get(mPackages.get(ipkg), mUid);
= stats.mPackages.getMap().valueAt(ipkg); if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ", pkg "
for (int iu=0, NU=uids.size(); iu<NU; iu++) { + mPackages.get(ipkg) + ":");
if (uids.keyAt(iu) != mUid) { if (pkgState == null) {
Log.w(TAG, "No package state found for " + mPackages.get(ipkg) + "/"
+ mUid + " in process " + mName);
continue; continue;
} }
ProcessStats.PackageState pkgState = uids.valueAt(iu); ProcessStats.ProcessState pkgProc = pkgState.mProcesses.get(mName);
for (int iproc=0, NPROC=pkgState.mProcesses.size(); iproc<NPROC; iproc++) { if (pkgProc == null) {
ProcessStats.ProcessState subProc = Log.w(TAG, "No process " + mName + " found in package state "
pkgState.mProcesses.valueAt(iproc); + mPackages.get(ipkg) + "/" + mUid);
if (subProc.mName.equals(mName)) { continue;
subProcs.add(new ProcStatsEntry(subProc, totals, useUss, }
subProcs.add(new ProcStatsEntry(pkgProc, pkgState.mPackageName, totals, useUss,
weightWithTime)); weightWithTime));
} }
}
}
}
if (subProcs.size() > 1) { if (subProcs.size() > 1) {
Collections.sort(subProcs, compare); Collections.sort(subProcs, compare);
if (subProcs.get(0).mWeight > (subProcs.get(1).mWeight*3)) { if (subProcs.get(0).mWeight > (subProcs.get(1).mWeight*3)) {
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": best pkg "
+ subProcs.get(0).mPackage + " weight " + subProcs.get(0).mWeight
+ " better than " + subProcs.get(1).mPackage
+ " weight " + subProcs.get(1).mWeight);
mBestTargetPackage = subProcs.get(0).mPackage; mBestTargetPackage = subProcs.get(0).mPackage;
return;
} }
// Couldn't find one that is best by weight, let's decide on best another
// way: the one that has the longest running service, accounts for at least
// half of the maximum weight, and has specified an explicit app icon.
long maxWeight = subProcs.get(0).mWeight;
long bestRunTime = -1;
for (int i=0; i<subProcs.size(); i++) {
if (subProcs.get(i).mWeight < (maxWeight/2)) {
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
+ subProcs.get(i).mPackage + " weight " + subProcs.get(i).mWeight
+ " too small");
continue;
}
try {
ApplicationInfo ai = pm.getApplicationInfo(subProcs.get(i).mPackage, 0);
if (ai.icon == 0) {
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
+ subProcs.get(i).mPackage + " has no icon");
continue;
}
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
+ subProcs.get(i).mPackage + " failed finding app info");
continue;
}
ArrayList<Service> subProcServices = null;
for (int isp=0, NSP=mServices.size(); isp<NSP; isp++) {
ArrayList<Service> subServices = mServices.valueAt(isp);
if (subServices.get(0).mPackage.equals(subProcs.get(i).mPackage)) {
subProcServices = subServices;
break;
}
}
long thisRunTime = 0;
if (subProcServices != null) {
for (int iss=0, NSS=subProcServices.size(); iss<NSS; iss++) {
Service service = subProcServices.get(iss);
if (service.mDuration > thisRunTime) {
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
+ subProcs.get(i).mPackage + " service " + service.mName
+ " run time is " + service.mDuration);
thisRunTime = service.mDuration;
break;
}
}
}
if (thisRunTime > bestRunTime) {
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
+ subProcs.get(i).mPackage + " new best run time " + thisRunTime);
mBestTargetPackage = subProcs.get(i).mPackage;
bestRunTime = thisRunTime;
} else {
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
+ subProcs.get(i).mPackage + " run time " + thisRunTime
+ " not as good as last " + bestRunTime);
}
}
} else if (subProcs.size() == 1) {
mBestTargetPackage = subProcs.get(0).mPackage;
} }
} }
} }
@@ -178,7 +259,12 @@ public final class ProcStatsEntry implements Parcelable {
} }
public void addService(ProcessStats.ServiceState svc) { public void addService(ProcessStats.ServiceState svc) {
mServices.add(new Service(svc)); ArrayList<Service> services = mServices.get(svc.mPackage);
if (services == null) {
services = new ArrayList<Service>();
mServices.put(svc.mPackage, services);
}
services.add(new Service(svc));
} }
@Override @Override
@@ -191,7 +277,7 @@ public final class ProcStatsEntry implements Parcelable {
dest.writeString(mPackage); dest.writeString(mPackage);
dest.writeInt(mUid); dest.writeInt(mUid);
dest.writeString(mName); dest.writeString(mName);
dest.writeInt(mUnique ? 1 : 0); dest.writeStringList(mPackages);
dest.writeLong(mDuration); dest.writeLong(mDuration);
dest.writeLong(mAvgPss); dest.writeLong(mAvgPss);
dest.writeLong(mMaxPss); dest.writeLong(mMaxPss);
@@ -199,7 +285,12 @@ public final class ProcStatsEntry implements Parcelable {
dest.writeLong(mMaxUss); dest.writeLong(mMaxUss);
dest.writeLong(mWeight); dest.writeLong(mWeight);
dest.writeString(mBestTargetPackage); dest.writeString(mBestTargetPackage);
dest.writeTypedList(mServices); final int N = mServices.size();
dest.writeInt(N);
for (int i=0; i<N; i++) {
dest.writeString(mServices.keyAt(i));
dest.writeTypedList(mServices.valueAt(i));
}
} }
public static final Parcelable.Creator<ProcStatsEntry> CREATOR public static final Parcelable.Creator<ProcStatsEntry> CREATOR

View File

@@ -168,6 +168,23 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
} }
} }
private void addPackageHeaderItem(ViewGroup parent, String packageName) {
LayoutInflater inflater = getActivity().getLayoutInflater();
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.running_processes_item,
null);
parent.addView(item);
final ImageView icon = (ImageView) item.findViewById(R.id.icon);
TextView nameView = (TextView) item.findViewById(R.id.name);
TextView descriptionView = (TextView) item.findViewById(R.id.description);
try {
ApplicationInfo ai = mPm.getApplicationInfo(packageName, 0);
icon.setImageDrawable(ai.loadIcon(mPm));
nameView.setText(ai.loadLabel(mPm));
} catch (PackageManager.NameNotFoundException e) {
}
descriptionView.setText(packageName);
}
private void addDetailsItem(ViewGroup parent, CharSequence label, CharSequence value) { private void addDetailsItem(ViewGroup parent, CharSequence label, CharSequence value) {
LayoutInflater inflater = getActivity().getLayoutInflater(); LayoutInflater inflater = getActivity().getLayoutInflater();
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text, ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text,
@@ -204,13 +221,21 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
}; };
private void fillServicesSection() { private void fillServicesSection() {
LayoutInflater inflater = getActivity().getLayoutInflater();
if (mEntry.mServices.size() > 0) { if (mEntry.mServices.size() > 0) {
boolean addPackageSections = false;
if (mEntry.mServices.size() > 1
|| !mEntry.mServices.valueAt(0).get(0).mPackage.equals(mEntry.mPackage)) {
addPackageSections = true;
}
for (int ip=0; ip<mEntry.mServices.size(); ip++) {
ArrayList<ProcStatsEntry.Service> services = ArrayList<ProcStatsEntry.Service> services =
(ArrayList<ProcStatsEntry.Service>)mEntry.mServices.clone(); (ArrayList<ProcStatsEntry.Service>)mEntry.mServices.valueAt(ip).clone();
Collections.sort(services, sServiceCompare); Collections.sort(services, sServiceCompare);
for (int i=0; i<services.size(); i++) { if (addPackageSections) {
ProcStatsEntry.Service service = services.get(i); addPackageHeaderItem(mServicesParent, services.get(0).mPackage);
}
for (int is=0; is<services.size(); is++) {
ProcStatsEntry.Service service = services.get(is);
String label = service.mName; String label = service.mName;
int tail = label.lastIndexOf('.'); int tail = label.lastIndexOf('.');
if (tail >= 0 && tail < (label.length()-1)) { if (tail >= 0 && tail < (label.length()-1)) {
@@ -223,6 +248,7 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
} }
} }
} }
}
private void killProcesses() { private void killProcesses() {
ActivityManager am = (ActivityManager)getActivity().getSystemService( ActivityManager am = (ActivityManager)getActivity().getSystemService(

View File

@@ -45,7 +45,7 @@ public class ProcessStatsPreference extends Preference {
public void setPercent(double percentOfWeight, double percentOfTime) { public void setPercent(double percentOfWeight, double percentOfTime) {
mProgress = (int) Math.ceil(percentOfWeight); mProgress = (int) Math.ceil(percentOfWeight);
mProgressText = getContext().getResources().getString( mProgressText = getContext().getResources().getString(
R.string.percentage, (int) Math.ceil(percentOfTime)); R.string.percentage, (int) Math.round(percentOfTime));
notifyChanged(); notifyChanged();
} }

View File

@@ -19,7 +19,6 @@ package com.android.settings.applications;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcel;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
@@ -30,7 +29,6 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup; import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.util.TimeUtils; import android.util.TimeUtils;
@@ -39,6 +37,7 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.SubMenu; import android.view.SubMenu;
import com.android.internal.app.IProcessStats; import com.android.internal.app.IProcessStats;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.ProcessStats; import com.android.internal.app.ProcessStats;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.fuelgauge.Utils; import com.android.settings.fuelgauge.Utils;
@@ -50,8 +49,8 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
public class ProcessStatsUi extends PreferenceFragment { public class ProcessStatsUi extends PreferenceFragment {
private static final String TAG = "ProcessStatsUi"; static final String TAG = "ProcessStatsUi";
private static final boolean DEBUG = false; static final boolean DEBUG = false;
private static final String KEY_APP_LIST = "app_list"; private static final String KEY_APP_LIST = "app_list";
private static final String KEY_MEM_STATUS = "mem_status"; private static final String KEY_MEM_STATUS = "mem_status";
@@ -76,6 +75,10 @@ public class ProcessStatsUi extends PreferenceFragment {
return 1; return 1;
} else if (lhs.mWeight > rhs.mWeight) { } else if (lhs.mWeight > rhs.mWeight) {
return -1; return -1;
} else if (lhs.mDuration < rhs.mDuration) {
return 1;
} else if (lhs.mDuration > rhs.mDuration) {
return -1;
} }
return 0; return 0;
} }
@@ -112,7 +115,7 @@ public class ProcessStatsUi extends PreferenceFragment {
// batches of 3 hours so we want to allow the time we use to be slightly // batches of 3 hours so we want to allow the time we use to be slightly
// smaller than the actual time selected instead of bumping up to 3 hours // smaller than the actual time selected instead of bumping up to 3 hours
// beyond it. // beyond it.
private static final long DURATION_QUANTUM = 3*60*60*1000; private static final long DURATION_QUANTUM = ProcessStats.COMMIT_PERIOD;
private static long[] sDurations = new long[] { private static long[] sDurations = new long[] {
3*60*60*1000 - DURATION_QUANTUM/2, 6*60*60*1000 - DURATION_QUANTUM/2, 3*60*60*1000 - DURATION_QUANTUM/2, 6*60*60*1000 - DURATION_QUANTUM/2,
12*60*60*1000 - DURATION_QUANTUM/2, 24*60*60*1000 - DURATION_QUANTUM/2 12*60*60*1000 - DURATION_QUANTUM/2, 24*60*60*1000 - DURATION_QUANTUM/2
@@ -319,6 +322,12 @@ public class ProcessStatsUi extends PreferenceFragment {
ProcessStats.STATE_CACHED_EMPTY ProcessStats.STATE_CACHED_EMPTY
}; };
private String makeDuration(long time) {
StringBuilder sb = new StringBuilder(32);
TimeUtils.formatDuration(time, sb);
return sb.toString();
}
private void refreshStats() { private void refreshStats() {
updateMenus(); updateMenus();
@@ -378,6 +387,7 @@ public class ProcessStatsUi extends PreferenceFragment {
mTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations, mTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations,
mStats.mMemFactor, mStats.mStartTime, now); mStats.mMemFactor, mStats.mStartTime, now);
if (DEBUG) Log.d(TAG, "Total time of stats: " + makeDuration(mTotalTime));
LinearColorPreference colors = new LinearColorPreference(getActivity()); LinearColorPreference colors = new LinearColorPreference(getActivity());
colors.setOrder(-1); colors.setOrder(-1);
@@ -396,7 +406,7 @@ public class ProcessStatsUi extends PreferenceFragment {
+ memTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]) / (float)mTotalTime, + memTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]) / (float)mTotalTime,
memTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL] / (float)mTotalTime); memTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL] / (float)mTotalTime);
ArrayList<ProcStatsEntry> procs = new ArrayList<ProcStatsEntry>(); ArrayList<ProcStatsEntry> entries = new ArrayList<ProcStatsEntry>();
/* /*
ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked( ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked(
@@ -407,50 +417,43 @@ public class ProcessStatsUi extends PreferenceFragment {
} }
*/ */
ArrayMap<String, ProcStatsEntry> processes = new ArrayMap<String, ProcStatsEntry>( if (DEBUG) Log.d(TAG, "-------------------- PULLING PROCESSES");
mStats.mProcesses.getMap().size());
for (int ip=0, N=mStats.mProcesses.getMap().size(); ip<N; ip++) { final ProcessMap<ProcStatsEntry> entriesMap = new ProcessMap<ProcStatsEntry>();
SparseArray<ProcessStats.ProcessState> uids = mStats.mProcesses.getMap().valueAt(ip); for (int ipkg=0, N=mStats.mPackages.getMap().size(); ipkg<N; ipkg++) {
for (int iu=0; iu<uids.size(); iu++) { final SparseArray<ProcessStats.PackageState> pkgUids
ProcStatsEntry ent = new ProcStatsEntry(uids.valueAt(iu), totals, mUseUss, = mStats.mPackages.getMap().valueAt(ipkg);
for (int iu=0; iu<pkgUids.size(); iu++) {
final ProcessStats.PackageState st = pkgUids.valueAt(iu);
for (int iproc=0; iproc<st.mProcesses.size(); iproc++) {
final ProcessStats.ProcessState pkgProc = st.mProcesses.valueAt(iproc);
final ProcessStats.ProcessState proc = mStats.mProcesses.get(pkgProc.mName,
pkgProc.mUid);
if (proc == null) {
Log.w(TAG, "No process found for pkg " + st.mPackageName
+ "/" + st.mUid + " proc name " + pkgProc.mName);
continue;
}
ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid);
if (ent == null) {
ent = new ProcStatsEntry(proc, st.mPackageName, totals, mUseUss,
mStatsType == MENU_TYPE_BACKGROUND); mStatsType == MENU_TYPE_BACKGROUND);
procs.add(ent); if (ent.mDuration > 0) {
processes.put(ent.mName, ent); if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
+ proc.mUid + ": time=" + makeDuration(ent.mDuration) + " ("
+ ((((double)ent.mDuration) / mTotalTime) * 100) + "%)"
+ " pss=" + ent.mAvgPss);
entriesMap.put(proc.mName, proc.mUid, ent);
entries.add(ent);
}
} else {
ent.addPackage(st.mPackageName);
}
}
} }
} }
Collections.sort(procs, sEntryCompare); if (DEBUG) Log.d(TAG, "-------------------- MAPPING SERVICES");
while (procs.size() > MAX_ITEMS_TO_LIST) {
procs.remove(procs.size()-1);
}
long maxWeight = 0;
for (int i=0, N=(procs != null ? procs.size() : 0); i<N; i++) {
ProcStatsEntry proc = procs.get(i);
if (maxWeight < proc.mWeight) {
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) break;
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null, proc);
proc.evaluateTargetPackage(mStats, totals, sEntryCompare, mUseUss,
mStatsType == MENU_TYPE_BACKGROUND);
proc.retrieveUiData(pm);
pref.setTitle(proc.mUiLabel);
if (proc.mUiTargetApp != null) {
pref.setIcon(proc.mUiTargetApp.loadIcon(pm));
}
pref.setOrder(i);
pref.setPercent(percentOfWeight, percentOfTime);
mAppListGroup.addPreference(pref);
if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) break;
}
// Add in service info. // Add in service info.
if (mStatsType == MENU_TYPE_BACKGROUND) { if (mStatsType == MENU_TYPE_BACKGROUND) {
@@ -461,8 +464,15 @@ public class ProcessStatsUi extends PreferenceFragment {
for (int is=0, NS=ps.mServices.size(); is<NS; is++) { for (int is=0, NS=ps.mServices.size(); is<NS; is++) {
ProcessStats.ServiceState ss = ps.mServices.valueAt(is); ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
if (ss.mProcessName != null) { if (ss.mProcessName != null) {
ProcStatsEntry ent = processes.get(ss.mProcessName); ProcStatsEntry ent = entriesMap.get(ss.mProcessName, uids.keyAt(iu));
if (ent != null) {
if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName
+ "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc "
+ ss.mProcessName);
ent.addService(ss); ent.addService(ss);
} else {
Log.w(TAG, "No process " + ss.mProcessName + "/" + uids.keyAt(iu)
+ " for service " + ss.mName);
} }
} }
} }
@@ -470,6 +480,71 @@ public class ProcessStatsUi extends PreferenceFragment {
} }
} }
/*
SparseArray<ArrayMap<String, ProcStatsEntry>> processes
= new SparseArray<ArrayMap<String, ProcStatsEntry>>();
for (int ip=0, N=mStats.mProcesses.getMap().size(); ip<N; ip++) {
SparseArray<ProcessStats.ProcessState> uids = mStats.mProcesses.getMap().valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
ProcessStats.ProcessState st = uids.valueAt(iu);
ProcStatsEntry ent = new ProcStatsEntry(st, totals, mUseUss,
mStatsType == MENU_TYPE_BACKGROUND);
if (ent.mDuration > 0) {
if (DEBUG) Log.d(TAG, "Adding proc " + st.mName + "/" + st.mUid + ": time="
+ makeDuration(ent.mDuration) + " ("
+ ((((double)ent.mDuration) / mTotalTime) * 100) + "%)");
procs.add(ent);
ArrayMap<String, ProcStatsEntry> uidProcs = processes.get(ent.mUid);
if (uidProcs == null) {
uidProcs = new ArrayMap<String, ProcStatsEntry>();
processes.put(ent.mUid, uidProcs);
}
uidProcs.put(ent.mName, ent);
}
}
}
*/
Collections.sort(entries, sEntryCompare);
long maxWeight = 1;
for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) {
ProcStatsEntry proc = entries.get(i);
if (maxWeight < proc.mWeight) {
maxWeight = proc.mWeight;
}
}
mMaxWeight = maxWeight;
if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI");
for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) {
ProcStatsEntry proc = entries.get(i);
final double percentOfWeight = (((double)proc.mWeight) / maxWeight) * 100;
final double percentOfTime = (((double)proc.mDuration) / mTotalTime) * 100;
if (percentOfWeight < 1 && percentOfTime < 33) {
if (DEBUG) Log.d(TAG, "Skipping " + proc.mName + " weight=" + percentOfWeight
+ " time=" + percentOfTime);
continue;
}
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null, proc);
proc.evaluateTargetPackage(pm, mStats, totals, sEntryCompare, mUseUss,
mStatsType == MENU_TYPE_BACKGROUND);
proc.retrieveUiData(pm);
pref.setTitle(proc.mUiLabel);
if (proc.mUiTargetApp != null) {
pref.setIcon(proc.mUiTargetApp.loadIcon(pm));
}
pref.setOrder(i);
pref.setPercent(percentOfWeight, percentOfTime);
mAppListGroup.addPreference(pref);
if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) {
if (DEBUG) Log.d(TAG, "Done with UI, hit item limit!");
break;
}
}
}
private void load() { private void load() {
try { try {
mLastDuration = mDuration; mLastDuration = mDuration;