Merge "Make proc stats UI app-centric instead of process-centric."

This commit is contained in:
Dianne Hackborn
2015-02-03 17:43:54 +00:00
committed by Android (Google) Code Review
8 changed files with 647 additions and 397 deletions

View File

@@ -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);

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

View File

@@ -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);
}
}
}

View File

@@ -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();
}

View File

@@ -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)));
}
}