Initial rough stab at a proc stats UI.

You see procs, and you see some stats.

Change-Id: I91c86d198fd5e64a41c72901e150466b3c602caf
This commit is contained in:
Dianne Hackborn
2013-08-08 12:57:53 -07:00
parent dcd15ee04b
commit c6d658e37d
7 changed files with 370 additions and 1 deletions

View File

@@ -3545,6 +3545,16 @@
<!-- Label for mediaserver process --> <!-- Label for mediaserver process -->
<string name="process_mediaserver_label">Mediaserver</string> <string name="process_mediaserver_label">Mediaserver</string>
<!-- Process Stats strings -->
<skip />
<!-- Activity title for Process Stats summary -->
<string name="process_stats_summary_title">Process Stats</string>
<!-- Activity title summary for Process Stats summary -->
<string name="process_stats_summary">Geeky stats about running processes</string>
<!-- Battery usage since unplugged -->
<string name="app_memory_use">Memory use</string>
<!-- Voice input/output settings --><skip /> <!-- Voice input/output settings --><skip />
<!-- Title of setting on main settings screen. This item will take the user to the screen to tweak settings related to speech functionality --> <!-- Title of setting on main settings screen. This item will take the user to the screen to tweak settings related to speech functionality -->
<string name="voice_input_output_settings">Voice input &amp; output</string> <string name="voice_input_output_settings">Voice input &amp; output</string>

View File

@@ -61,6 +61,12 @@
android:title="@string/bt_hci_snoop_log" android:title="@string/bt_hci_snoop_log"
android:summary="@string/bt_hci_snoop_log_summary"/> android:summary="@string/bt_hci_snoop_log_summary"/>
<PreferenceScreen android:key="proc_stats"
android:title="@string/process_stats_summary_title"
android:summary="@string/process_stats_summary"
android:fragment="com.android.settings.applications.ProcessStatsUi">
</PreferenceScreen>
<PreferenceCategory android:key="debug_debugging_category" <PreferenceCategory android:key="debug_debugging_category"
android:title="@string/debug_debugging_category"> android:title="@string/debug_debugging_category">

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/app_memory_use"
android:key="app_list">
<Preference
style="?android:attr/preferenceInformationStyle"
android:key="mem_status"
android:persistent="false"
/>
</PreferenceScreen>

View File

@@ -1283,6 +1283,8 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
writeDebugLayoutOptions(); writeDebugLayoutOptions();
} else if (preference == mForceRtlLayout) { } else if (preference == mForceRtlLayout) {
writeForceRtlOptions(); writeForceRtlOptions();
} else {
return super.onPreferenceTreeClick(preferenceScreen, preference);
} }
return false; return false;

View File

