Merge "Make proc stats UI app-centric instead of process-centric."
This commit is contained in:
committed by
Android (Google) Code Review
commit
1836796559
@@ -21,6 +21,7 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
@@ -38,37 +39,49 @@ public final class ProcStatsEntry implements Parcelable {
|
||||
final int mUid;
|
||||
final String mName;
|
||||
final ArrayList<String> mPackages = new ArrayList<String>();
|
||||
final long mDuration;
|
||||
final long mAvgPss;
|
||||
final long mMaxPss;
|
||||
final long mAvgUss;
|
||||
final long mMaxUss;
|
||||
final long mWeight;
|
||||
final long mBgDuration;
|
||||
final long mAvgBgMem;
|
||||
final long mMaxBgMem;
|
||||
final double mBgWeight;
|
||||
final long mRunDuration;
|
||||
final long mAvgRunMem;
|
||||
final long mMaxRunMem;
|
||||
final double mRunWeight;
|
||||
|
||||
String mBestTargetPackage;
|
||||
|
||||
ArrayMap<String, ArrayList<Service>> mServices = new ArrayMap<String, ArrayList<Service>>(1);
|
||||
|
||||
public ApplicationInfo mUiTargetApp;
|
||||
public String mUiLabel;
|
||||
public String mUiBaseLabel;
|
||||
public String mUiPackage;
|
||||
|
||||
public ProcStatsEntry(ProcessStats.ProcessState proc, String packageName,
|
||||
ProcessStats.ProcessDataCollection tmpTotals, boolean useUss, boolean weightWithTime) {
|
||||
ProcessStats.computeProcessData(proc, tmpTotals, 0);
|
||||
ProcessStats.ProcessDataCollection tmpBgTotals,
|
||||
ProcessStats.ProcessDataCollection tmpRunTotals, boolean useUss) {
|
||||
ProcessStats.computeProcessData(proc, tmpBgTotals, 0);
|
||||
ProcessStats.computeProcessData(proc, tmpRunTotals, 0);
|
||||
mPackage = proc.mPackage;
|
||||
mUid = proc.mUid;
|
||||
mName = proc.mName;
|
||||
mPackages.add(packageName);
|
||||
mDuration = tmpTotals.totalTime;
|
||||
mAvgPss = tmpTotals.avgPss;
|
||||
mMaxPss = tmpTotals.maxPss;
|
||||
mAvgUss = tmpTotals.avgUss;
|
||||
mMaxUss = tmpTotals.maxUss;
|
||||
mWeight = (weightWithTime ? mDuration : 1) * (useUss ? mAvgUss : mAvgPss);
|
||||
if (DEBUG) Log.d(TAG, "New proc entry " + proc.mName + ": dur=" + mDuration
|
||||
+ " avgpss=" + mAvgPss + " weight=" + mWeight);
|
||||
mBgDuration = tmpBgTotals.totalTime;
|
||||
mAvgBgMem = useUss ? tmpBgTotals.avgUss : tmpBgTotals.avgPss;
|
||||
mMaxBgMem = useUss ? tmpBgTotals.maxUss : tmpBgTotals.maxPss;
|
||||
mBgWeight = mAvgBgMem * (double) mBgDuration;
|
||||
mRunDuration = tmpRunTotals.totalTime;
|
||||
mAvgRunMem = useUss ? tmpRunTotals.avgUss : tmpRunTotals.avgPss;
|
||||
mMaxRunMem = useUss ? tmpRunTotals.maxUss : tmpRunTotals.maxPss;
|
||||
mRunWeight = mAvgRunMem * (double) mRunDuration;
|
||||
if (DEBUG) Log.d(TAG, "New proc entry " + proc.mName + ": dur=" + mBgDuration
|
||||
+ " avgpss=" + mAvgBgMem + " weight=" + mBgWeight);
|
||||
}
|
||||
|
||||
public ProcStatsEntry(String pkgName, int uid, String procName, long duration, long mem) {
|
||||
mPackage = pkgName;
|
||||
mUid = uid;
|
||||
mName = procName;
|
||||
mBgDuration = mRunDuration = duration;
|
||||
mAvgBgMem = mMaxBgMem = mAvgRunMem = mMaxRunMem = mem;
|
||||
mBgWeight = mRunWeight = ((double)duration) * mem;
|
||||
if (DEBUG) Log.d(TAG, "New proc entry " + procName + ": dur=" + mBgDuration
|
||||
+ " avgpss=" + mAvgBgMem + " weight=" + mBgWeight);
|
||||
}
|
||||
|
||||
public ProcStatsEntry(Parcel in) {
|
||||
@@ -76,12 +89,14 @@ public final class ProcStatsEntry implements Parcelable {
|
||||
mUid = in.readInt();
|
||||
mName = in.readString();
|
||||
in.readStringList(mPackages);
|
||||
mDuration = in.readLong();
|
||||
mAvgPss = in.readLong();
|
||||
mMaxPss = in.readLong();
|
||||
mAvgUss = in.readLong();
|
||||
mMaxUss = in.readLong();
|
||||
mWeight = in.readLong();
|
||||
mBgDuration = in.readLong();
|
||||
mAvgBgMem = in.readLong();
|
||||
mMaxBgMem = in.readLong();
|
||||
mBgWeight = in.readDouble();
|
||||
mRunDuration = in.readLong();
|
||||
mAvgRunMem = in.readLong();
|
||||
mMaxRunMem = in.readLong();
|
||||
mRunWeight = in.readDouble();
|
||||
mBestTargetPackage = in.readString();
|
||||
final int N = in.readInt();
|
||||
if (N > 0) {
|
||||
@@ -100,166 +115,139 @@ public final class ProcStatsEntry implements Parcelable {
|
||||
}
|
||||
|
||||
public void evaluateTargetPackage(PackageManager pm, ProcessStats stats,
|
||||
ProcessStats.ProcessDataCollection totals, Comparator<ProcStatsEntry> compare,
|
||||
boolean useUss, boolean weightWithTime) {
|
||||
ProcessStats.ProcessDataCollection bgTotals,
|
||||
ProcessStats.ProcessDataCollection runTotals, Comparator<ProcStatsEntry> compare,
|
||||
boolean useUss) {
|
||||
mBestTargetPackage = null;
|
||||
if (mPackages.size() == 1) {
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": single pkg " + mPackages.get(0));
|
||||
mBestTargetPackage = mPackages.get(0);
|
||||
} else {
|
||||
// See if there is one significant package that was running here.
|
||||
ArrayList<ProcStatsEntry> subProcs = new ArrayList<ProcStatsEntry>();
|
||||
for (int ipkg=0; ipkg<mPackages.size(); ipkg++) {
|
||||
SparseArray<ProcessStats.PackageState> vpkgs
|
||||
= stats.mPackages.get(mPackages.get(ipkg), mUid);
|
||||
for (int ivers=0; ivers<vpkgs.size(); ivers++) {
|
||||
ProcessStats.PackageState pkgState = vpkgs.valueAt(ivers);
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ", pkg "
|
||||
+ pkgState + ":");
|
||||
if (pkgState == null) {
|
||||
Log.w(TAG, "No package state found for " + mPackages.get(ipkg) + "/"
|
||||
+ mUid + " in process " + mName);
|
||||
continue;
|
||||
}
|
||||
ProcessStats.ProcessState pkgProc = pkgState.mProcesses.get(mName);
|
||||
if (pkgProc == null) {
|
||||
Log.w(TAG, "No process " + mName + " found in package state "
|
||||
+ mPackages.get(ipkg) + "/" + mUid);
|
||||
continue;
|
||||
}
|
||||
subProcs.add(new ProcStatsEntry(pkgProc, pkgState.mPackageName, totals, useUss,
|
||||
weightWithTime));
|
||||
}
|
||||
}
|
||||
if (subProcs.size() > 1) {
|
||||
Collections.sort(subProcs, compare);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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 one of the packages is the framework itself, that wins.
|
||||
// See if there is one significant package that was running here.
|
||||
for (int ipkg=0; ipkg<mPackages.size(); ipkg++) {
|
||||
if ("android".equals(mPackages.get(ipkg))) {
|
||||
mBestTargetPackage = mPackages.get(ipkg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
// Collect information about each package running in the process.
|
||||
ArrayList<ProcStatsEntry> subProcs = new ArrayList<>();
|
||||
for (int ipkg=0; ipkg<mPackages.size(); ipkg++) {
|
||||
SparseArray<ProcessStats.PackageState> vpkgs
|
||||
= stats.mPackages.get(mPackages.get(ipkg), mUid);
|
||||
for (int ivers=0; ivers<vpkgs.size(); ivers++) {
|
||||
ProcessStats.PackageState pkgState = vpkgs.valueAt(ivers);
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ", pkg "
|
||||
+ pkgState + ":");
|
||||
if (pkgState == null) {
|
||||
Log.w(TAG, "No package state found for " + mPackages.get(ipkg) + "/"
|
||||
+ mUid + " in process " + mName);
|
||||
continue;
|
||||
}
|
||||
ProcessStats.ProcessState pkgProc = pkgState.mProcesses.get(mName);
|
||||
if (pkgProc == null) {
|
||||
Log.w(TAG, "No process " + mName + " found in package state "
|
||||
+ mPackages.get(ipkg) + "/" + mUid);
|
||||
continue;
|
||||
}
|
||||
subProcs.add(new ProcStatsEntry(pkgProc, pkgState.mPackageName, bgTotals,
|
||||
runTotals, useUss));
|
||||
}
|
||||
}
|
||||
|
||||
if (subProcs.size() > 1) {
|
||||
Collections.sort(subProcs, compare);
|
||||
if (subProcs.get(0).mRunWeight > (subProcs.get(1).mRunWeight *3)) {
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": best pkg "
|
||||
+ subProcs.get(0).mPackage + " weight " + subProcs.get(0).mRunWeight
|
||||
+ " better than " + subProcs.get(1).mPackage
|
||||
+ " weight " + subProcs.get(1).mRunWeight);
|
||||
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.
|
||||
double maxWeight = subProcs.get(0).mRunWeight;
|
||||
long bestRunTime = -1;
|
||||
boolean bestPersistent = false;
|
||||
for (int i=0; i<subProcs.size(); i++) {
|
||||
final ProcStatsEntry subProc = subProcs.get(i);
|
||||
if (subProc.mRunWeight < (maxWeight/2)) {
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||
+ subProc.mPackage + " weight " + subProc.mRunWeight
|
||||
+ " too small");
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
ApplicationInfo ai = pm.getApplicationInfo(subProc.mPackage, 0);
|
||||
if (ai.icon == 0) {
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||
+ subProc.mPackage + " has no icon");
|
||||
continue;
|
||||
}
|
||||
if ((ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0) {
|
||||
long thisRunTime = subProc.mRunDuration;
|
||||
if (!bestPersistent || thisRunTime > bestRunTime) {
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||
+ subProc.mPackage + " new best pers run time "
|
||||
+ thisRunTime);
|
||||
bestRunTime = thisRunTime;
|
||||
bestPersistent = true;
|
||||
} else {
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||
+ subProc.mPackage + " pers run time " + thisRunTime
|
||||
+ " not as good as last " + bestRunTime);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
continue;
|
||||
} else if (bestPersistent) {
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||
+ subProc.mPackage + " is not persistent");
|
||||
continue;
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||
+ subProc.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(subProc.mPackage)) {
|
||||
subProcServices = subServices;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no current packages for this uid, typically because of uninstall
|
||||
Log.i(TAG, "No package for uid " + mUid);
|
||||
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 "
|
||||
+ subProc.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 "
|
||||
+ subProc.mPackage + " new best run time " + thisRunTime);
|
||||
mBestTargetPackage = subProc.mPackage;
|
||||
bestRunTime = thisRunTime;
|
||||
} else {
|
||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||
+ subProc.mPackage + " run time " + thisRunTime
|
||||
+ " not as good as last " + bestRunTime);
|
||||
}
|
||||
}
|
||||
} else if (subProcs.size() == 1) {
|
||||
mBestTargetPackage = subProcs.get(0).mPackage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,12 +271,14 @@ public final class ProcStatsEntry implements Parcelable {
|
||||
dest.writeInt(mUid);
|
||||
dest.writeString(mName);
|
||||
dest.writeStringList(mPackages);
|
||||
dest.writeLong(mDuration);
|
||||
dest.writeLong(mAvgPss);
|
||||
dest.writeLong(mMaxPss);
|
||||
dest.writeLong(mAvgUss);
|
||||
dest.writeLong(mMaxUss);
|
||||
dest.writeLong(mWeight);
|
||||
dest.writeLong(mBgDuration);
|
||||
dest.writeLong(mAvgBgMem);
|
||||
dest.writeLong(mMaxBgMem);
|
||||
dest.writeDouble(mBgWeight);
|
||||
dest.writeLong(mRunDuration);
|
||||
dest.writeLong(mAvgRunMem);
|
||||
dest.writeLong(mMaxRunMem);
|
||||
dest.writeDouble(mRunWeight);
|
||||
dest.writeString(mBestTargetPackage);
|
||||
final int N = mServices.size();
|
||||
dest.writeInt(N);
|
||||
|
145
src/com/android/settings/applications/ProcStatsPackageEntry.java
Normal file
145
src/com/android/settings/applications/ProcStatsPackageEntry.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ProcStatsPackageEntry implements Parcelable {
|
||||
private static final String TAG = "ProcStatsEntry";
|
||||
private static boolean DEBUG = ProcessStatsUi.DEBUG;
|
||||
|
||||
final String mPackage;
|
||||
final ArrayList<ProcStatsEntry> mEntries = new ArrayList<ProcStatsEntry>();
|
||||
|
||||
long mBgDuration;
|
||||
long mAvgBgMem;
|
||||
long mMaxBgMem;
|
||||
double mBgWeight;
|
||||
long mRunDuration;
|
||||
long mAvgRunMem;
|
||||
long mMaxRunMem;
|
||||
double mRunWeight;
|
||||
|
||||
public ApplicationInfo mUiTargetApp;
|
||||
public String mUiLabel;
|
||||
|
||||
public ProcStatsPackageEntry(String pkg) {
|
||||
mPackage = pkg;
|
||||
}
|
||||
|
||||
public ProcStatsPackageEntry(Parcel in) {
|
||||
mPackage = in.readString();
|
||||
in.readTypedList(mEntries, ProcStatsEntry.CREATOR);
|
||||
mBgDuration = in.readLong();
|
||||
mAvgBgMem = in.readLong();
|
||||
mMaxBgMem = in.readLong();
|
||||
mBgWeight = in.readDouble();
|
||||
mRunDuration = in.readLong();
|
||||
mAvgRunMem = in.readLong();
|
||||
mMaxRunMem = in.readLong();
|
||||
mRunWeight = in.readDouble();
|
||||
}
|
||||
|
||||
public void addEntry(ProcStatsEntry entry) {
|
||||
mEntries.add(entry);
|
||||
}
|
||||
|
||||
public void updateMetrics() {
|
||||
mBgDuration = mAvgBgMem = mMaxBgMem = 0;
|
||||
mBgWeight = 0;
|
||||
mRunDuration = mAvgRunMem = mMaxRunMem = 0;
|
||||
mRunWeight = 0;
|
||||
final int N = mEntries.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
ProcStatsEntry entry = mEntries.get(i);
|
||||
mBgDuration += entry.mBgDuration;
|
||||
mAvgBgMem += entry.mAvgBgMem;
|
||||
if (entry.mMaxBgMem > mMaxBgMem) {
|
||||
mMaxBgMem = entry.mMaxBgMem;
|
||||
}
|
||||
mBgWeight += entry.mBgWeight;
|
||||
mRunDuration += entry.mRunDuration;
|
||||
mAvgRunMem += entry.mAvgRunMem;
|
||||
if (entry.mMaxRunMem > mMaxRunMem) {
|
||||
mMaxRunMem = entry.mMaxRunMem;
|
||||
}
|
||||
mRunWeight += entry.mRunWeight;
|
||||
}
|
||||
mAvgBgMem /= N;
|
||||
mAvgRunMem /= N;
|
||||
}
|
||||
|
||||
public void retrieveUiData(Context context, PackageManager pm) {
|
||||
mUiTargetApp = null;
|
||||
mUiLabel = mPackage;
|
||||
// Only one app associated with this process.
|
||||
try {
|
||||
if ("os".equals(mPackage)) {
|
||||
mUiTargetApp = pm.getApplicationInfo("android",
|
||||
PackageManager.GET_DISABLED_COMPONENTS |
|
||||
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||
mUiLabel = context.getString(R.string.process_stats_os_label);
|
||||
} else {
|
||||
mUiTargetApp = pm.getApplicationInfo(mPackage,
|
||||
PackageManager.GET_DISABLED_COMPONENTS |
|
||||
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||
mUiLabel = mUiTargetApp.loadLabel(pm).toString();
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(mPackage);
|
||||
dest.writeTypedList(mEntries);
|
||||
dest.writeLong(mBgDuration);
|
||||
dest.writeLong(mAvgBgMem);
|
||||
dest.writeLong(mMaxBgMem);
|
||||
dest.writeDouble(mBgWeight);
|
||||
dest.writeLong(mRunDuration);
|
||||
dest.writeLong(mAvgRunMem);
|
||||
dest.writeLong(mMaxRunMem);
|
||||
dest.writeDouble(mRunWeight);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ProcStatsPackageEntry> CREATOR
|
||||
= new Parcelable.Creator<ProcStatsPackageEntry>() {
|
||||
public ProcStatsPackageEntry createFromParcel(Parcel in) {
|
||||
return new ProcStatsPackageEntry(in);
|
||||
}
|
||||
|
||||
public ProcStatsPackageEntry[] newArray(int size) {
|
||||
return new ProcStatsPackageEntry[size];
|
||||
}
|
||||
};
|
||||
}
|
@@ -16,20 +16,14 @@
|
||||
|
||||
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.os.UserHandle;
|
||||
import android.text.format.Formatter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -44,6 +38,7 @@ import com.android.settings.Utils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static com.android.settings.Utils.prepareCustomPreferencesList;
|
||||
|
||||
@@ -52,25 +47,28 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
||||
|
||||
public static final int ACTION_FORCE_STOP = 1;
|
||||
|
||||
public static final String EXTRA_ENTRY = "entry";
|
||||
public static final String EXTRA_PACKAGE_ENTRY = "package_entry";
|
||||
public static final String EXTRA_USE_USS = "use_uss";
|
||||
public static final String EXTRA_MAX_WEIGHT = "max_weight";
|
||||
public static final String EXTRA_WEIGHT_TO_RAM = "weight_to_ram";
|
||||
public static final String EXTRA_TOTAL_TIME = "total_time";
|
||||
|
||||
private PackageManager mPm;
|
||||
private DevicePolicyManager mDpm;
|
||||
|
||||
private ProcStatsEntry mEntry;
|
||||
private ProcStatsPackageEntry mApp;
|
||||
private boolean mUseUss;
|
||||
private long mMaxWeight;
|
||||
private double mMaxWeight;
|
||||
private double mWeightToRam;
|
||||
private long mTotalTime;
|
||||
private long mOnePercentTime;
|
||||
|
||||
private View mRootView;
|
||||
private TextView mTitleView;
|
||||
private ViewGroup mTwoButtonsPanel;
|
||||
private Button mForceStopButton;
|
||||
private Button mReportButton;
|
||||
private ViewGroup mDetailsParent;
|
||||
private ViewGroup mProcessesParent;
|
||||
private ViewGroup mServicesParent;
|
||||
|
||||
@Override
|
||||
@@ -79,11 +77,13 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
||||
mPm = getActivity().getPackageManager();
|
||||
mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
final Bundle args = getArguments();
|
||||
mEntry = (ProcStatsEntry)args.getParcelable(EXTRA_ENTRY);
|
||||
mEntry.retrieveUiData(mPm);
|
||||
mApp = args.getParcelable(EXTRA_PACKAGE_ENTRY);
|
||||
mApp.retrieveUiData(getActivity(), mPm);
|
||||
mUseUss = args.getBoolean(EXTRA_USE_USS);
|
||||
mMaxWeight = args.getLong(EXTRA_MAX_WEIGHT);
|
||||
mMaxWeight = args.getDouble(EXTRA_MAX_WEIGHT);
|
||||
mWeightToRam = args.getDouble(EXTRA_WEIGHT_TO_RAM);
|
||||
mTotalTime = args.getLong(EXTRA_TOTAL_TIME);
|
||||
mOnePercentTime = mTotalTime/100;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,24 +109,22 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
||||
}
|
||||
|
||||
private void createDetails() {
|
||||
final double percentOfWeight = (((double)mEntry.mWeight) / mMaxWeight) * 100;
|
||||
final double percentOfWeight = (mApp.mBgWeight / mMaxWeight) * 100;
|
||||
|
||||
int appLevel = (int) Math.ceil(percentOfWeight);
|
||||
String appLevelText = Utils.formatPercentage(mEntry.mDuration, mTotalTime);
|
||||
String appLevelText = Formatter.formatShortFileSize(getActivity(),
|
||||
(long)(mApp.mRunWeight * mWeightToRam));
|
||||
|
||||
// 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);
|
||||
mTitleView.setText(mApp.mUiLabel);
|
||||
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));
|
||||
if (mApp.mUiTargetApp != null) {
|
||||
icon.setImageDrawable(mApp.mUiTargetApp.loadIcon(mPm));
|
||||
}
|
||||
|
||||
mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel);
|
||||
@@ -135,13 +133,17 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
||||
mForceStopButton.setEnabled(false);
|
||||
mReportButton.setVisibility(View.INVISIBLE);
|
||||
|
||||
mDetailsParent = (ViewGroup)mRootView.findViewById(R.id.details);
|
||||
mProcessesParent = (ViewGroup)mRootView.findViewById(R.id.processes);
|
||||
mServicesParent = (ViewGroup)mRootView.findViewById(R.id.services);
|
||||
|
||||
fillDetailsSection();
|
||||
fillProcessesSection();
|
||||
fillServicesSection();
|
||||
if (mServicesParent.getChildCount() <= 0) {
|
||||
mServicesParent.setVisibility(View.GONE);
|
||||
mRootView.findViewById(R.id.services_label).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (mEntry.mUid >= android.os.Process.FIRST_APPLICATION_UID) {
|
||||
if (mApp.mEntries.get(0).mUid >= android.os.Process.FIRST_APPLICATION_UID) {
|
||||
mForceStopButton.setText(R.string.force_stop);
|
||||
mForceStopButton.setTag(ACTION_FORCE_STOP);
|
||||
mForceStopButton.setOnClickListener(this);
|
||||
@@ -191,15 +193,43 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
||||
valueView.setText(value);
|
||||
}
|
||||
|
||||
private void fillDetailsSection() {
|
||||
addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_avg_ram_use),
|
||||
Formatter.formatShortFileSize(getActivity(),
|
||||
(mUseUss ? mEntry.mAvgUss : mEntry.mAvgPss) * 1024));
|
||||
addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_max_ram_use),
|
||||
Formatter.formatShortFileSize(getActivity(),
|
||||
(mUseUss ? mEntry.mMaxUss : mEntry.mMaxPss) * 1024));
|
||||
addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_run_time),
|
||||
Utils.formatPercentage(mEntry.mDuration, mTotalTime));
|
||||
final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
|
||||
@Override
|
||||
public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
|
||||
if (lhs.mRunWeight < rhs.mRunWeight) {
|
||||
return 1;
|
||||
} else if (lhs.mRunWeight > rhs.mRunWeight) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
private void fillProcessesSection() {
|
||||
final ArrayList<ProcStatsEntry> entries = new ArrayList<>();
|
||||
for (int ie=0; ie<mApp.mEntries.size(); ie++) {
|
||||
ProcStatsEntry entry = mApp.mEntries.get(ie);
|
||||
entries.add(entry);
|
||||
}
|
||||
Collections.sort(entries, sEntryCompare);
|
||||
for (int ie=0; ie<entries.size(); ie++) {
|
||||
ProcStatsEntry entry = entries.get(ie);
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.process_stats_proc_details,
|
||||
null);
|
||||
mProcessesParent.addView(item);
|
||||
((TextView)item.findViewById(R.id.processes_name)).setText(entry.mName);
|
||||
addDetailsItem(item, getResources().getText(R.string.process_stats_ram_use),
|
||||
Formatter.formatShortFileSize(getActivity(),
|
||||
(long)(entry.mRunWeight * mWeightToRam)));
|
||||
if (entry.mBgWeight > 0) {
|
||||
addDetailsItem(item, getResources().getText(R.string.process_stats_bg_ram_use),
|
||||
Formatter.formatShortFileSize(getActivity(),
|
||||
(long)(entry.mBgWeight * mWeightToRam)));
|
||||
}
|
||||
addDetailsItem(item, getResources().getText(R.string.process_stats_run_time),
|
||||
Utils.formatPercentage(entry.mRunDuration, mTotalTime));
|
||||
}
|
||||
}
|
||||
|
||||
final static Comparator<ProcStatsEntry.Service> sServiceCompare
|
||||
@@ -215,95 +245,106 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
||||
}
|
||||
};
|
||||
|
||||
final static Comparator<ArrayList<ProcStatsEntry.Service>> sServicePkgCompare
|
||||
= new Comparator<ArrayList<ProcStatsEntry.Service>>() {
|
||||
final static Comparator<PkgService> sServicePkgCompare = new Comparator<PkgService>() {
|
||||
@Override
|
||||
public int compare(ArrayList<ProcStatsEntry.Service> lhs,
|
||||
ArrayList<ProcStatsEntry.Service> rhs) {
|
||||
long topLhs = lhs.size() > 0 ? lhs.get(0).mDuration : 0;
|
||||
long topRhs = rhs.size() > 0 ? rhs.get(0).mDuration : 0;
|
||||
if (topLhs < topRhs) {
|
||||
public int compare(PkgService lhs, PkgService rhs) {
|
||||
if (lhs.mDuration < rhs.mDuration) {
|
||||
return 1;
|
||||
} else if (topLhs > topRhs) {
|
||||
} else if (lhs.mDuration > rhs.mDuration) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
static class PkgService {
|
||||
final ArrayList<ProcStatsEntry.Service> mServices = new ArrayList<>();
|
||||
long mDuration;
|
||||
}
|
||||
|
||||
private void fillServicesSection() {
|
||||
if (mEntry.mServices.size() > 0) {
|
||||
boolean addPackageSections = false;
|
||||
// Sort it all.
|
||||
ArrayList<ArrayList<ProcStatsEntry.Service>> servicePkgs
|
||||
= new ArrayList<ArrayList<ProcStatsEntry.Service>>();
|
||||
for (int ip=0; ip<mEntry.mServices.size(); ip++) {
|
||||
ArrayList<ProcStatsEntry.Service> services =
|
||||
(ArrayList<ProcStatsEntry.Service>)mEntry.mServices.valueAt(ip).clone();
|
||||
Collections.sort(services, sServiceCompare);
|
||||
servicePkgs.add(services);
|
||||
}
|
||||
if (mEntry.mServices.size() > 1
|
||||
|| !mEntry.mServices.valueAt(0).get(0).mPackage.equals(mEntry.mPackage)) {
|
||||
addPackageSections = true;
|
||||
// Sort these so that the one(s) with the longest run durations are on top.
|
||||
Collections.sort(servicePkgs, sServicePkgCompare);
|
||||
}
|
||||
for (int ip=0; ip<servicePkgs.size(); ip++) {
|
||||
ArrayList<ProcStatsEntry.Service> services = servicePkgs.get(ip);
|
||||
if (addPackageSections) {
|
||||
addPackageHeaderItem(mServicesParent, services.get(0).mPackage);
|
||||
}
|
||||
for (int is=0; is<services.size(); is++) {
|
||||
ProcStatsEntry.Service service = services.get(is);
|
||||
String label = service.mName;
|
||||
int tail = label.lastIndexOf('.');
|
||||
if (tail >= 0 && tail < (label.length()-1)) {
|
||||
label = label.substring(tail+1);
|
||||
final HashMap<String, PkgService> pkgServices = new HashMap<>();
|
||||
final ArrayList<PkgService> pkgList = new ArrayList<>();
|
||||
for (int ie=0; ie< mApp.mEntries.size(); ie++) {
|
||||
ProcStatsEntry ent = mApp.mEntries.get(ie);
|
||||
for (int ip=0; ip<ent.mServices.size(); ip++) {
|
||||
String pkg = ent.mServices.keyAt(ip);
|
||||
PkgService psvc = null;
|
||||
ArrayList<ProcStatsEntry.Service> services = ent.mServices.valueAt(ip);
|
||||
for (int is=services.size()-1; is>=0; is--) {
|
||||
ProcStatsEntry.Service pent = services.get(is);
|
||||
if (pent.mDuration >= mOnePercentTime) {
|
||||
if (psvc == null) {
|
||||
psvc = pkgServices.get(pkg);
|
||||
if (psvc == null) {
|
||||
psvc = new PkgService();
|
||||
pkgServices.put(pkg, psvc);
|
||||
pkgList.add(psvc);
|
||||
}
|
||||
}
|
||||
psvc.mServices.add(pent);
|
||||
psvc.mDuration += pent.mDuration;
|
||||
}
|
||||
String percentage = Utils.formatPercentage(service.mDuration, mTotalTime);
|
||||
addDetailsItem(mServicesParent, label, percentage);
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(pkgList, sServicePkgCompare);
|
||||
for (int ip=0; ip<pkgList.size(); ip++) {
|
||||
ArrayList<ProcStatsEntry.Service> services = pkgList.get(ip).mServices;
|
||||
Collections.sort(services, sServiceCompare);
|
||||
if (pkgList.size() > 1) {
|
||||
addPackageHeaderItem(mServicesParent, services.get(0).mPackage);
|
||||
}
|
||||
for (int is=0; is<services.size(); is++) {
|
||||
ProcStatsEntry.Service service = services.get(is);
|
||||
String label = service.mName;
|
||||
int tail = label.lastIndexOf('.');
|
||||
if (tail >= 0 && tail < (label.length()-1)) {
|
||||
label = label.substring(tail+1);
|
||||
}
|
||||
String percentage = Utils.formatPercentage(service.mDuration, mTotalTime);
|
||||
addDetailsItem(mServicesParent, label, percentage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void killProcesses() {
|
||||
ActivityManager am = (ActivityManager)getActivity().getSystemService(
|
||||
Context.ACTIVITY_SERVICE);
|
||||
am.forceStopPackage(mEntry.mUiPackage);
|
||||
for (int i=0; i< mApp.mEntries.size(); i++) {
|
||||
ProcStatsEntry ent = mApp.mEntries.get(i);
|
||||
for (int j=0; j<ent.mPackages.size(); j++) {
|
||||
am.forceStopPackage(ent.mPackages.get(j));
|
||||
}
|
||||
}
|
||||
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) {
|
||||
if (mApp.mEntries.get(0).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);
|
||||
boolean isStarted = false;
|
||||
for (int i=0; i< mApp.mEntries.size(); i++) {
|
||||
ProcStatsEntry ent = mApp.mEntries.get(i);
|
||||
for (int j=0; j<ent.mPackages.size(); j++) {
|
||||
String pkg = ent.mPackages.get(j);
|
||||
if (mDpm.packageHasActiveAdmins(pkg)) {
|
||||
mForceStopButton.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ApplicationInfo info = mPm.getApplicationInfo(pkg, 0);
|
||||
if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
|
||||
isStarted = true;
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
}
|
||||
}
|
||||
} 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, UserHandle.getUserId(mEntry.mUid));
|
||||
getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
|
||||
Activity.RESULT_CANCELED, null, null);
|
||||
if (isStarted) {
|
||||
mForceStopButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
|
||||
public class ProcessStatsPreference extends Preference {
|
||||
private ProcStatsEntry mEntry;
|
||||
private ProcStatsPackageEntry mEntry;
|
||||
private int mProgress;
|
||||
private CharSequence mProgressText;
|
||||
|
||||
@@ -51,18 +51,19 @@ public class ProcessStatsPreference extends Preference {
|
||||
setLayoutResource(R.layout.preference_app_percentage);
|
||||
}
|
||||
|
||||
public void init(Drawable icon, ProcStatsEntry entry) {
|
||||
public void init(Drawable icon, ProcStatsPackageEntry entry) {
|
||||
mEntry = entry;
|
||||
setIcon(icon != null ? icon : new ColorDrawable(0));
|
||||
}
|
||||
|
||||
public ProcStatsEntry getEntry() {
|
||||
public ProcStatsPackageEntry getEntry() {
|
||||
return mEntry;
|
||||
}
|
||||
|
||||
public void setPercent(double percentOfWeight, double percentOfTime) {
|
||||
public void setPercent(double percentOfWeight, double percentOfTime, long memory) {
|
||||
mProgress = (int) Math.ceil(percentOfWeight);
|
||||
mProgressText = Utils.formatPercentage((int) percentOfTime);
|
||||
//mProgressText = Utils.formatPercentage((int) percentOfTime);
|
||||
mProgressText = Formatter.formatShortFileSize(getContext(), memory);
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,7 @@ package com.android.settings.applications;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
@@ -50,6 +51,7 @@ import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ProcessStatsUi extends PreferenceFragment
|
||||
implements LinearColorBar.OnRegionTappedListener {
|
||||
@@ -75,13 +77,30 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
|
||||
@Override
|
||||
public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
|
||||
if (lhs.mWeight < rhs.mWeight) {
|
||||
if (lhs.mRunWeight < rhs.mRunWeight) {
|
||||
return 1;
|
||||
} else if (lhs.mWeight > rhs.mWeight) {
|
||||
} else if (lhs.mRunWeight > rhs.mRunWeight) {
|
||||
return -1;
|
||||
} else if (lhs.mDuration < rhs.mDuration) {
|
||||
} else if (lhs.mRunDuration < rhs.mRunDuration) {
|
||||
return 1;
|
||||
} else if (lhs.mDuration > rhs.mDuration) {
|
||||
} else if (lhs.mRunDuration > rhs.mRunDuration) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
final static Comparator<ProcStatsPackageEntry> sPackageEntryCompare
|
||||
= new Comparator<ProcStatsPackageEntry>() {
|
||||
@Override
|
||||
public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) {
|
||||
if (lhs.mRunWeight < rhs.mRunWeight) {
|
||||
return 1;
|
||||
} else if (lhs.mRunWeight > rhs.mRunWeight) {
|
||||
return -1;
|
||||
} else if (lhs.mRunDuration < rhs.mRunDuration) {
|
||||
return 1;
|
||||
} else if (lhs.mRunDuration > rhs.mRunDuration) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -112,7 +131,7 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
private PreferenceGroup mAppListGroup;
|
||||
private Preference mMemStatusPref;
|
||||
|
||||
long mMaxWeight;
|
||||
double mMaxWeight;
|
||||
long mTotalTime;
|
||||
|
||||
long[] mMemTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT];
|
||||
@@ -123,6 +142,7 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
double mMemKernelWeight;
|
||||
double mMemNativeWeight;
|
||||
double mMemTotalWeight;
|
||||
double mWeightToRam;
|
||||
|
||||
// The actual duration value to use for each duration option. Note these
|
||||
// are lower than the actual duration, since our durations are computed in
|
||||
@@ -218,9 +238,10 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
|
||||
ProcessStatsPreference pgp = (ProcessStatsPreference) preference;
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(ProcessStatsDetail.EXTRA_ENTRY, pgp.getEntry());
|
||||
args.putParcelable(ProcessStatsDetail.EXTRA_PACKAGE_ENTRY, pgp.getEntry());
|
||||
args.putBoolean(ProcessStatsDetail.EXTRA_USE_USS, mUseUss);
|
||||
args.putLong(ProcessStatsDetail.EXTRA_MAX_WEIGHT, mMaxWeight);
|
||||
args.putDouble(ProcessStatsDetail.EXTRA_MAX_WEIGHT, mMaxWeight);
|
||||
args.putDouble(ProcessStatsDetail.EXTRA_WEIGHT_TO_RAM, mWeightToRam);
|
||||
args.putLong(ProcessStatsDetail.EXTRA_TOTAL_TIME, mTotalTime);
|
||||
((SettingsActivity) getActivity()).startPreferencePanel(
|
||||
ProcessStatsDetail.class.getName(), args, R.string.details_title, null, null, 0);
|
||||
@@ -406,31 +427,6 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
|
||||
final long elapsedTime = mStats.mTimePeriodEndRealtime-mStats.mTimePeriodStartRealtime;
|
||||
|
||||
mMemStatusPref.setOrder(-2);
|
||||
mAppListGroup.addPreference(mMemStatusPref);
|
||||
String durationString = Utils.formatElapsedTime(getActivity(), elapsedTime, false);
|
||||
CharSequence memString;
|
||||
CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states);
|
||||
if (mMemState >= 0 && mMemState < memStatesStr.length) {
|
||||
memString = memStatesStr[mMemState];
|
||||
} else {
|
||||
memString = "?";
|
||||
}
|
||||
mMemStatusPref.setTitle(getActivity().getString(R.string.process_stats_total_duration,
|
||||
getActivity().getString(statsLabel), durationString));
|
||||
mMemStatusPref.setSummary(getActivity().getString(R.string.process_stats_memory_status,
|
||||
memString));
|
||||
/*
|
||||
mMemStatusPref.setTitle(DateFormat.format(DateFormat.getBestDateTimePattern(
|
||||
getActivity().getResources().getConfiguration().locale,
|
||||
"MMMM dd, yyyy h:mm a"), mStats.mTimePeriodStartClock));
|
||||
*/
|
||||
/*
|
||||
BatteryHistoryPreference hist = new BatteryHistoryPreference(getActivity(), mStats);
|
||||
hist.setOrder(-1);
|
||||
mAppListGroup.addPreference(hist);
|
||||
*/
|
||||
|
||||
long now = SystemClock.uptimeMillis();
|
||||
|
||||
final PackageManager pm = getActivity().getPackageManager();
|
||||
@@ -470,9 +466,13 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
memStates = ProcessStats.ALL_MEM_ADJ;
|
||||
break;
|
||||
}
|
||||
colors.setColoredRegions(LinearColorBar.REGION_RED);
|
||||
Resources res = getResources();
|
||||
colors.setColors(res.getColor(R.color.running_processes_apps_ram),
|
||||
res.getColor(R.color.running_processes_apps_ram),
|
||||
res.getColor(R.color.running_processes_free_ram));
|
||||
|
||||
// Compute memory badness for chart color.
|
||||
/*
|
||||
int[] badColors = com.android.settings.Utils.BADNESS_COLORS;
|
||||
long timeGood = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL];
|
||||
timeGood += (mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]*2)/3;
|
||||
@@ -480,6 +480,7 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
float memBadness = ((float)timeGood)/mTotalTime;
|
||||
int badnessColor = badColors[1 + Math.round(memBadness*(badColors.length-2))];
|
||||
colors.setColors(badnessColor, badnessColor, badnessColor);
|
||||
*/
|
||||
|
||||
// We are now going to scale the mMemTimes to match the total elapsed time.
|
||||
// These are in uptime, so they will often be smaller than the elapsed time,
|
||||
@@ -547,6 +548,8 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
memReader.readMemInfo();
|
||||
double realTotalRam = memReader.getTotalSize();
|
||||
double totalScale = realTotalRam / totalRam;
|
||||
mWeightToRam = totalScale / memTotalTime * 1024;
|
||||
mMaxWeight = totalRam / mWeightToRam;
|
||||
double realUsedRam = usedRam * totalScale;
|
||||
double realFreeRam = freeRam * totalScale;
|
||||
if (DEBUG) {
|
||||
@@ -558,12 +561,15 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
|
||||
((ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(
|
||||
memInfo);
|
||||
long baseCacheRam;
|
||||
if (memInfo.hiddenAppThreshold >= realFreeRam) {
|
||||
realUsedRam = realFreeRam;
|
||||
realFreeRam = 0;
|
||||
baseCacheRam = (long)realFreeRam;
|
||||
} else {
|
||||
realUsedRam += memInfo.hiddenAppThreshold;
|
||||
realFreeRam -= memInfo.hiddenAppThreshold;
|
||||
baseCacheRam = memInfo.hiddenAppThreshold;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "Adj Scaled Used RAM: " + Formatter.formatShortFileSize(getActivity(),
|
||||
@@ -572,6 +578,22 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
(long)realFreeRam));
|
||||
}
|
||||
|
||||
mMemStatusPref.setOrder(-2);
|
||||
mAppListGroup.addPreference(mMemStatusPref);
|
||||
String durationString = Utils.formatElapsedTime(getActivity(), elapsedTime, false);
|
||||
String usedString = Formatter.formatShortFileSize(getActivity(), (long) realUsedRam);
|
||||
String totalString = Formatter.formatShortFileSize(getActivity(), (long)realTotalRam);
|
||||
CharSequence memString;
|
||||
CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states);
|
||||
if (mMemState >= 0 && mMemState < memStatesStr.length) {
|
||||
memString = memStatesStr[mMemState];
|
||||
} else {
|
||||
memString = "?";
|
||||
}
|
||||
mMemStatusPref.setTitle(getActivity().getString(R.string.process_stats_total_duration,
|
||||
usedString, totalString, durationString));
|
||||
mMemStatusPref.setSummary(getActivity().getString(R.string.process_stats_memory_status,
|
||||
memString));
|
||||
float usedRatio = (float)(realUsedRam/(realFreeRam+realUsedRam));
|
||||
colors.setRatios(usedRatio, 0, 1-usedRatio);
|
||||
|
||||
@@ -605,17 +627,20 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
|
||||
mAppListGroup.addPreference(colors);
|
||||
|
||||
ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
|
||||
ProcessStats.ProcessDataCollection bgTotals = new ProcessStats.ProcessDataCollection(
|
||||
ProcessStats.ALL_SCREEN_ADJ, memStates, stats);
|
||||
ProcessStats.ProcessDataCollection runTotals = new ProcessStats.ProcessDataCollection(
|
||||
ProcessStats.ALL_SCREEN_ADJ, memStates, ProcessStats.NON_CACHED_PROC_STATES);
|
||||
|
||||
ArrayList<ProcStatsEntry> entries = new ArrayList<ProcStatsEntry>();
|
||||
final ArrayList<ProcStatsEntry> procEntries = new ArrayList<>();
|
||||
final ArrayList<ProcStatsPackageEntry> pkgEntries = new ArrayList<>();
|
||||
|
||||
/*
|
||||
ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked(
|
||||
ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ,
|
||||
ProcessStats.BACKGROUND_PROC_STATES, now, null);
|
||||
for (int i=0, N=(rawProcs != null ? rawProcs.size() : 0); i<N; i++) {
|
||||
procs.add(new ProcStatsEntry(rawProcs.get(i), totals));
|
||||
procs.add(new ProcStatsEntry(rawProcs.get(i), bgTotals));
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -640,15 +665,15 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
}
|
||||
ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid);
|
||||
if (ent == null) {
|
||||
ent = new ProcStatsEntry(proc, st.mPackageName, totals, mUseUss,
|
||||
mStatsType == MENU_TYPE_BACKGROUND);
|
||||
if (ent.mDuration > 0) {
|
||||
ent = new ProcStatsEntry(proc, st.mPackageName, bgTotals, runTotals,
|
||||
mUseUss);
|
||||
if (ent.mRunWeight > 0) {
|
||||
if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
|
||||
+ proc.mUid + ": time=" + makeDuration(ent.mDuration) + " ("
|
||||
+ ((((double)ent.mDuration) / memTotalTime) * 100) + "%)"
|
||||
+ " pss=" + ent.mAvgPss);
|
||||
+ proc.mUid + ": time=" + makeDuration(ent.mRunDuration) + " ("
|
||||
+ ((((double)ent.mRunDuration) / memTotalTime) * 100) + "%)"
|
||||
+ " pss=" + ent.mAvgRunMem);
|
||||
entriesMap.put(proc.mName, proc.mUid, ent);
|
||||
entries.add(ent);
|
||||
procEntries.add(ent);
|
||||
}
|
||||
} else {
|
||||
ent.addPackage(st.mPackageName);
|
||||
@@ -672,7 +697,8 @@ public class ProcessStatsUi extends PreferenceFragment
|
||||
for (int is=0, NS=ps.mServices.size(); is<NS; is++) {
|
||||
ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
|
||||
if (ss.mProcessName != null) {
|
||||
ProcStatsEntry ent = entriesMap.get(ss.mProcessName, uids.keyAt(iu));
|
||||
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 "
|
||||
@@ -689,90 +715,99 @@ 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) / memTotalTime) * 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);
|
||||
}
|
||||
// Combine processes into packages.
|
||||
HashMap<String, ProcStatsPackageEntry> pkgMap = new HashMap<>();
|
||||
for (int i=procEntries.size()-1; i>=0; i--) {
|
||||
ProcStatsEntry proc = procEntries.get(i);
|
||||
proc.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
|
||||
ProcStatsPackageEntry pkg = pkgMap.get(proc.mBestTargetPackage);
|
||||
if (pkg == null) {
|
||||
pkg = new ProcStatsPackageEntry(proc.mBestTargetPackage);
|
||||
pkgMap.put(proc.mBestTargetPackage, pkg);
|
||||
pkgEntries.add(pkg);
|
||||
}
|
||||
pkg.addEntry(proc);
|
||||
}
|
||||
*/
|
||||
|
||||
Collections.sort(entries, sEntryCompare);
|
||||
// Add in fake entry representing the OS itself.
|
||||
ProcStatsPackageEntry osPkg = new ProcStatsPackageEntry("os");
|
||||
pkgMap.put("os", osPkg);
|
||||
pkgEntries.add(osPkg);
|
||||
ProcStatsEntry osEntry;
|
||||
if (totalMem.sysMemNativeWeight > 0) {
|
||||
osEntry = new ProcStatsEntry("os", 0,
|
||||
getString(R.string.process_stats_os_native), memTotalTime,
|
||||
(long)(totalMem.sysMemNativeWeight/memTotalTime));
|
||||
osEntry.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
|
||||
osPkg.addEntry(osEntry);
|
||||
}
|
||||
if (totalMem.sysMemKernelWeight > 0) {
|
||||
osEntry = new ProcStatsEntry("os", 0,
|
||||
getString(R.string.process_stats_os_kernel), memTotalTime,
|
||||
(long)(totalMem.sysMemKernelWeight/memTotalTime));
|
||||
osEntry.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
|
||||
osPkg.addEntry(osEntry);
|
||||
}
|
||||
if (totalMem.sysMemZRamWeight > 0) {
|
||||
osEntry = new ProcStatsEntry("os", 0,
|
||||
getString(R.string.process_stats_os_zram), memTotalTime,
|
||||
(long)(totalMem.sysMemZRamWeight/memTotalTime));
|
||||
osEntry.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
|
||||
osPkg.addEntry(osEntry);
|
||||
}
|
||||
if (baseCacheRam > 0) {
|
||||
osEntry = new ProcStatsEntry("os", 0,
|
||||
getString(R.string.process_stats_os_cache), memTotalTime, baseCacheRam/1024);
|
||||
osEntry.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
|
||||
osPkg.addEntry(osEntry);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (mStatsType == MENU_TYPE_BACKGROUND) {
|
||||
mMaxWeight = (long)(mShowSystem ? persBackgroundWeight : backgroundWeight);
|
||||
if (mMaxWeight < maxWeight) {
|
||||
mMaxWeight = maxWeight;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "Bar max RAM: " + Formatter.formatShortFileSize(getActivity(),
|
||||
(mMaxWeight * 1024) / memTotalTime));
|
||||
}
|
||||
} else {
|
||||
mMaxWeight = maxWeight;
|
||||
for (int i=0, N=pkgEntries.size(); i<N; i++) {
|
||||
ProcStatsPackageEntry pkg = pkgEntries.get(i);
|
||||
pkg.updateMetrics();
|
||||
}
|
||||
|
||||
Collections.sort(pkgEntries, sPackageEntryCompare);
|
||||
|
||||
// Now collect the per-process information into applications, so that applications
|
||||
// running as multiple processes will have only one entry representing all of them.
|
||||
|
||||
if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI");
|
||||
|
||||
// Find where we should stop. Because we have two properties we are looking at,
|
||||
// we need to go from the back looking for the first place either holds.
|
||||
int end = entries != null ? entries.size()-1 : -1;
|
||||
int end = pkgEntries.size()-1;
|
||||
while (end >= 0) {
|
||||
ProcStatsEntry proc = entries.get(end);
|
||||
final double percentOfWeight = (((double)proc.mWeight) / mMaxWeight) * 100;
|
||||
final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100;
|
||||
if (percentOfWeight >= 1 || percentOfTime >= 25) {
|
||||
ProcStatsPackageEntry pkg = pkgEntries.get(end);
|
||||
final double percentOfWeight = (pkg.mRunWeight / mMaxWeight) * 100;
|
||||
final double percentOfTime = (((double)pkg.mRunDuration) / memTotalTime) * 100;
|
||||
if (percentOfWeight >= .01 || percentOfTime >= 25) {
|
||||
break;
|
||||
}
|
||||
end--;
|
||||
}
|
||||
for (int i=0; i<=end; i++) {
|
||||
ProcStatsEntry proc = entries.get(i);
|
||||
final double percentOfWeight = (((double)proc.mWeight) / mMaxWeight) * 100;
|
||||
final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100;
|
||||
ProcStatsPackageEntry pkg = pkgEntries.get(i);
|
||||
final double percentOfWeight = (pkg.mRunWeight / mMaxWeight) * 100;
|
||||
final double percentOfTime = (((double)pkg.mRunDuration) / memTotalTime) * 100;
|
||||
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity());
|
||||
pref.init(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.init(null, pkg);
|
||||
pkg.retrieveUiData(getActivity(), pm);
|
||||
pref.setTitle(pkg.mUiLabel);
|
||||
if (pkg.mUiTargetApp != null) {
|
||||
pref.setIcon(pkg.mUiTargetApp.loadIcon(pm));
|
||||
}
|
||||
pref.setOrder(i);
|
||||
pref.setPercent(percentOfWeight, percentOfTime);
|
||||
pref.setPercent(percentOfWeight, percentOfTime,
|
||||
(long)(pkg.mRunWeight * mWeightToRam));
|
||||
mAppListGroup.addPreference(pref);
|
||||
if (mStatsType == MENU_TYPE_BACKGROUND) {
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "App " + proc.mUiLabel + ": weightedRam="
|
||||
Log.i(TAG, "App " + pkg.mUiLabel + ": weightedRam="
|
||||
+ Formatter.formatShortFileSize(getActivity(),
|
||||
(proc.mWeight * 1024) / memTotalTime)
|
||||
(long)((pkg.mRunWeight * 1024) / memTotalTime))
|
||||
+ ", avgRam=" + Formatter.formatShortFileSize(getActivity(),
|
||||
(proc.mAvgPss*1024)));
|
||||
(pkg.mAvgRunMem *1024)));
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user