Implement issue #10895990: Better durations for proc stats
Add new option to select data duration to show, with the default being 3 hours. Reworked how menus are updated to remove redundant code. Switch to using new proc stats service API for retrieving stats, which is more efficient and won't hit IPC limits. Fixed layout for details items to ellipsize long items. Change-Id: I1a0f8a4adf8fc330c2639077323c6379d23ad987
This commit is contained in:
@@ -26,7 +26,9 @@
|
|||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
|
android:ellipsize="middle"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_toStartOf="@+id/value"
|
||||||
android:layout_marginBottom="4dip"
|
android:layout_marginBottom="4dip"
|
||||||
android:layout_marginTop="4dip"
|
android:layout_marginTop="4dip"
|
||||||
android:layout_marginStart="4dip" />
|
android:layout_marginStart="4dip" />
|
||||||
|
@@ -3657,6 +3657,16 @@
|
|||||||
<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 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 -->
|
||||||
|
<string name="menu_proc_stats_duration">Duration</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Menu for process stats to show 3 hours of data -->
|
||||||
|
<string name="menu_duration_3h">3 hours</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Menu for process stats to show 3 hours of data -->
|
||||||
|
<string name="menu_duration_6h">6 hours</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Menu for process stats to show 3 hours of data -->
|
||||||
|
<string name="menu_duration_12h">12 hours</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Menu for process stats to show 3 hours of data -->
|
||||||
|
<string name="menu_duration_1d">1 day</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Menu for process stats to control whether system processes are shown -->
|
<!-- [CHAR LIMIT=NONE] Menu for process stats to control whether system processes are shown -->
|
||||||
<string name="menu_show_system">Show system</string>
|
<string name="menu_show_system">Show system</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Menu for process stats to control whether computation should be based
|
<!-- [CHAR LIMIT=NONE] Menu for process stats to control whether computation should be based
|
||||||
|
@@ -56,15 +56,18 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
private static final String KEY_APP_LIST = "app_list";
|
private static final String KEY_APP_LIST = "app_list";
|
||||||
private static final String KEY_MEM_STATUS = "mem_status";
|
private static final String KEY_MEM_STATUS = "mem_status";
|
||||||
|
|
||||||
private static final int MENU_STATS_REFRESH = Menu.FIRST;
|
private static final int NUM_DURATIONS = 4;
|
||||||
private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 1;
|
|
||||||
private static final int MENU_USE_USS = Menu.FIRST + 2;
|
|
||||||
private static final int MENU_TYPE_BACKGROUND = Menu.FIRST + 3;
|
|
||||||
private static final int MENU_TYPE_FOREGROUND = Menu.FIRST + 4;
|
|
||||||
private static final int MENU_TYPE_CACHED = Menu.FIRST + 5;
|
|
||||||
private static final int MENU_HELP = Menu.FIRST + 6;
|
|
||||||
|
|
||||||
static final int MAX_ITEMS_TO_LIST = 40;
|
private static final int MENU_STATS_REFRESH = Menu.FIRST;
|
||||||
|
private static final int MENU_DURATION = Menu.FIRST + 1;
|
||||||
|
private static final int MENU_SHOW_SYSTEM = MENU_DURATION + NUM_DURATIONS;
|
||||||
|
private static final int MENU_USE_USS = MENU_SHOW_SYSTEM + 1;
|
||||||
|
private static final int MENU_TYPE_BACKGROUND = MENU_USE_USS + 1;
|
||||||
|
private static final int MENU_TYPE_FOREGROUND = MENU_TYPE_BACKGROUND + 1;
|
||||||
|
private static final int MENU_TYPE_CACHED = MENU_TYPE_FOREGROUND + 1;
|
||||||
|
private static final int MENU_HELP = MENU_TYPE_CACHED + 1;
|
||||||
|
|
||||||
|
static final int MAX_ITEMS_TO_LIST = 60;
|
||||||
|
|
||||||
final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
|
final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -85,10 +88,13 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
ProcessStats mStats;
|
ProcessStats mStats;
|
||||||
int mMemState;
|
int mMemState;
|
||||||
|
|
||||||
|
private long mDuration;
|
||||||
|
private long mLastDuration;
|
||||||
private boolean mShowSystem;
|
private boolean mShowSystem;
|
||||||
private boolean mUseUss;
|
private boolean mUseUss;
|
||||||
private int mStatsType;
|
private int mStatsType;
|
||||||
|
|
||||||
|
private MenuItem[] mDurationMenus = new MenuItem[NUM_DURATIONS];
|
||||||
private MenuItem mShowSystemMenu;
|
private MenuItem mShowSystemMenu;
|
||||||
private MenuItem mUseUssMenu;
|
private MenuItem mUseUssMenu;
|
||||||
private MenuItem mTypeBackgroundMenu;
|
private MenuItem mTypeBackgroundMenu;
|
||||||
@@ -101,6 +107,21 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
long mMaxWeight;
|
long mMaxWeight;
|
||||||
long mTotalTime;
|
long mTotalTime;
|
||||||
|
|
||||||
|
// The actual duration value to use for each duration option. Note these
|
||||||
|
// are lower than the actual duration, since our durations are computed in
|
||||||
|
// batches of 3 hours so we want to allow the time we use to be slightly
|
||||||
|
// smaller than the actual time selected instead of bumping up to 3 hours
|
||||||
|
// beyond it.
|
||||||
|
private static final long DURATION_QUANTUM = 3*60*60*1000;
|
||||||
|
private static long[] sDurations = new long[] {
|
||||||
|
3*60*60*1000 - DURATION_QUANTUM/2, 6*60*60*1000 - DURATION_QUANTUM/2,
|
||||||
|
12*60*60*1000 - DURATION_QUANTUM/2, 24*60*60*1000 - DURATION_QUANTUM/2
|
||||||
|
};
|
||||||
|
private static int[] sDurationLabels = new int[] {
|
||||||
|
R.string.menu_duration_3h, R.string.menu_duration_6h,
|
||||||
|
R.string.menu_duration_12h, R.string.menu_duration_1d
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
@@ -115,6 +136,7 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
mUm = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
|
mUm = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
|
||||||
mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
|
mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
|
||||||
mMemStatusPref = mAppListGroup.findPreference(KEY_MEM_STATUS);
|
mMemStatusPref = mAppListGroup.findPreference(KEY_MEM_STATUS);
|
||||||
|
mDuration = icicle != null ? icicle.getLong("duration", sDurations[0]) : sDurations[0];
|
||||||
mShowSystem = icicle != null ? icicle.getBoolean("show_system") : false;
|
mShowSystem = icicle != null ? icicle.getBoolean("show_system") : false;
|
||||||
mUseUss = icicle != null ? icicle.getBoolean("use_uss") : false;
|
mUseUss = icicle != null ? icicle.getBoolean("use_uss") : false;
|
||||||
mStatsType = icicle != null ? icicle.getInt("stats_type", MENU_TYPE_BACKGROUND)
|
mStatsType = icicle != null ? icicle.getInt("stats_type", MENU_TYPE_BACKGROUND)
|
||||||
@@ -136,6 +158,7 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putLong("duration", mDuration);
|
||||||
outState.putBoolean("show_system", mShowSystem);
|
outState.putBoolean("show_system", mShowSystem);
|
||||||
outState.putBoolean("use_uss", mUseUss);
|
outState.putBoolean("use_uss", mUseUss);
|
||||||
outState.putInt("stats_type", mStatsType);
|
outState.putInt("stats_type", mStatsType);
|
||||||
@@ -174,31 +197,31 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
.setAlphabeticShortcut('r');
|
.setAlphabeticShortcut('r');
|
||||||
refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
|
refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
|
||||||
MenuItem.SHOW_AS_ACTION_WITH_TEXT);
|
MenuItem.SHOW_AS_ACTION_WITH_TEXT);
|
||||||
|
SubMenu subMenu = menu.addSubMenu(R.string.menu_proc_stats_duration);
|
||||||
|
for (int i=0; i<NUM_DURATIONS; i++) {
|
||||||
|
mDurationMenus[i] = subMenu.add(0, MENU_DURATION+i, 0, sDurationLabels[i])
|
||||||
|
.setCheckable(true);
|
||||||
|
}
|
||||||
mShowSystemMenu = menu.add(0, MENU_SHOW_SYSTEM, 0, R.string.menu_show_system)
|
mShowSystemMenu = menu.add(0, MENU_SHOW_SYSTEM, 0, R.string.menu_show_system)
|
||||||
.setAlphabeticShortcut('s')
|
.setAlphabeticShortcut('s')
|
||||||
.setCheckable(true)
|
.setCheckable(true);
|
||||||
.setChecked(mShowSystem)
|
|
||||||
.setEnabled(mStatsType == MENU_TYPE_BACKGROUND);
|
|
||||||
mUseUssMenu = menu.add(0, MENU_USE_USS, 0, R.string.menu_use_uss)
|
mUseUssMenu = menu.add(0, MENU_USE_USS, 0, R.string.menu_use_uss)
|
||||||
.setAlphabeticShortcut('s')
|
.setAlphabeticShortcut('u')
|
||||||
.setCheckable(true)
|
.setCheckable(true);
|
||||||
.setChecked(mUseUss);
|
subMenu = menu.addSubMenu(R.string.menu_proc_stats_type);
|
||||||
SubMenu subMenu = menu.addSubMenu(R.string.menu_proc_stats_type);
|
|
||||||
mTypeBackgroundMenu = subMenu.add(0, MENU_TYPE_BACKGROUND, 0,
|
mTypeBackgroundMenu = subMenu.add(0, MENU_TYPE_BACKGROUND, 0,
|
||||||
R.string.menu_proc_stats_type_background)
|
R.string.menu_proc_stats_type_background)
|
||||||
.setAlphabeticShortcut('b')
|
.setAlphabeticShortcut('b')
|
||||||
.setCheckable(true)
|
.setCheckable(true);
|
||||||
.setChecked(mStatsType == MENU_TYPE_BACKGROUND);
|
|
||||||
mTypeForegroundMenu = subMenu.add(0, MENU_TYPE_FOREGROUND, 0,
|
mTypeForegroundMenu = subMenu.add(0, MENU_TYPE_FOREGROUND, 0,
|
||||||
R.string.menu_proc_stats_type_foreground)
|
R.string.menu_proc_stats_type_foreground)
|
||||||
.setAlphabeticShortcut('f')
|
.setAlphabeticShortcut('f')
|
||||||
.setCheckable(true)
|
.setCheckable(true);
|
||||||
.setChecked(mStatsType == MENU_TYPE_FOREGROUND);
|
|
||||||
mTypeCachedMenu = subMenu.add(0, MENU_TYPE_CACHED, 0,
|
mTypeCachedMenu = subMenu.add(0, MENU_TYPE_CACHED, 0,
|
||||||
R.string.menu_proc_stats_type_cached)
|
R.string.menu_proc_stats_type_cached)
|
||||||
.setAlphabeticShortcut('c')
|
.setCheckable(true);
|
||||||
.setCheckable(true)
|
|
||||||
.setChecked(mStatsType == MENU_TYPE_CACHED);
|
updateMenus();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
String helpUrl;
|
String helpUrl;
|
||||||
@@ -209,9 +232,44 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateMenus() {
|
||||||
|
int closestIndex = 0;
|
||||||
|
long closestDelta = Math.abs(sDurations[0]-mDuration);
|
||||||
|
for (int i=1; i<NUM_DURATIONS; i++) {
|
||||||
|
long delta = Math.abs(sDurations[i]-mDuration);
|
||||||
|
if (delta < closestDelta) {
|
||||||
|
closestDelta = delta;
|
||||||
|
closestIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=0; i<NUM_DURATIONS; i++) {
|
||||||
|
if (mDurationMenus[i] != null) {
|
||||||
|
mDurationMenus[i].setChecked(i == closestIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDuration = sDurations[closestIndex];
|
||||||
|
if (mShowSystemMenu != null) {
|
||||||
|
mShowSystemMenu.setChecked(mShowSystem);
|
||||||
|
mShowSystemMenu.setEnabled(mStatsType == MENU_TYPE_BACKGROUND);
|
||||||
|
}
|
||||||
|
if (mUseUssMenu != null) {
|
||||||
|
mUseUssMenu.setChecked(mUseUss);
|
||||||
|
}
|
||||||
|
if (mTypeBackgroundMenu != null) {
|
||||||
|
mTypeBackgroundMenu.setChecked(mStatsType == MENU_TYPE_BACKGROUND);
|
||||||
|
}
|
||||||
|
if (mTypeForegroundMenu != null) {
|
||||||
|
mTypeForegroundMenu.setChecked(mStatsType == MENU_TYPE_FOREGROUND);
|
||||||
|
}
|
||||||
|
if (mTypeCachedMenu != null) {
|
||||||
|
mTypeCachedMenu.setChecked(mStatsType == MENU_TYPE_CACHED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
final int id = item.getItemId();
|
||||||
|
switch (id) {
|
||||||
case MENU_STATS_REFRESH:
|
case MENU_STATS_REFRESH:
|
||||||
mStats = null;
|
mStats = null;
|
||||||
refreshStats();
|
refreshStats();
|
||||||
@@ -231,6 +289,10 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
refreshStats();
|
refreshStats();
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
if (id >= MENU_DURATION && id < (MENU_DURATION+NUM_DURATIONS)) {
|
||||||
|
mDuration = sDurations[id-MENU_DURATION];
|
||||||
|
refreshStats();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,25 +320,10 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private void refreshStats() {
|
private void refreshStats() {
|
||||||
if (mStats == null) {
|
updateMenus();
|
||||||
load();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mShowSystemMenu != null) {
|
if (mStats == null || mLastDuration != mDuration) {
|
||||||
mShowSystemMenu.setChecked(mShowSystem);
|
load();
|
||||||
mShowSystemMenu.setEnabled(mStatsType == MENU_TYPE_BACKGROUND);
|
|
||||||
}
|
|
||||||
if (mUseUssMenu != null) {
|
|
||||||
mUseUssMenu.setChecked(mUseUss);
|
|
||||||
}
|
|
||||||
if (mTypeBackgroundMenu != null) {
|
|
||||||
mTypeBackgroundMenu.setChecked(mStatsType == MENU_TYPE_BACKGROUND);
|
|
||||||
}
|
|
||||||
if (mTypeForegroundMenu != null) {
|
|
||||||
mTypeForegroundMenu.setChecked(mStatsType == MENU_TYPE_FOREGROUND);
|
|
||||||
}
|
|
||||||
if (mTypeCachedMenu != null) {
|
|
||||||
mTypeCachedMenu.setChecked(mStatsType == MENU_TYPE_CACHED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] stats;
|
int[] stats;
|
||||||
@@ -390,7 +437,7 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
ProcStatsEntry proc = procs.get(i);
|
ProcStatsEntry proc = procs.get(i);
|
||||||
final double percentOfWeight = (((double)proc.mWeight) / maxWeight) * 100;
|
final double percentOfWeight = (((double)proc.mWeight) / maxWeight) * 100;
|
||||||
final double percentOfTime = (((double)proc.mDuration) / mTotalTime) * 100;
|
final double percentOfTime = (((double)proc.mDuration) / mTotalTime) * 100;
|
||||||
if (percentOfWeight < 2) break;
|
if (percentOfWeight < 1) break;
|
||||||
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null, proc);
|
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null, proc);
|
||||||
proc.evaluateTargetPackage(mStats, totals, sEntryCompare, mUseUss,
|
proc.evaluateTargetPackage(mStats, totals, sEntryCompare, mUseUss,
|
||||||
mStatsType == MENU_TYPE_BACKGROUND);
|
mStatsType == MENU_TYPE_BACKGROUND);
|
||||||
@@ -425,44 +472,18 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
|
|
||||||
private void load() {
|
private void load() {
|
||||||
try {
|
try {
|
||||||
|
mLastDuration = mDuration;
|
||||||
mMemState = mProcessStats.getCurrentMemoryState();
|
mMemState = mProcessStats.getCurrentMemoryState();
|
||||||
ArrayList<ParcelFileDescriptor> fds = new ArrayList<ParcelFileDescriptor>();
|
ParcelFileDescriptor pfd = mProcessStats.getStatsOverTime(mDuration);
|
||||||
byte[] data = mProcessStats.getCurrentStats(fds);
|
mStats = new ProcessStats(false);
|
||||||
Parcel parcel = Parcel.obtain();
|
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
|
||||||
parcel.unmarshall(data, 0, data.length);
|
mStats.read(is);
|
||||||
parcel.setDataPosition(0);
|
try {
|
||||||
mStats = ProcessStats.CREATOR.createFromParcel(parcel);
|
is.close();
|
||||||
int i = fds.size()-1;
|
} catch (IOException e) {
|
||||||
while (i >= 0 && (mStats.mTimePeriodEndRealtime-mStats.mTimePeriodStartRealtime)
|
|
||||||
< (24*60*60*1000)) {
|
|
||||||
Log.i(TAG, "Not enough data, loading next file @ " + i);
|
|
||||||
ProcessStats stats = new ProcessStats(false);
|
|
||||||
InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(fds.get(i));
|
|
||||||
stats.read(stream);
|
|
||||||
try {
|
|
||||||
stream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
if (stats.mReadError == null) {
|
|
||||||
mStats.add(stats);
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("Added stats: ");
|
|
||||||
sb.append(stats.mTimePeriodStartClockStr);
|
|
||||||
sb.append(", over ");
|
|
||||||
TimeUtils.formatDuration(
|
|
||||||
stats.mTimePeriodEndRealtime-stats.mTimePeriodStartRealtime, sb);
|
|
||||||
Log.i(TAG, sb.toString());
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Read error: " + stats.mReadError);
|
|
||||||
}
|
|
||||||
i--;
|
|
||||||
}
|
}
|
||||||
while (i >= 0) {
|
if (mStats.mReadError != null) {
|
||||||
try {
|
Log.w(TAG, "Failure reading process stats: " + mStats.mReadError);
|
||||||
fds.get(i).close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
i--;
|
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "RemoteException:", e);
|
Log.e(TAG, "RemoteException:", e);
|
||||||
|
Reference in New Issue
Block a user