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:
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user