@@ -64,6 +64,7 @@ import com.android.settings.accounts.AuthenticatorHelper;
import com.android.settings.accounts.ManageAccountsSettings; import com.android.settings.accounts.ManageAccountsSettings;
import com.android.settings.applications.AppOpsSummary; import com.android.settings.applications.AppOpsSummary;
import com.android.settings.applications.ManageApplications; import com.android.settings.applications.ManageApplications;
import com.android.settings.applications.ProcessStatsUi;
import com.android.settings.bluetooth.BluetoothEnabler; import com.android.settings.bluetooth.BluetoothEnabler;
import com.android.settings.bluetooth.BluetoothSettings; import com.android.settings.bluetooth.BluetoothSettings;
import com.android.settings.deviceinfo.Memory; import com.android.settings.deviceinfo.Memory;
@@ -310,6 +311,7 @@ public class Settings extends PreferenceActivity
DisplaySettings.class.getName(), DisplaySettings.class.getName(),
DeviceInfoSettings.class.getName(), DeviceInfoSettings.class.getName(),
ManageApplications.class.getName(), ManageApplications.class.getName(),
ProcessStatsUi.class.getName(),
NotificationStation.class.getName(), NotificationStation.class.getName(),
AppOpsSummary.class.getName(), AppOpsSummary.class.getName(),
LocationSettings.class.getName(), LocationSettings.class.getName(),
@@ -331,7 +333,7 @@ public class Settings extends PreferenceActivity
UserSettings.class.getName(), UserSettings.class.getName(),
NotificationAccessSettings.class.getName(), NotificationAccessSettings.class.getName(),
ManageAccountsSettings.class.getName(), ManageAccountsSettings.class.getName(),
PrintingSettings.class.getName() PrintingSettings.class.getName(),
}; };
@Override @Override

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2013 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.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.preference.Preference;
import android.text.format.Formatter;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.settings.R;
public class ProcessStatsPreference extends Preference {
private int mProgress;
private CharSequence mProgressText;
public ProcessStatsPreference(Context context, Drawable icon) {
super(context);
setLayoutResource(R.layout.app_percentage_item);
setIcon(icon != null ? icon : new ColorDrawable(0));
}
public void setPercent(double percentOfTotal, long pss) {
mProgress = (int) Math.ceil(percentOfTotal);
mProgressText = pss > 0 ? Formatter.formatShortFileSize(getContext(), pss) : "";
notifyChanged();
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
final ProgressBar progress = (ProgressBar) view.findViewById(android.R.id.progress);
progress.setProgress(mProgress);
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
text1.setText(mProgressText);
}
}

View File

