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];
}
};
}
}