From b94079a704ef9ca144ca94885d655b2befabcf45 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 30 Jan 2015 18:19:38 -0800 Subject: Make proc stats UI app-centric instead of process-centric. The UI now shows a much simpler overview of memory use for the current measured duration, computing the weighted RAM user per application. (This is done basically by rolling up each individual process into an app that can contain multiple processes, and using the recently introduced weighted RAM for all data processing.) The details screen is updated to reflect this new design, showing an overview of a particular application, which separate entries for each process running for that app. Change-Id: I47d79c30086d733eb37440a6c21b18a92b767d01 --- .../settings/applications/ProcStatsEntry.java | 330 ++++++++++----------- .../applications/ProcStatsPackageEntry.java | 145 +++++++++ .../settings/applications/ProcessStatsDetail.java | 231 +++++++++------ .../applications/ProcessStatsPreference.java | 11 +- .../settings/applications/ProcessStatsUi.java | 243 ++++++++------- 5 files changed, 586 insertions(+), 374 deletions(-) create mode 100644 src/com/android/settings/applications/ProcStatsPackageEntry.java (limited to 'src/com') diff --git a/src/com/android/settings/applications/ProcStatsEntry.java b/src/com/android/settings/applications/ProcStatsEntry.java index 8702478..6cb6997 100644 --- a/src/com/android/settings/applications/ProcStatsEntry.java +++ b/src/com/android/settings/applications/ProcStatsEntry.java @@ -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 mPackages = new ArrayList(); - 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> mServices = new ArrayMap>(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 compare, - boolean useUss, boolean weightWithTime) { + ProcessStats.ProcessDataCollection bgTotals, + ProcessStats.ProcessDataCollection runTotals, Comparator 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 subProcs = new ArrayList(); - for (int ipkg=0; ipkg vpkgs - = stats.mPackages.get(mPackages.get(ipkg), mUid); - for (int ivers=0; ivers subProcs = new ArrayList<>(); + for (int ipkg=0; ipkg vpkgs + = stats.mPackages.get(mPackages.get(ipkg), mUid); + for (int ivers=0; ivers 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; } - 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. + double maxWeight = subProcs.get(0).mRunWeight; + long bestRunTime = -1; + boolean bestPersistent = false; + for (int i=0; i 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 " - + subProcs.get(i).mPackage + " has no icon"); - continue; + + subProc.mPackage + " pers run time " + thisRunTime + + " not as good as last " + bestRunTime); } - } catch (PackageManager.NameNotFoundException e) { - if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg " - + subProcs.get(i).mPackage + " failed finding app info"); continue; - } - ArrayList subProcServices = null; - for (int isp=0, NSP=mServices.size(); isp 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 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) { + } else if (bestPersistent) { 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); + + 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; } - } else if (subProcs.size() == 1) { - mBestTargetPackage = subProcs.get(0).mPackage; - } - } - } - - public void retrieveUiData(PackageManager pm) { - mUiTargetApp = null; - mUiLabel = mUiBaseLabel = mName; - mUiPackage = mBestTargetPackage; - if (mUiPackage != null) { - // Only one app associated with this process. - try { - mUiTargetApp = pm.getApplicationInfo(mUiPackage, - PackageManager.GET_DISABLED_COMPONENTS | - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | - PackageManager.GET_UNINSTALLED_PACKAGES); - String name = mUiBaseLabel = mUiTargetApp.loadLabel(pm).toString(); - if (mName.equals(mUiPackage)) { - mUiLabel = name; - } else { - if (mName.startsWith(mUiPackage)) { - int off = mUiPackage.length(); - if (mName.length() > off) { - off++; - } - mUiLabel = name + " (" + mName.substring(off) + ")"; - } else { - mUiLabel = name + " (" + mName + ")"; + ArrayList subProcServices = null; + for (int isp=0, NSP=mServices.size(); isp subServices = mServices.valueAt(isp); + if (subServices.get(0).mPackage.equals(subProc.mPackage)) { + subProcServices = subServices; + break; } } - } catch (PackageManager.NameNotFoundException e) { - } - } - if (mUiTargetApp == null) { - String[] packages = pm.getPackagesForUid(mUid); - if (packages != null) { - for (String curPkg : packages) { - try { - final PackageInfo pi = pm.getPackageInfo(curPkg, - PackageManager.GET_DISABLED_COMPONENTS | - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | - PackageManager.GET_UNINSTALLED_PACKAGES); - if (pi.sharedUserLabel != 0) { - mUiTargetApp = pi.applicationInfo; - final CharSequence nm = pm.getText(curPkg, - pi.sharedUserLabel, pi.applicationInfo); - if (nm != null) { - mUiBaseLabel = nm.toString(); - mUiLabel = mUiBaseLabel + " (" + mName + ")"; - } else { - mUiBaseLabel = mUiTargetApp.loadLabel(pm).toString(); - mUiLabel = mUiBaseLabel + " (" + mName + ")"; - } + long thisRunTime = 0; + if (subProcServices != null) { + for (int iss=0, NSS=subProcServices.size(); iss 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; } - } catch (PackageManager.NameNotFoundException e) { } } - } else { - // no current packages for this uid, typically because of uninstall - Log.i(TAG, "No package for uid " + mUid); + 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); diff --git a/src/com/android/settings/applications/ProcStatsPackageEntry.java b/src/com/android/settings/applications/ProcStatsPackageEntry.java new file mode 100644 index 0000000..3925d1d --- /dev/null +++ b/src/com/android/settings/applications/ProcStatsPackageEntry.java @@ -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 mEntries = new ArrayList(); + + 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 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 CREATOR + = new Parcelable.Creator() { + public ProcStatsPackageEntry createFromParcel(Parcel in) { + return new ProcStatsPackageEntry(in); + } + + public ProcStatsPackageEntry[] newArray(int size) { + return new ProcStatsPackageEntry[size]; + } + }; +} diff --git a/src/com/android/settings/applications/ProcessStatsDetail.java b/src/com/android/settings/applications/ProcessStatsDetail.java index 30f6b52..f0e76d4 100644 --- a/src/com/android/settings/applications/ProcessStatsDetail.java +++ b/src/com/android/settings/applications/ProcessStatsDetail.java @@ -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 sEntryCompare = new Comparator() { + @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 entries = new ArrayList<>(); + for (int ie=0; ie 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 sServiceCompare @@ -215,55 +245,65 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen } }; - final static Comparator> sServicePkgCompare - = new Comparator>() { + final static Comparator sServicePkgCompare = new Comparator() { @Override - public int compare(ArrayList lhs, - ArrayList 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 mServices = new ArrayList<>(); + long mDuration; + } + private void fillServicesSection() { - if (mEntry.mServices.size() > 0) { - boolean addPackageSections = false; - // Sort it all. - ArrayList> servicePkgs - = new ArrayList>(); - for (int ip=0; ip services = - (ArrayList)mEntry.mServices.valueAt(ip).clone(); - Collections.sort(services, sServiceCompare); - servicePkgs.add(services); + final HashMap pkgServices = new HashMap<>(); + final ArrayList pkgList = new ArrayList<>(); + for (int ie=0; ie< mApp.mEntries.size(); ie++) { + ProcStatsEntry ent = mApp.mEntries.get(ie); + for (int ip=0; ip 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; + } + } } - 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); + } + Collections.sort(pkgList, sServicePkgCompare); + for (int ip=0; ip services = pkgList.get(ip).mServices; + Collections.sort(services, sServiceCompare); + if (pkgList.size() > 1) { + addPackageHeaderItem(mServicesParent, services.get(0).mPackage); } - for (int ip=0; ip services = servicePkgs.get(ip); - if (addPackageSections) { - addPackageHeaderItem(mServicesParent, services.get(0).mPackage); - } - for (int is=0; is= 0 && tail < (label.length()-1)) { - label = label.substring(tail+1); - } - String percentage = Utils.formatPercentage(service.mDuration, mTotalTime); - addDetailsItem(mServicesParent, label, percentage); + for (int is=0; is= 0 && tail < (label.length()-1)) { + label = label.substring(tail+1); } + String percentage = Utils.formatPercentage(service.mDuration, mTotalTime); + addDetailsItem(mServicesParent, label, percentage); } } } @@ -271,39 +311,40 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen 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 sEntryCompare = new Comparator() { @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 sPackageEntryCompare + = new Comparator() { + @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 entries = new ArrayList(); + final ArrayList procEntries = new ArrayList<>(); + final ArrayList pkgEntries = new ArrayList<>(); /* ArrayList 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 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> processes - = new SparseArray>(); - for (int ip=0, N=mStats.mProcesses.getMap().size(); ip uids = mStats.mProcesses.getMap().valueAt(ip); - for (int iu=0; iu 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 uidProcs = processes.get(ent.mUid); - if (uidProcs == null) { - uidProcs = new ArrayMap(); - processes.put(ent.mUid, uidProcs); - } - uidProcs.put(ent.mName, ent); - } + // Combine processes into packages. + HashMap 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); - - long maxWeight = 1; - for (int i=0, N=(entries != null ? entries.size() : 0); i 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 (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; + 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); + } + + for (int i=0, N=pkgEntries.size(); i= 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))); } } -- cgit v1.1