@@ -0,0 +1,269 @@
/*
* Copyright (C) 2013 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.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.android.internal.app.IProcessStats;
import com.android.internal.app.ProcessStats;
import com.android.settings.R;
import java.io.IOException;
import java.util.ArrayList;
public class ProcessStatsUi extends PreferenceFragment {
private static final String TAG = "ProcessStatsUi";
private static final boolean DEBUG = false;
private static final String KEY_APP_LIST = "app_list";
private static final String KEY_MEM_STATUS = "mem_status";
private static final int MENU_STATS_REFRESH = Menu.FIRST;
private static final int MENU_HELP = Menu.FIRST + 2;
static final int MAX_ITEMS_TO_LIST = 20;
private static ProcessStats sStatsXfer;
IProcessStats mProcessStats;
UserManager mUm;
ProcessStats mStats;
private PreferenceGroup mAppListGroup;
private Preference mMemStatusPref;
long mTotalTime;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (icicle != null) {
mStats = sStatsXfer;
}
addPreferencesFromResource(R.xml.process_stats_summary);
mProcessStats = IProcessStats.Stub.asInterface(
ServiceManager.getService(ProcessStats.SERVICE_NAME));
mUm = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
mMemStatusPref = mAppListGroup.findPreference(KEY_MEM_STATUS);
setHasOptionsMenu(true);
}
@Override
public void onResume() {
super.onResume();
refreshStats();
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
if (getActivity().isChangingConfigurations()) {
sStatsXfer = mStats;
}
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (!(preference instanceof ProcessStatsPreference)) {
return false;
}
/*
PreferenceActivity pa = (PreferenceActivity)getActivity();
pa.startPreferencePanel(PowerUsageDetail.class.getName(), args,
R.string.details_title, null, null, 0);
*/
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
MenuItem refresh = menu.add(0, MENU_STATS_REFRESH, 0, R.string.menu_stats_refresh)
.setIcon(R.drawable.ic_menu_refresh_holo_dark)
.setAlphabeticShortcut('r');
refresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
MenuItem.SHOW_AS_ACTION_WITH_TEXT);
/*
String helpUrl;
if (!TextUtils.isEmpty(helpUrl = getResources().getString(R.string.help_url_battery))) {
final MenuItem help = menu.add(0, MENU_HELP, 0, R.string.help_label);
HelpUtils.prepareHelpMenuItem(getActivity(), help, helpUrl);
}
*/
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_STATS_REFRESH:
mStats = null;
refreshStats();
return true;
default:
return false;
}
}
private void addNotAvailableMessage() {
Preference notAvailable = new Preference(getActivity());
notAvailable.setTitle(R.string.power_usage_not_available);
mAppListGroup.addPreference(notAvailable);
}
private void refreshStats() {
if (mStats == null) {
load();
}
mAppListGroup.removeAll();
mAppListGroup.setOrderingAsAdded(false);
mMemStatusPref.setOrder(-2);
mAppListGroup.addPreference(mMemStatusPref);
/*
BatteryHistoryPreference hist = new BatteryHistoryPreference(getActivity(), mStats);
hist.setOrder(-1);
mAppListGroup.addPreference(hist);
*/
ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ,
ProcessStats.BACKGROUND_PROC_STATES);
long now = SystemClock.uptimeMillis();
mTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations,
mStats.mMemFactor, mStats.mStartTime, now);
ArrayList<ProcessStats.ProcessState> procs = mStats.collectProcessesLocked(
ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ,
ProcessStats.BACKGROUND_PROC_STATES, now, null);
final PackageManager pm = getActivity().getPackageManager();
for (int i=0, N=(procs != null ? procs.size() : 0); i<N; i++) {
ProcessStats.ProcessState ps = procs.get(i);
final double percentOfTotal = (((double)ps.mTmpTotalTime) / mTotalTime) * 100;
if (percentOfTotal < 1) continue;
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null);
ApplicationInfo targetApp = null;
String label = ps.mName;
if (ps.mCommonProcess == ps) {
// Only one app associated with this process.
try {
targetApp = pm.getApplicationInfo(ps.mPackage,
PackageManager.GET_DISABLED_COMPONENTS |
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
PackageManager.GET_UNINSTALLED_PACKAGES);
String name = targetApp.loadLabel(pm).toString();
if (ps.mName.equals(ps.mPackage)) {
label = name;
} else {
if (ps.mName.startsWith(ps.mPackage)) {
int off = ps.mPackage.length();
if (ps.mName.length() > off) {
off++;
}
label = name + " (" + ps.mName.substring(off) + ")";
} else {
label = name + " (" + ps.mName + ")";
}
}
} catch (PackageManager.NameNotFoundException e) {
}
}
if (targetApp == null) {
String[] packages = pm.getPackagesForUid(ps.mUid);
for (String pkgName : packages) {
try {
final PackageInfo pi = pm.getPackageInfo(pkgName,
PackageManager.GET_DISABLED_COMPONENTS |
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS |
PackageManager.GET_UNINSTALLED_PACKAGES);
if (pi.sharedUserLabel != 0) {
targetApp = pi.applicationInfo;
final CharSequence nm = pm.getText(pkgName,
pi.sharedUserLabel, pi.applicationInfo);
if (nm != null) {
label = nm.toString() + " (" + ps.mName + ")";
} else {
label = targetApp.loadLabel(pm).toString() + " (" + ps.mName + ")";
}
break;
}
} catch (PackageManager.NameNotFoundException e) {
}
}
}
pref.setTitle(label);
if (targetApp != null) {
pref.setIcon(targetApp.loadIcon(pm));
}
pref.setOrder(N+100-i);
ProcessStats.computeProcessData(ps, totals, now);
pref.setPercent(percentOfTotal, totals.avgPss * 1024);
mAppListGroup.addPreference(pref);
if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) break;
}
}
private void load() {
try {
ArrayList<ParcelFileDescriptor> fds = new ArrayList<ParcelFileDescriptor>();
byte[] data = mProcessStats.getCurrentStats(fds);
for (int i=0; i<fds.size(); i++) {
try {
fds.get(i).close();
} catch (IOException e) {
}
}
Parcel parcel = Parcel.obtain();
parcel.unmarshall(data, 0, data.length);
parcel.setDataPosition(0);
mStats = ProcessStats.CREATOR.createFromParcel(parcel);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException:", e);
}
}
}