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
This commit is contained in:
@@ -49,21 +49,18 @@
|
|||||||
<include layout="@layout/two_buttons_panel"/>
|
<include layout="@layout/two_buttons_panel"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="?android:attr/listSeparatorTextViewStyle"
|
|
||||||
android:text="@string/details_subtitle" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/details"
|
android:id="@+id/processes"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<!-- Insert detail items here -->
|
<!-- Insert process items here -->
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/services_label"
|
||||||
style="?android:attr/listSeparatorTextViewStyle"
|
style="?android:attr/listSeparatorTextViewStyle"
|
||||||
android:text="@string/services_subtitle" />
|
android:text="@string/services_subtitle" />
|
||||||
|
|
||||||
|
28
res/layout/process_stats_proc_details.xml
Normal file
28
res/layout/process_stats_proc_details.xml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/processes"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/processes_name"
|
||||||
|
style="?android:attr/listSeparatorTextViewStyle" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@@ -4059,8 +4059,9 @@
|
|||||||
<!-- [CHAR LIMIT=NONE] Label for amount of memory use -->
|
<!-- [CHAR LIMIT=NONE] Label for amount of memory use -->
|
||||||
<string name="app_memory_use">Memory use</string>
|
<string name="app_memory_use">Memory use</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Label for process stats, duration of time the stats are over -->
|
<!-- [CHAR LIMIT=NONE] Label for process stats, duration of time the stats are over -->
|
||||||
<string name="process_stats_total_duration"><xliff:g id="type">%1$s</xliff:g> apps over
|
<string name="process_stats_total_duration"><xliff:g id="usedRam">%1$s</xliff:g>
|
||||||
<xliff:g id="time">%2$s</xliff:g></string>
|
of <xliff:g id="totalRam">%2$s</xliff:g> used over
|
||||||
|
<xliff:g id="time">%3$s</xliff:g></string>
|
||||||
<!-- [CHAR LIMIT=NONE] Label for process stats, text for stats type -->
|
<!-- [CHAR LIMIT=NONE] Label for process stats, text for stats type -->
|
||||||
<string name="process_stats_type_background">Background</string>
|
<string name="process_stats_type_background">Background</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Label for process stats, text for stats type -->
|
<!-- [CHAR LIMIT=NONE] Label for process stats, text for stats type -->
|
||||||
@@ -4070,12 +4071,24 @@
|
|||||||
<!-- [CHAR LIMIT=NONE] Label for process stats, duration of time the stats are over -->
|
<!-- [CHAR LIMIT=NONE] Label for process stats, duration of time the stats are over -->
|
||||||
<string name="process_stats_memory_status">Device memory is currently
|
<string name="process_stats_memory_status">Device memory is currently
|
||||||
<xliff:g id="memstate">%1$s</xliff:g></string>
|
<xliff:g id="memstate">%1$s</xliff:g></string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Label OS "process" app -->
|
||||||
|
<string name="process_stats_os_label">Android OS</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Name of OS "process" for all native processes -->
|
||||||
|
<string name="process_stats_os_native">Native</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Name of OS "process" for all kernel memory -->
|
||||||
|
<string name="process_stats_os_kernel">Kernel</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Name of OS "process" for all zram memory -->
|
||||||
|
<string name="process_stats_os_zram">Z-Ram</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Name of OS "process" for base memory needed for caches -->
|
||||||
|
<string name="process_stats_os_cache">Caches</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Label for item showing details of average RAM use -->
|
<!-- [CHAR LIMIT=NONE] Label for item showing details of average RAM use -->
|
||||||
<string name="process_stats_avg_ram_use">Average RAM use</string>
|
<string name="process_stats_ram_use">RAM use</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Label for item showing details of maximum RAM use -->
|
<!-- [CHAR LIMIT=NONE] Label for item showing details of average RAM use -->
|
||||||
<string name="process_stats_max_ram_use">Maximum RAM use</string>
|
<string name="process_stats_bg_ram_use">RAM use (background)</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Label for item showing percent of time spent running -->
|
<!-- [CHAR LIMIT=NONE] Label for item showing percent of time spent running -->
|
||||||
<string name="process_stats_run_time">Run time</string>
|
<string name="process_stats_run_time">Run time</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Subtitle for process stats processes list -->
|
||||||
|
<string name="processes_subtitle">Processes</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Subtitle for process stats services list -->
|
<!-- [CHAR LIMIT=NONE] Subtitle for process stats services list -->
|
||||||
<string name="services_subtitle">Services</string>
|
<string name="services_subtitle">Services</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Menu for process stats to select duration of stats to show -->
|
<!-- [CHAR LIMIT=NONE] Menu for process stats to select duration of stats to show -->
|
||||||
|
@@ -21,6 +21,7 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.os.Process;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
@@ -38,37 +39,49 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
final int mUid;
|
final int mUid;
|
||||||
final String mName;
|
final String mName;
|
||||||
final ArrayList<String> mPackages = new ArrayList<String>();
|
final ArrayList<String> mPackages = new ArrayList<String>();
|
||||||
final long mDuration;
|
final long mBgDuration;
|
||||||
final long mAvgPss;
|
final long mAvgBgMem;
|
||||||
final long mMaxPss;
|
final long mMaxBgMem;
|
||||||
final long mAvgUss;
|
final double mBgWeight;
|
||||||
final long mMaxUss;
|
final long mRunDuration;
|
||||||
final long mWeight;
|
final long mAvgRunMem;
|
||||||
|
final long mMaxRunMem;
|
||||||
|
final double mRunWeight;
|
||||||
|
|
||||||
String mBestTargetPackage;
|
String mBestTargetPackage;
|
||||||
|
|
||||||
ArrayMap<String, ArrayList<Service>> mServices = new ArrayMap<String, ArrayList<Service>>(1);
|
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,
|
public ProcStatsEntry(ProcessStats.ProcessState proc, String packageName,
|
||||||
ProcessStats.ProcessDataCollection tmpTotals, boolean useUss, boolean weightWithTime) {
|
ProcessStats.ProcessDataCollection tmpBgTotals,
|
||||||
ProcessStats.computeProcessData(proc, tmpTotals, 0);
|
ProcessStats.ProcessDataCollection tmpRunTotals, boolean useUss) {
|
||||||
|
ProcessStats.computeProcessData(proc, tmpBgTotals, 0);
|
||||||
|
ProcessStats.computeProcessData(proc, tmpRunTotals, 0);
|
||||||
mPackage = proc.mPackage;
|
mPackage = proc.mPackage;
|
||||||
mUid = proc.mUid;
|
mUid = proc.mUid;
|
||||||
mName = proc.mName;
|
mName = proc.mName;
|
||||||
mPackages.add(packageName);
|
mPackages.add(packageName);
|
||||||
mDuration = tmpTotals.totalTime;
|
mBgDuration = tmpBgTotals.totalTime;
|
||||||
mAvgPss = tmpTotals.avgPss;
|
mAvgBgMem = useUss ? tmpBgTotals.avgUss : tmpBgTotals.avgPss;
|
||||||
mMaxPss = tmpTotals.maxPss;
|
mMaxBgMem = useUss ? tmpBgTotals.maxUss : tmpBgTotals.maxPss;
|
||||||
mAvgUss = tmpTotals.avgUss;
|
mBgWeight = mAvgBgMem * (double) mBgDuration;
|
||||||
mMaxUss = tmpTotals.maxUss;
|
mRunDuration = tmpRunTotals.totalTime;
|
||||||
mWeight = (weightWithTime ? mDuration : 1) * (useUss ? mAvgUss : mAvgPss);
|
mAvgRunMem = useUss ? tmpRunTotals.avgUss : tmpRunTotals.avgPss;
|
||||||
if (DEBUG) Log.d(TAG, "New proc entry " + proc.mName + ": dur=" + mDuration
|
mMaxRunMem = useUss ? tmpRunTotals.maxUss : tmpRunTotals.maxPss;
|
||||||
+ " avgpss=" + mAvgPss + " weight=" + mWeight);
|
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) {
|
public ProcStatsEntry(Parcel in) {
|
||||||
@@ -76,12 +89,14 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
mUid = in.readInt();
|
mUid = in.readInt();
|
||||||
mName = in.readString();
|
mName = in.readString();
|
||||||
in.readStringList(mPackages);
|
in.readStringList(mPackages);
|
||||||
mDuration = in.readLong();
|
mBgDuration = in.readLong();
|
||||||
mAvgPss = in.readLong();
|
mAvgBgMem = in.readLong();
|
||||||
mMaxPss = in.readLong();
|
mMaxBgMem = in.readLong();
|
||||||
mAvgUss = in.readLong();
|
mBgWeight = in.readDouble();
|
||||||
mMaxUss = in.readLong();
|
mRunDuration = in.readLong();
|
||||||
mWeight = in.readLong();
|
mAvgRunMem = in.readLong();
|
||||||
|
mMaxRunMem = in.readLong();
|
||||||
|
mRunWeight = in.readDouble();
|
||||||
mBestTargetPackage = in.readString();
|
mBestTargetPackage = in.readString();
|
||||||
final int N = in.readInt();
|
final int N = in.readInt();
|
||||||
if (N > 0) {
|
if (N > 0) {
|
||||||
@@ -100,15 +115,27 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void evaluateTargetPackage(PackageManager pm, ProcessStats stats,
|
public void evaluateTargetPackage(PackageManager pm, ProcessStats stats,
|
||||||
ProcessStats.ProcessDataCollection totals, Comparator<ProcStatsEntry> compare,
|
ProcessStats.ProcessDataCollection bgTotals,
|
||||||
boolean useUss, boolean weightWithTime) {
|
ProcessStats.ProcessDataCollection runTotals, Comparator<ProcStatsEntry> compare,
|
||||||
|
boolean useUss) {
|
||||||
mBestTargetPackage = null;
|
mBestTargetPackage = null;
|
||||||
if (mPackages.size() == 1) {
|
if (mPackages.size() == 1) {
|
||||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": single pkg " + mPackages.get(0));
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": single pkg " + mPackages.get(0));
|
||||||
mBestTargetPackage = mPackages.get(0);
|
mBestTargetPackage = mPackages.get(0);
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If one of the packages is the framework itself, that wins.
|
||||||
// See if there is one significant package that was running here.
|
// 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++) {
|
||||||
|
if ("android".equals(mPackages.get(ipkg))) {
|
||||||
|
mBestTargetPackage = mPackages.get(ipkg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect information about each package running in the process.
|
||||||
|
ArrayList<ProcStatsEntry> subProcs = new ArrayList<>();
|
||||||
for (int ipkg=0; ipkg<mPackages.size(); ipkg++) {
|
for (int ipkg=0; ipkg<mPackages.size(); ipkg++) {
|
||||||
SparseArray<ProcessStats.PackageState> vpkgs
|
SparseArray<ProcessStats.PackageState> vpkgs
|
||||||
= stats.mPackages.get(mPackages.get(ipkg), mUid);
|
= stats.mPackages.get(mPackages.get(ipkg), mUid);
|
||||||
@@ -127,48 +154,70 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
+ mPackages.get(ipkg) + "/" + mUid);
|
+ mPackages.get(ipkg) + "/" + mUid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
subProcs.add(new ProcStatsEntry(pkgProc, pkgState.mPackageName, totals, useUss,
|
subProcs.add(new ProcStatsEntry(pkgProc, pkgState.mPackageName, bgTotals,
|
||||||
weightWithTime));
|
runTotals, useUss));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subProcs.size() > 1) {
|
if (subProcs.size() > 1) {
|
||||||
Collections.sort(subProcs, compare);
|
Collections.sort(subProcs, compare);
|
||||||
if (subProcs.get(0).mWeight > (subProcs.get(1).mWeight*3)) {
|
if (subProcs.get(0).mRunWeight > (subProcs.get(1).mRunWeight *3)) {
|
||||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": best pkg "
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": best pkg "
|
||||||
+ subProcs.get(0).mPackage + " weight " + subProcs.get(0).mWeight
|
+ subProcs.get(0).mPackage + " weight " + subProcs.get(0).mRunWeight
|
||||||
+ " better than " + subProcs.get(1).mPackage
|
+ " better than " + subProcs.get(1).mPackage
|
||||||
+ " weight " + subProcs.get(1).mWeight);
|
+ " weight " + subProcs.get(1).mRunWeight);
|
||||||
mBestTargetPackage = subProcs.get(0).mPackage;
|
mBestTargetPackage = subProcs.get(0).mPackage;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Couldn't find one that is best by weight, let's decide on best another
|
// 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
|
// 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.
|
// half of the maximum weight, and has specified an explicit app icon.
|
||||||
long maxWeight = subProcs.get(0).mWeight;
|
double maxWeight = subProcs.get(0).mRunWeight;
|
||||||
long bestRunTime = -1;
|
long bestRunTime = -1;
|
||||||
|
boolean bestPersistent = false;
|
||||||
for (int i=0; i<subProcs.size(); i++) {
|
for (int i=0; i<subProcs.size(); i++) {
|
||||||
if (subProcs.get(i).mWeight < (maxWeight/2)) {
|
final ProcStatsEntry subProc = subProcs.get(i);
|
||||||
|
if (subProc.mRunWeight < (maxWeight/2)) {
|
||||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
+ subProcs.get(i).mPackage + " weight " + subProcs.get(i).mWeight
|
+ subProc.mPackage + " weight " + subProc.mRunWeight
|
||||||
+ " too small");
|
+ " too small");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ApplicationInfo ai = pm.getApplicationInfo(subProcs.get(i).mPackage, 0);
|
ApplicationInfo ai = pm.getApplicationInfo(subProc.mPackage, 0);
|
||||||
if (ai.icon == 0) {
|
if (ai.icon == 0) {
|
||||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
+ subProcs.get(i).mPackage + " has no icon");
|
+ 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);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (bestPersistent) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
|
+ subProc.mPackage + " is not persistent");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
+ subProcs.get(i).mPackage + " failed finding app info");
|
+ subProc.mPackage + " failed finding app info");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ArrayList<Service> subProcServices = null;
|
ArrayList<Service> subProcServices = null;
|
||||||
for (int isp=0, NSP=mServices.size(); isp<NSP; isp++) {
|
for (int isp=0, NSP=mServices.size(); isp<NSP; isp++) {
|
||||||
ArrayList<Service> subServices = mServices.valueAt(isp);
|
ArrayList<Service> subServices = mServices.valueAt(isp);
|
||||||
if (subServices.get(0).mPackage.equals(subProcs.get(i).mPackage)) {
|
if (subServices.get(0).mPackage.equals(subProc.mPackage)) {
|
||||||
subProcServices = subServices;
|
subProcServices = subServices;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -179,7 +228,7 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
Service service = subProcServices.get(iss);
|
Service service = subProcServices.get(iss);
|
||||||
if (service.mDuration > thisRunTime) {
|
if (service.mDuration > thisRunTime) {
|
||||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
+ subProcs.get(i).mPackage + " service " + service.mName
|
+ subProc.mPackage + " service " + service.mName
|
||||||
+ " run time is " + service.mDuration);
|
+ " run time is " + service.mDuration);
|
||||||
thisRunTime = service.mDuration;
|
thisRunTime = service.mDuration;
|
||||||
break;
|
break;
|
||||||
@@ -188,12 +237,12 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
}
|
}
|
||||||
if (thisRunTime > bestRunTime) {
|
if (thisRunTime > bestRunTime) {
|
||||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
+ subProcs.get(i).mPackage + " new best run time " + thisRunTime);
|
+ subProc.mPackage + " new best run time " + thisRunTime);
|
||||||
mBestTargetPackage = subProcs.get(i).mPackage;
|
mBestTargetPackage = subProc.mPackage;
|
||||||
bestRunTime = thisRunTime;
|
bestRunTime = thisRunTime;
|
||||||
} else {
|
} else {
|
||||||
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
+ subProcs.get(i).mPackage + " run time " + thisRunTime
|
+ subProc.mPackage + " run time " + thisRunTime
|
||||||
+ " not as good as last " + bestRunTime);
|
+ " not as good as last " + bestRunTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,67 +250,6 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
mBestTargetPackage = subProcs.get(0).mPackage;
|
mBestTargetPackage = subProcs.get(0).mPackage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void retrieveUiData(PackageManager pm) {
|
|
||||||
mUiTargetApp = null;
|
|
||||||
mUiLabel = mUiBaseLabel = mName;
|
|
||||||
mUiPackage = mBestTargetPackage;
|
|
||||||
if (mUiPackage != null) {
|
|
||||||
// Only one app associated with this process.
|
|
||||||
try {
|
|
||||||
mUiTargetApp = pm.getApplicationInfo(mUiPackage,
|
|
||||||
PackageManager.GET_DISABLED_COMPONENTS |
|
|
||||||
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
|
|
||||||
PackageManager.GET_UNINSTALLED_PACKAGES);
|
|
||||||
String name = mUiBaseLabel = mUiTargetApp.loadLabel(pm).toString();
|
|
||||||
if (mName.equals(mUiPackage)) {
|
|
||||||
mUiLabel = name;
|
|
||||||
} else {
|
|
||||||
if (mName.startsWith(mUiPackage)) {
|
|
||||||
int off = mUiPackage.length();
|
|
||||||
if (mName.length() > off) {
|
|
||||||
off++;
|
|
||||||
}
|
|
||||||
mUiLabel = name + " (" + mName.substring(off) + ")";
|
|
||||||
} else {
|
|
||||||
mUiLabel = name + " (" + mName + ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mUiTargetApp == null) {
|
|
||||||
String[] packages = pm.getPackagesForUid(mUid);
|
|
||||||
if (packages != null) {
|
|
||||||
for (String curPkg : packages) {
|
|
||||||
try {
|
|
||||||
final PackageInfo pi = pm.getPackageInfo(curPkg,
|
|
||||||
PackageManager.GET_DISABLED_COMPONENTS |
|
|
||||||
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
|
|
||||||
PackageManager.GET_UNINSTALLED_PACKAGES);
|
|
||||||
if (pi.sharedUserLabel != 0) {
|
|
||||||
mUiTargetApp = pi.applicationInfo;
|
|
||||||
final CharSequence nm = pm.getText(curPkg,
|
|
||||||
pi.sharedUserLabel, pi.applicationInfo);
|
|
||||||
if (nm != null) {
|
|
||||||
mUiBaseLabel = nm.toString();
|
|
||||||
mUiLabel = mUiBaseLabel + " (" + mName + ")";
|
|
||||||
} else {
|
|
||||||
mUiBaseLabel = mUiTargetApp.loadLabel(pm).toString();
|
|
||||||
mUiLabel = mUiBaseLabel + " (" + mName + ")";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no current packages for this uid, typically because of uninstall
|
|
||||||
Log.i(TAG, "No package for uid " + mUid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addService(ProcessStats.ServiceState svc) {
|
public void addService(ProcessStats.ServiceState svc) {
|
||||||
ArrayList<Service> services = mServices.get(svc.mPackage);
|
ArrayList<Service> services = mServices.get(svc.mPackage);
|
||||||
@@ -283,12 +271,14 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
dest.writeInt(mUid);
|
dest.writeInt(mUid);
|
||||||
dest.writeString(mName);
|
dest.writeString(mName);
|
||||||
dest.writeStringList(mPackages);
|
dest.writeStringList(mPackages);
|
||||||
dest.writeLong(mDuration);
|
dest.writeLong(mBgDuration);
|
||||||
dest.writeLong(mAvgPss);
|
dest.writeLong(mAvgBgMem);
|
||||||
dest.writeLong(mMaxPss);
|
dest.writeLong(mMaxBgMem);
|
||||||
dest.writeLong(mAvgUss);
|
dest.writeDouble(mBgWeight);
|
||||||
dest.writeLong(mMaxUss);
|
dest.writeLong(mRunDuration);
|
||||||
dest.writeLong(mWeight);
|
dest.writeLong(mAvgRunMem);
|
||||||
|
dest.writeLong(mMaxRunMem);
|
||||||
|
dest.writeDouble(mRunWeight);
|
||||||
dest.writeString(mBestTargetPackage);
|
dest.writeString(mBestTargetPackage);
|
||||||
final int N = mServices.size();
|
final int N = mServices.size();
|
||||||
dest.writeInt(N);
|
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;
|
package com.android.settings.applications;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -44,6 +38,7 @@ import com.android.settings.Utils;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
import static com.android.settings.Utils.prepareCustomPreferencesList;
|
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 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_USE_USS = "use_uss";
|
||||||
public static final String EXTRA_MAX_WEIGHT = "max_weight";
|
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";
|
public static final String EXTRA_TOTAL_TIME = "total_time";
|
||||||
|
|
||||||
private PackageManager mPm;
|
private PackageManager mPm;
|
||||||
private DevicePolicyManager mDpm;
|
private DevicePolicyManager mDpm;
|
||||||
|
|
||||||
private ProcStatsEntry mEntry;
|
private ProcStatsPackageEntry mApp;
|
||||||
private boolean mUseUss;
|
private boolean mUseUss;
|
||||||
private long mMaxWeight;
|
private double mMaxWeight;
|
||||||
|
private double mWeightToRam;
|
||||||
private long mTotalTime;
|
private long mTotalTime;
|
||||||
|
private long mOnePercentTime;
|
||||||
|
|
||||||
private View mRootView;
|
private View mRootView;
|
||||||
private TextView mTitleView;
|
private TextView mTitleView;
|
||||||
private ViewGroup mTwoButtonsPanel;
|
private ViewGroup mTwoButtonsPanel;
|
||||||
private Button mForceStopButton;
|
private Button mForceStopButton;
|
||||||
private Button mReportButton;
|
private Button mReportButton;
|
||||||
private ViewGroup mDetailsParent;
|
private ViewGroup mProcessesParent;
|
||||||
private ViewGroup mServicesParent;
|
private ViewGroup mServicesParent;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -79,11 +77,13 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
|||||||
mPm = getActivity().getPackageManager();
|
mPm = getActivity().getPackageManager();
|
||||||
mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
|
mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||||
final Bundle args = getArguments();
|
final Bundle args = getArguments();
|
||||||
mEntry = (ProcStatsEntry)args.getParcelable(EXTRA_ENTRY);
|
mApp = args.getParcelable(EXTRA_PACKAGE_ENTRY);
|
||||||
mEntry.retrieveUiData(mPm);
|
mApp.retrieveUiData(getActivity(), mPm);
|
||||||
mUseUss = args.getBoolean(EXTRA_USE_USS);
|
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);
|
mTotalTime = args.getLong(EXTRA_TOTAL_TIME);
|
||||||
|
mOnePercentTime = mTotalTime/100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -109,24 +109,22 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createDetails() {
|
private void createDetails() {
|
||||||
final double percentOfWeight = (((double)mEntry.mWeight) / mMaxWeight) * 100;
|
final double percentOfWeight = (mApp.mBgWeight / mMaxWeight) * 100;
|
||||||
|
|
||||||
int appLevel = (int) Math.ceil(percentOfWeight);
|
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.
|
// 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 = (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);
|
final TextView text1 = (TextView)mRootView.findViewById(android.R.id.text1);
|
||||||
text1.setText(appLevelText);
|
text1.setText(appLevelText);
|
||||||
final ProgressBar progress = (ProgressBar) mRootView.findViewById(android.R.id.progress);
|
final ProgressBar progress = (ProgressBar) mRootView.findViewById(android.R.id.progress);
|
||||||
progress.setProgress(appLevel);
|
progress.setProgress(appLevel);
|
||||||
final ImageView icon = (ImageView) mRootView.findViewById(android.R.id.icon);
|
final ImageView icon = (ImageView) mRootView.findViewById(android.R.id.icon);
|
||||||
if (mEntry.mUiTargetApp != null) {
|
if (mApp.mUiTargetApp != null) {
|
||||||
icon.setImageDrawable(mEntry.mUiTargetApp.loadIcon(mPm));
|
icon.setImageDrawable(mApp.mUiTargetApp.loadIcon(mPm));
|
||||||
}
|
}
|
||||||
|
|
||||||
mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel);
|
mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel);
|
||||||
@@ -135,13 +133,17 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
|||||||
mForceStopButton.setEnabled(false);
|
mForceStopButton.setEnabled(false);
|
||||||
mReportButton.setVisibility(View.INVISIBLE);
|
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);
|
mServicesParent = (ViewGroup)mRootView.findViewById(R.id.services);
|
||||||
|
|
||||||
fillDetailsSection();
|
fillProcessesSection();
|
||||||
fillServicesSection();
|
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.setText(R.string.force_stop);
|
||||||
mForceStopButton.setTag(ACTION_FORCE_STOP);
|
mForceStopButton.setTag(ACTION_FORCE_STOP);
|
||||||
mForceStopButton.setOnClickListener(this);
|
mForceStopButton.setOnClickListener(this);
|
||||||
@@ -191,15 +193,43 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
|||||||
valueView.setText(value);
|
valueView.setText(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillDetailsSection() {
|
final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
|
||||||
addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_avg_ram_use),
|
@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(),
|
Formatter.formatShortFileSize(getActivity(),
|
||||||
(mUseUss ? mEntry.mAvgUss : mEntry.mAvgPss) * 1024));
|
(long)(entry.mRunWeight * mWeightToRam)));
|
||||||
addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_max_ram_use),
|
if (entry.mBgWeight > 0) {
|
||||||
|
addDetailsItem(item, getResources().getText(R.string.process_stats_bg_ram_use),
|
||||||
Formatter.formatShortFileSize(getActivity(),
|
Formatter.formatShortFileSize(getActivity(),
|
||||||
(mUseUss ? mEntry.mMaxUss : mEntry.mMaxPss) * 1024));
|
(long)(entry.mBgWeight * mWeightToRam)));
|
||||||
addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_run_time),
|
}
|
||||||
Utils.formatPercentage(mEntry.mDuration, mTotalTime));
|
addDetailsItem(item, getResources().getText(R.string.process_stats_run_time),
|
||||||
|
Utils.formatPercentage(entry.mRunDuration, mTotalTime));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final static Comparator<ProcStatsEntry.Service> sServiceCompare
|
final static Comparator<ProcStatsEntry.Service> sServiceCompare
|
||||||
@@ -215,43 +245,54 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
final static Comparator<ArrayList<ProcStatsEntry.Service>> sServicePkgCompare
|
final static Comparator<PkgService> sServicePkgCompare = new Comparator<PkgService>() {
|
||||||
= new Comparator<ArrayList<ProcStatsEntry.Service>>() {
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(ArrayList<ProcStatsEntry.Service> lhs,
|
public int compare(PkgService lhs, PkgService rhs) {
|
||||||
ArrayList<ProcStatsEntry.Service> rhs) {
|
if (lhs.mDuration < rhs.mDuration) {
|
||||||
long topLhs = lhs.size() > 0 ? lhs.get(0).mDuration : 0;
|
|
||||||
long topRhs = rhs.size() > 0 ? rhs.get(0).mDuration : 0;
|
|
||||||
if (topLhs < topRhs) {
|
|
||||||
return 1;
|
return 1;
|
||||||
} else if (topLhs > topRhs) {
|
} else if (lhs.mDuration > rhs.mDuration) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static class PkgService {
|
||||||
|
final ArrayList<ProcStatsEntry.Service> mServices = new ArrayList<>();
|
||||||
|
long mDuration;
|
||||||
|
}
|
||||||
|
|
||||||
private void fillServicesSection() {
|
private void fillServicesSection() {
|
||||||
if (mEntry.mServices.size() > 0) {
|
final HashMap<String, PkgService> pkgServices = new HashMap<>();
|
||||||
boolean addPackageSections = false;
|
final ArrayList<PkgService> pkgList = new ArrayList<>();
|
||||||
// Sort it all.
|
for (int ie=0; ie< mApp.mEntries.size(); ie++) {
|
||||||
ArrayList<ArrayList<ProcStatsEntry.Service>> servicePkgs
|
ProcStatsEntry ent = mApp.mEntries.get(ie);
|
||||||
= new ArrayList<ArrayList<ProcStatsEntry.Service>>();
|
for (int ip=0; ip<ent.mServices.size(); ip++) {
|
||||||
for (int ip=0; ip<mEntry.mServices.size(); ip++) {
|
String pkg = ent.mServices.keyAt(ip);
|
||||||
ArrayList<ProcStatsEntry.Service> services =
|
PkgService psvc = null;
|
||||||
(ArrayList<ProcStatsEntry.Service>)mEntry.mServices.valueAt(ip).clone();
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(pkgList, sServicePkgCompare);
|
||||||
|
for (int ip=0; ip<pkgList.size(); ip++) {
|
||||||
|
ArrayList<ProcStatsEntry.Service> services = pkgList.get(ip).mServices;
|
||||||
Collections.sort(services, sServiceCompare);
|
Collections.sort(services, sServiceCompare);
|
||||||
servicePkgs.add(services);
|
if (pkgList.size() > 1) {
|
||||||
}
|
|
||||||
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);
|
addPackageHeaderItem(mServicesParent, services.get(0).mPackage);
|
||||||
}
|
}
|
||||||
for (int is=0; is<services.size(); is++) {
|
for (int is=0; is<services.size(); is++) {
|
||||||
@@ -266,44 +307,44 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void killProcesses() {
|
private void killProcesses() {
|
||||||
ActivityManager am = (ActivityManager)getActivity().getSystemService(
|
ActivityManager am = (ActivityManager)getActivity().getSystemService(
|
||||||
Context.ACTIVITY_SERVICE);
|
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();
|
checkForceStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private void checkForceStop() {
|
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);
|
mForceStopButton.setEnabled(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mDpm.packageHasActiveAdmins(mEntry.mUiPackage)) {
|
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);
|
mForceStopButton.setEnabled(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ApplicationInfo info = mPm.getApplicationInfo(mEntry.mUiPackage, 0);
|
ApplicationInfo info = mPm.getApplicationInfo(pkg, 0);
|
||||||
if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
|
if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
|
||||||
mForceStopButton.setEnabled(true);
|
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 });
|
if (isStarted) {
|
||||||
intent.putExtra(Intent.EXTRA_UID, mEntry.mUid);
|
mForceStopButton.setEnabled(true);
|
||||||
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mEntry.mUid));
|
}
|
||||||
getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
|
|
||||||
Activity.RESULT_CANCELED, null, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,7 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
|
|
||||||
public class ProcessStatsPreference extends Preference {
|
public class ProcessStatsPreference extends Preference {
|
||||||
private ProcStatsEntry mEntry;
|
private ProcStatsPackageEntry mEntry;
|
||||||
private int mProgress;
|
private int mProgress;
|
||||||
private CharSequence mProgressText;
|
private CharSequence mProgressText;
|
||||||
|
|
||||||
@@ -51,18 +51,19 @@ public class ProcessStatsPreference extends Preference {
|
|||||||
setLayoutResource(R.layout.preference_app_percentage);
|
setLayoutResource(R.layout.preference_app_percentage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Drawable icon, ProcStatsEntry entry) {
|
public void init(Drawable icon, ProcStatsPackageEntry entry) {
|
||||||
mEntry = entry;
|
mEntry = entry;
|
||||||
setIcon(icon != null ? icon : new ColorDrawable(0));
|
setIcon(icon != null ? icon : new ColorDrawable(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProcStatsEntry getEntry() {
|
public ProcStatsPackageEntry getEntry() {
|
||||||
return mEntry;
|
return mEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPercent(double percentOfWeight, double percentOfTime) {
|
public void setPercent(double percentOfWeight, double percentOfTime, long memory) {
|
||||||
mProgress = (int) Math.ceil(percentOfWeight);
|
mProgress = (int) Math.ceil(percentOfWeight);
|
||||||
mProgressText = Utils.formatPercentage((int) percentOfTime);
|
//mProgressText = Utils.formatPercentage((int) percentOfTime);
|
||||||
|
mProgressText = Formatter.formatShortFileSize(getContext(), memory);
|
||||||
notifyChanged();
|
notifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ package com.android.settings.applications;
|
|||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -50,6 +51,7 @@ import java.io.InputStream;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class ProcessStatsUi extends PreferenceFragment
|
public class ProcessStatsUi extends PreferenceFragment
|
||||||
implements LinearColorBar.OnRegionTappedListener {
|
implements LinearColorBar.OnRegionTappedListener {
|
||||||
@@ -75,13 +77,30 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
|
final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
|
public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
|
||||||
if (lhs.mWeight < rhs.mWeight) {
|
if (lhs.mRunWeight < rhs.mRunWeight) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (lhs.mWeight > rhs.mWeight) {
|
} else if (lhs.mRunWeight > rhs.mRunWeight) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (lhs.mDuration < rhs.mDuration) {
|
} else if (lhs.mRunDuration < rhs.mRunDuration) {
|
||||||
return 1;
|
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 -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -112,7 +131,7 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
private PreferenceGroup mAppListGroup;
|
private PreferenceGroup mAppListGroup;
|
||||||
private Preference mMemStatusPref;
|
private Preference mMemStatusPref;
|
||||||
|
|
||||||
long mMaxWeight;
|
double mMaxWeight;
|
||||||
long mTotalTime;
|
long mTotalTime;
|
||||||
|
|
||||||
long[] mMemTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT];
|
long[] mMemTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT];
|
||||||
@@ -123,6 +142,7 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
double mMemKernelWeight;
|
double mMemKernelWeight;
|
||||||
double mMemNativeWeight;
|
double mMemNativeWeight;
|
||||||
double mMemTotalWeight;
|
double mMemTotalWeight;
|
||||||
|
double mWeightToRam;
|
||||||
|
|
||||||
// The actual duration value to use for each duration option. Note these
|
// The actual duration value to use for each duration option. Note these
|
||||||
// are lower than the actual duration, since our durations are computed in
|
// 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;
|
ProcessStatsPreference pgp = (ProcessStatsPreference) preference;
|
||||||
Bundle args = new Bundle();
|
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.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);
|
args.putLong(ProcessStatsDetail.EXTRA_TOTAL_TIME, mTotalTime);
|
||||||
((SettingsActivity) getActivity()).startPreferencePanel(
|
((SettingsActivity) getActivity()).startPreferencePanel(
|
||||||
ProcessStatsDetail.class.getName(), args, R.string.details_title, null, null, 0);
|
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;
|
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();
|
long now = SystemClock.uptimeMillis();
|
||||||
|
|
||||||
final PackageManager pm = getActivity().getPackageManager();
|
final PackageManager pm = getActivity().getPackageManager();
|
||||||
@@ -470,9 +466,13 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
memStates = ProcessStats.ALL_MEM_ADJ;
|
memStates = ProcessStats.ALL_MEM_ADJ;
|
||||||
break;
|
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.
|
// Compute memory badness for chart color.
|
||||||
|
/*
|
||||||
int[] badColors = com.android.settings.Utils.BADNESS_COLORS;
|
int[] badColors = com.android.settings.Utils.BADNESS_COLORS;
|
||||||
long timeGood = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL];
|
long timeGood = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL];
|
||||||
timeGood += (mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]*2)/3;
|
timeGood += (mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]*2)/3;
|
||||||
@@ -480,6 +480,7 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
float memBadness = ((float)timeGood)/mTotalTime;
|
float memBadness = ((float)timeGood)/mTotalTime;
|
||||||
int badnessColor = badColors[1 + Math.round(memBadness*(badColors.length-2))];
|
int badnessColor = badColors[1 + Math.round(memBadness*(badColors.length-2))];
|
||||||
colors.setColors(badnessColor, badnessColor, badnessColor);
|
colors.setColors(badnessColor, badnessColor, badnessColor);
|
||||||
|
*/
|
||||||
|
|
||||||
// We are now going to scale the mMemTimes to match the total elapsed time.
|
// 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,
|
// 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();
|
memReader.readMemInfo();
|
||||||
double realTotalRam = memReader.getTotalSize();
|
double realTotalRam = memReader.getTotalSize();
|
||||||
double totalScale = realTotalRam / totalRam;
|
double totalScale = realTotalRam / totalRam;
|
||||||
|
mWeightToRam = totalScale / memTotalTime * 1024;
|
||||||
|
mMaxWeight = totalRam / mWeightToRam;
|
||||||
double realUsedRam = usedRam * totalScale;
|
double realUsedRam = usedRam * totalScale;
|
||||||
double realFreeRam = freeRam * totalScale;
|
double realFreeRam = freeRam * totalScale;
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@@ -558,12 +561,15 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
|
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
|
||||||
((ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(
|
((ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(
|
||||||
memInfo);
|
memInfo);
|
||||||
|
long baseCacheRam;
|
||||||
if (memInfo.hiddenAppThreshold >= realFreeRam) {
|
if (memInfo.hiddenAppThreshold >= realFreeRam) {
|
||||||
realUsedRam = realFreeRam;
|
realUsedRam = realFreeRam;
|
||||||
realFreeRam = 0;
|
realFreeRam = 0;
|
||||||
|
baseCacheRam = (long)realFreeRam;
|
||||||
} else {
|
} else {
|
||||||
realUsedRam += memInfo.hiddenAppThreshold;
|
realUsedRam += memInfo.hiddenAppThreshold;
|
||||||
realFreeRam -= memInfo.hiddenAppThreshold;
|
realFreeRam -= memInfo.hiddenAppThreshold;
|
||||||
|
baseCacheRam = memInfo.hiddenAppThreshold;
|
||||||
}
|
}
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "Adj Scaled Used RAM: " + Formatter.formatShortFileSize(getActivity(),
|
Log.i(TAG, "Adj Scaled Used RAM: " + Formatter.formatShortFileSize(getActivity(),
|
||||||
@@ -572,6 +578,22 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
(long)realFreeRam));
|
(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));
|
float usedRatio = (float)(realUsedRam/(realFreeRam+realUsedRam));
|
||||||
colors.setRatios(usedRatio, 0, 1-usedRatio);
|
colors.setRatios(usedRatio, 0, 1-usedRatio);
|
||||||
|
|
||||||
@@ -605,17 +627,20 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
|
|
||||||
mAppListGroup.addPreference(colors);
|
mAppListGroup.addPreference(colors);
|
||||||
|
|
||||||
ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
|
ProcessStats.ProcessDataCollection bgTotals = new ProcessStats.ProcessDataCollection(
|
||||||
ProcessStats.ALL_SCREEN_ADJ, memStates, stats);
|
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(
|
ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked(
|
||||||
ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ,
|
ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ,
|
||||||
ProcessStats.BACKGROUND_PROC_STATES, now, null);
|
ProcessStats.BACKGROUND_PROC_STATES, now, null);
|
||||||
for (int i=0, N=(rawProcs != null ? rawProcs.size() : 0); i<N; i++) {
|
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);
|
ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid);
|
||||||
if (ent == null) {
|
if (ent == null) {
|
||||||
ent = new ProcStatsEntry(proc, st.mPackageName, totals, mUseUss,
|
ent = new ProcStatsEntry(proc, st.mPackageName, bgTotals, runTotals,
|
||||||
mStatsType == MENU_TYPE_BACKGROUND);
|
mUseUss);
|
||||||
if (ent.mDuration > 0) {
|
if (ent.mRunWeight > 0) {
|
||||||
if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
|
if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
|
||||||
+ proc.mUid + ": time=" + makeDuration(ent.mDuration) + " ("
|
+ proc.mUid + ": time=" + makeDuration(ent.mRunDuration) + " ("
|
||||||
+ ((((double)ent.mDuration) / memTotalTime) * 100) + "%)"
|
+ ((((double)ent.mRunDuration) / memTotalTime) * 100) + "%)"
|
||||||
+ " pss=" + ent.mAvgPss);
|
+ " pss=" + ent.mAvgRunMem);
|
||||||
entriesMap.put(proc.mName, proc.mUid, ent);
|
entriesMap.put(proc.mName, proc.mUid, ent);
|
||||||
entries.add(ent);
|
procEntries.add(ent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ent.addPackage(st.mPackageName);
|
ent.addPackage(st.mPackageName);
|
||||||
@@ -672,7 +697,8 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
for (int is=0, NS=ps.mServices.size(); is<NS; is++) {
|
for (int is=0, NS=ps.mServices.size(); is<NS; is++) {
|
||||||
ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
|
ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
|
||||||
if (ss.mProcessName != null) {
|
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 (ent != null) {
|
||||||
if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName
|
if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName
|
||||||
+ "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc "
|
+ "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc "
|
||||||
@@ -689,90 +715,99 @@ public class ProcessStatsUi extends PreferenceFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Combine processes into packages.
|
||||||
SparseArray<ArrayMap<String, ProcStatsEntry>> processes
|
HashMap<String, ProcStatsPackageEntry> pkgMap = new HashMap<>();
|
||||||
= new SparseArray<ArrayMap<String, ProcStatsEntry>>();
|
for (int i=procEntries.size()-1; i>=0; i--) {
|
||||||
for (int ip=0, N=mStats.mProcesses.getMap().size(); ip<N; ip++) {
|
ProcStatsEntry proc = procEntries.get(i);
|
||||||
SparseArray<ProcessStats.ProcessState> uids = mStats.mProcesses.getMap().valueAt(ip);
|
proc.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
|
||||||
for (int iu=0; iu<uids.size(); iu++) {
|
ProcStatsPackageEntry pkg = pkgMap.get(proc.mBestTargetPackage);
|
||||||
ProcessStats.ProcessState st = uids.valueAt(iu);
|
if (pkg == null) {
|
||||||
ProcStatsEntry ent = new ProcStatsEntry(st, totals, mUseUss,
|
pkg = new ProcStatsPackageEntry(proc.mBestTargetPackage);
|
||||||
mStatsType == MENU_TYPE_BACKGROUND);
|
pkgMap.put(proc.mBestTargetPackage, pkg);
|
||||||
if (ent.mDuration > 0) {
|
pkgEntries.add(pkg);
|
||||||
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);
|
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=pkgEntries.size(); i<N; i++) {
|
||||||
for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) {
|
ProcStatsPackageEntry pkg = pkgEntries.get(i);
|
||||||
ProcStatsEntry proc = entries.get(i);
|
pkg.updateMetrics();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI");
|
||||||
|
|
||||||
// Find where we should stop. Because we have two properties we are looking at,
|
// 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.
|
// 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) {
|
while (end >= 0) {
|
||||||
ProcStatsEntry proc = entries.get(end);
|
ProcStatsPackageEntry pkg = pkgEntries.get(end);
|
||||||
final double percentOfWeight = (((double)proc.mWeight) / mMaxWeight) * 100;
|
final double percentOfWeight = (pkg.mRunWeight / mMaxWeight) * 100;
|
||||||
final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100;
|
final double percentOfTime = (((double)pkg.mRunDuration) / memTotalTime) * 100;
|
||||||
if (percentOfWeight >= 1 || percentOfTime >= 25) {
|
if (percentOfWeight >= .01 || percentOfTime >= 25) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
end--;
|
end--;
|
||||||
}
|
}
|
||||||
for (int i=0; i<=end; i++) {
|
for (int i=0; i<=end; i++) {
|
||||||
ProcStatsEntry proc = entries.get(i);
|
ProcStatsPackageEntry pkg = pkgEntries.get(i);
|
||||||
final double percentOfWeight = (((double)proc.mWeight) / mMaxWeight) * 100;
|
final double percentOfWeight = (pkg.mRunWeight / mMaxWeight) * 100;
|
||||||
final double percentOfTime = (((double)proc.mDuration) / memTotalTime) * 100;
|
final double percentOfTime = (((double)pkg.mRunDuration) / memTotalTime) * 100;
|
||||||
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity());
|
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity());
|
||||||
pref.init(null, proc);
|
pref.init(null, pkg);
|
||||||
proc.evaluateTargetPackage(pm, mStats, totals, sEntryCompare, mUseUss,
|
pkg.retrieveUiData(getActivity(), pm);
|
||||||
mStatsType == MENU_TYPE_BACKGROUND);
|
pref.setTitle(pkg.mUiLabel);
|
||||||
proc.retrieveUiData(pm);
|
if (pkg.mUiTargetApp != null) {
|
||||||
pref.setTitle(proc.mUiLabel);
|
pref.setIcon(pkg.mUiTargetApp.loadIcon(pm));
|
||||||
if (proc.mUiTargetApp != null) {
|
|
||||||
pref.setIcon(proc.mUiTargetApp.loadIcon(pm));
|
|
||||||
}
|
}
|
||||||
pref.setOrder(i);
|
pref.setOrder(i);
|
||||||
pref.setPercent(percentOfWeight, percentOfTime);
|
pref.setPercent(percentOfWeight, percentOfTime,
|
||||||
|
(long)(pkg.mRunWeight * mWeightToRam));
|
||||||
mAppListGroup.addPreference(pref);
|
mAppListGroup.addPreference(pref);
|
||||||
if (mStatsType == MENU_TYPE_BACKGROUND) {
|
if (mStatsType == MENU_TYPE_BACKGROUND) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "App " + proc.mUiLabel + ": weightedRam="
|
Log.i(TAG, "App " + pkg.mUiLabel + ": weightedRam="
|
||||||
+ Formatter.formatShortFileSize(getActivity(),
|
+ Formatter.formatShortFileSize(getActivity(),
|
||||||
(proc.mWeight * 1024) / memTotalTime)
|
(long)((pkg.mRunWeight * 1024) / memTotalTime))
|
||||||
+ ", avgRam=" + Formatter.formatShortFileSize(getActivity(),
|
+ ", avgRam=" + Formatter.formatShortFileSize(getActivity(),
|
||||||
(proc.mAvgPss*1024)));
|
(pkg.mAvgRunMem *1024)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user