Move process stats screen into memory screen.

- Move process stats from developer options to top level
   settings item.
 - Some minor UI changes to the top of the page
 - Major UI updates to detail page, now shows info with processes
   as pref categories and services as prefs, with a way to kill
   them (taken from Running Services page).
 - Some major refactorings in code, in attempt to make it more
   usable
 - Added color bar on per app basis to visualize the avg/max
   relationship
 - Updated the way avg is calculated across multiple entries in
   ProcStatsPackageEntry to be more accurate
 - Change the way max memory is calculated in
   ProcStatsPackageEntry to be less accurate but more useful

Bug: 19443802
Change-Id: Ia6aaabe42c415c50997a09bfb814a6f6e5731772
This commit is contained in:
Jason Monk
2015-03-25 09:46:30 -04:00
parent c5184ff1af
commit 2583fc1e06
23 changed files with 1330 additions and 783 deletions

View File

@@ -0,0 +1,25 @@
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
android:fillColor="#FF000000"
android:pathData="M24.0,4.0C12.9,4.0 4.0,12.9 4.0,24.0s8.9,20.0 20.0,20.0c11.1,0.0 20.0,-8.9 20.0,-20.0S35.1,4.0 24.0,4.0zM34.0,31.2L31.2,34.0L24.0,26.8L16.8,34.0L14.0,31.2l7.2,-7.2L14.0,16.8l2.8,-2.8l7.2,7.2l7.2,-7.2l2.8,2.8L26.8,24.0L34.0,31.2z"/>
</vector>

View File

@@ -0,0 +1,37 @@
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M6.0,4.0l0.0,16.0 12.0,0.0 0.0,-16.0 -12.0,0.0z
M6.0,5.25l0,1.5 -3,0 0,-1.5 3,0z
M6.0,9.25l0,1.5 -3,0 0,-1.5 3,0z
M6.0,13.25l0,1.5 -3,0 0,-1.5 3,0z
M6.0,17.25l0,1.5 -3,0 0,-1.5 3,0z
M21.0,5.25l0,1.5 -3,0 0,-1.5 3,0z
M21.0,9.25l0,1.5 -3,0 0,-1.5 3,0z
M21.0,13.25l0,1.5 -3,0 0,-1.5 3,0z
M21.0,17.25l0,1.5 -3,0 0,-1.5 3,0z
M11.5,14.5l1,0 0,3 -1,0 0,-3z
M13.25,14.5l1,0 0,3 -1,0 0,-3z
M15.0,14.5l1,0 0,3 -1,0 0,-3z
"
android:fillColor="#ff009587" />
</vector>

View File

@@ -0,0 +1,74 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="8dip"
android:paddingBottom="8dip">
<ImageView
android:id="@android:id/icon"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
android:layout_marginEnd="8dip"
android:scaleType="centerInside"
android:contentDescription="@null"
android:duplicateParentState="true" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:duplicateParentState="true">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textAlignment="viewStart"
android:duplicateParentState="true" />
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
android:textColor="?android:attr/textColorSecondary"
android:textAlignment="viewStart"
android:duplicateParentState="true" />
</LinearLayout>
<com.android.settings.applications.LinearColorBar
android:id="@+id/linear_color_bar"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:duplicateParentState="true" />
</LinearLayout>

View File

@@ -0,0 +1,22 @@
<?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.
-->
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:src="@drawable/ic_cancel"
/>

58
res/layout/memory_key.xml Normal file
View File

@@ -0,0 +1,58 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|end"
android:layout_marginBottom="5dp" >
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:scaleType="centerInside"
android:src="@color/memory_avg_use"
android:contentDescription="@null" />
<TextView
android:id="@+id/memory_avg"
android:text="@string/memory_avg_use"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
android:textColor="?android:attr/textColorSecondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp" />
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:scaleType="centerInside"
android:src="@color/memory_max_use"
android:contentDescription="@null" />
<TextView
android:id="@+id/memory_max"
android:text="@string/memory_max_use"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
android:textColor="?android:attr/textColorSecondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp" />
</LinearLayout>

View File

@@ -0,0 +1,55 @@
<?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/all_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:orientation="vertical">
<TextView
android:id="@+id/memory_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
/>
<com.android.settings.applications.LinearColorBar
android:id="@+id/color_bar"
android:layout_width="match_parent"
android:layout_height="30dp"
/>
<TextView
android:id="@+id/memory_used"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="10dp"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:textColor="?android:attr/textColorSecondary"
/>
<include layout="@layout/memory_key" />
</LinearLayout>

View File

@@ -0,0 +1,39 @@
<?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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dip"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="16dip">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.Material.Body2"
android:textColor="?android:attr/colorAccent" />
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:textAppearance="@android:style/TextAppearance.Material.Body2"
android:textColor="?android:attr/colorAccent" />
</RelativeLayout>

View File

@@ -14,68 +14,34 @@
limitations under the License.
-->
<ScrollView
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/all_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbarStyle="@integer/preference_scrollbar_style">
android:orientation="vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<LinearLayout
android:id="@+id/all_details"
<com.android.settings.applications.LinearColorBar
android:id="@+id/color_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:orientation="vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
android:layout_height="40dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="10dp"
/>
<include layout="@layout/app_percentage_item" />
<include layout="@layout/memory_key" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Force stop and report buttons -->
<LinearLayout
android:id="@+id/two_buttons_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="6dip"
android:orientation="vertical">
<include layout="@layout/two_buttons_panel"/>
</LinearLayout>
<LinearLayout
android:id="@+id/processes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Insert process items here -->
</LinearLayout>
<TextView
android:id="@+id/services_label"
style="?android:attr/listSeparatorTextViewStyle"
android:text="@string/services_subtitle" />
<LinearLayout
android:id="@+id/services"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Insert service items here -->
</LinearLayout>
</LinearLayout>
<!-- Force stop and report buttons -->
<LinearLayout
android:id="@+id/two_buttons_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="6dip"
android:orientation="vertical">
<include layout="@layout/two_buttons_panel"/>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@@ -86,4 +86,9 @@
<color name="voice_interaction_highlight">#33b5e5</color>
<drawable name="fp_enrollment_header_landscape">#009688</drawable>
<color name="memory_avg_use">#ff384248</color>
<color name="memory_max_use">#ff009587</color>
<color name="memory_remaining">#ffced7db</color>
</resources>

View File

@@ -4188,8 +4188,13 @@
<!-- [CHAR LIMIT=NONE] Label for process stats, duration of time the stats are over;
timeDuration is a duration such as "1h 30m" -->
<string name="process_stats_total_duration"><xliff:g id="usedRam">%1$s</xliff:g>
of <xliff:g id="totalRam">%2$s</xliff:g> used over
of <xliff:g id="totalRam">%2$s</xliff:g> used over last
<xliff:g id="timeDuration">%3$s</xliff:g></string>
<!-- [CHAR LIMIT=NONE] Label for process stats, duration of time the stats are over;
timeDuration is a duration such as "1h 30m" -->
<string name="process_stats_total_duration_percentage"><xliff:g id="percent" example="50%">%1$s</xliff:g>
of RAM used over
<xliff:g id="timeDuration">%2$s</xliff:g></string>
<!-- [CHAR LIMIT=NONE] Label for process stats, text for stats type -->
<string name="process_stats_type_background">Background</string>
<!-- [CHAR LIMIT=NONE] Label for process stats, text for stats type -->
@@ -4197,7 +4202,7 @@
<!-- [CHAR LIMIT=NONE] Label for process stats, text for stats type -->
<string name="process_stats_type_cached">Cached</string>
<!-- [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">Memory is
<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>
@@ -4251,6 +4256,9 @@
<string name="menu_show_system">Show system</string>
<!-- [CHAR LIMIT=NONE] Menu for manage apps to control whether system processes are hidden -->
<string name="menu_hide_system">Hide system</string>
<!-- [CHAR LIMIT=NONE] Menu for process stats to control whether stats are shown
as percentages-->
<string name="menu_show_percentage">Show percentages</string>
<!-- [CHAR LIMIT=NONE] Menu for process stats to control whether computation should be based
on Uss (Unique Set Size) instead of Pss (Proportional Set Size) -->
<string name="menu_use_uss">Use Uss</string>
@@ -6498,4 +6506,40 @@
<!-- Description of the usage access setting [CHAR LIMIT=NONE] -->
<string name="usage_access_description">Usage access allows an app to track what other apps you\'re using and how often, as well as your carrier, language settings, and other details.</string>
<!-- Title for screen showing recent memory usage of device [CHAR LIMIT=30]-->
<string name="memory_settings_title">Memory</string>
<!-- Title for screen showing recent memory usage of specific app [CHAR LIMIT=30]-->
<string name="memory_details_title">Memory details</string>
<!-- Description of app always running [CHAR LIMIT=45] -->
<string name="always_running">Always running</string>
<!-- Description of app sometimes running [CHAR LIMIT=45] -->
<string name="sometimes_running">Sometimes running</string>
<!-- Description of app rarely running [CHAR LIMIT=45] -->
<string name="rarely_running">Rarely running</string>
<!-- Maximum memory usage key [CHAR LIMIT=25] -->
<string name="memory_max_use">Maximum</string>
<!-- Average memory usage key [CHAR LIMIT=25] -->
<string name="memory_avg_use">Average</string>
<!-- Maximum memory used by an app [CHAR LIMIT=25] -->
<string name="memory_max_desc">Maximum <xliff:g id="memory" example="30MB">%1$s</xliff:g></string>
<!-- Average memory used by an app [CHAR LIMIT=25] -->
<string name="memory_avg_desc">Average <xliff:g id="memory" example="30MB">%1$s</xliff:g></string>
<!-- Formatting for memory description [CHAR LIMIT=25] -->
<string name="memory_use_running_format"><xliff:g id="memory" example="30MB">%1$s</xliff:g> / <xliff:g id="running" example="Always running">%2$s</xliff:g></string>
<!-- Label for process (singular) [CHAR LIMIT=25] -->
<string name="process">Process</string>
<!-- Label for process [CHAR LIMIT=25] -->
<string name="process_format">Process <xliff:g id="count" example="3">%1$d</xliff:g></string>
</resources>

View File

@@ -0,0 +1,24 @@
<?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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/memory_details_title">
<com.android.settings.applications.LayoutPreference
android:key="details_header"
android:layout="@layout/process_stats_details" />
</PreferenceScreen>

View File

@@ -134,6 +134,14 @@
android:icon="@drawable/ic_settings_multiuser"
/>
<!-- Memory -->
<dashboard-tile
android:id="@+id/manage_memory"
android:title="@string/memory_settings_title"
android:fragment="com.android.settings.applications.ProcessStatsUi"
android:icon="@drawable/ic_settings_memory"
/>
<!-- Manage NFC payment apps -->
<dashboard-tile
android:id="@+id/nfc_payment_settings"

View File

@@ -54,12 +54,6 @@
android:title="@string/oem_unlock_enable"
android:summary="@string/oem_unlock_enable_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>
<PreferenceScreen
android:key="running_apps"
android:title="@string/runningservices_settings_title"

View File

@@ -14,12 +14,11 @@
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
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/app_memory_use"
android:key="app_list">
<com.android.settings.applications.LayoutPreference
android:key="status_header"
android:layout="@layout/proc_stats_ui" />
</PreferenceScreen>

View File

@@ -0,0 +1,69 @@
/*
* 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;
import android.content.Context;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
public class CancellablePreference extends Preference implements OnClickListener {
private boolean mCancellable;
private OnCancelListener mListener;
public CancellablePreference(Context context) {
super(context);
setWidgetLayoutResource(R.layout.cancel_pref_widget);
}
public CancellablePreference(Context context, AttributeSet attrs) {
super(context, attrs);
setWidgetLayoutResource(R.layout.cancel_pref_widget);
}
public void setCancellable(boolean isCancellable) {
mCancellable = isCancellable;
notifyChanged();
}
public void setOnCancelListener(OnCancelListener listener) {
mListener = listener;
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
ImageView cancel = (ImageView) view.findViewById(R.id.cancel);
cancel.setVisibility(mCancellable ? View.VISIBLE : View.INVISIBLE);
cancel.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.onCancel(this);
}
}
public interface OnCancelListener {
void onCancel(CancellablePreference preference);
}
}

View File

@@ -164,8 +164,6 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
private static final String SHOW_ALL_ANRS_KEY = "show_all_anrs";
private static final String PROCESS_STATS = "proc_stats";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
private static final String TERMINAL_APP_PACKAGE = "com.android.terminal";
@@ -246,7 +244,6 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
private SwitchPreference mShowAllANRs;
private PreferenceScreen mProcessStats;
private final ArrayList<Preference> mAllPrefs = new ArrayList<Preference>();
private final ArrayList<SwitchPreference> mResetSwitchPrefs
@@ -397,9 +394,6 @@ public class DevelopmentSettings extends SettingsPreferenceFragment
mAllPrefs.add(hdcpChecking);
removePreferenceForProduction(hdcpChecking);
}
mProcessStats = (PreferenceScreen) findPreference(PROCESS_STATS);
mAllPrefs.add(mProcessStats);
}
private ListPreference addListPreference(String prefKey) {

View File

@@ -340,6 +340,7 @@ public class SettingsActivity extends Activity
ZenModePrioritySettings.class.getName(),
ZenModeScheduleRuleSettings.class.getName(),
ZenModeExternalRuleSettings.class.getName(),
ProcessStatsUi.class.getName(),
};

View File

@@ -0,0 +1,408 @@
/*
* 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.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.app.IProcessStats;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.ProcessStats;
import com.android.internal.app.ProcessStats.ProcessDataCollection;
import com.android.internal.app.ProcessStats.TotalMemoryUseCollection;
import com.android.internal.util.MemInfoReader;
import com.android.settings.R;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class ProcStatsData {
private static final String TAG = "ProcStatsManager";
private static final boolean DEBUG = ProcessStatsUi.DEBUG;
private static ProcessStats sStatsXfer;
private PackageManager mPm;
private Context mContext;
private long memTotalTime;
private IProcessStats mProcessStats;
private ProcessStats mStats;
private int mMemState;
private boolean mUseUss;
private long mDuration;
private int[] mMemStates;
private int[] mStates;
private MemInfo mMemInfo;
private ArrayList<ProcStatsPackageEntry> pkgEntries;
public ProcStatsData(Context context, boolean useXfer) {
mContext = context;
mPm = context.getPackageManager();
mProcessStats = IProcessStats.Stub.asInterface(
ServiceManager.getService(ProcessStats.SERVICE_NAME));
mMemStates = ProcessStats.ALL_MEM_ADJ;
mStates = ProcessStats.BACKGROUND_PROC_STATES;
if (useXfer) {
mStats = sStatsXfer;
}
}
public void setTotalTime(int totalTime) {
memTotalTime = totalTime;
}
public void xferStats() {
sStatsXfer = mStats;
}
public void setMemStates(int[] memStates) {
mMemStates = memStates;
refreshStats(false);
}
public void setStats(int[] stats) {
this.mStates = stats;
refreshStats(false);
}
public int getMemState() {
return mMemState;
}
public MemInfo getMemInfo() {
return mMemInfo;
}
public long getElapsedTime() {
return mStats.mTimePeriodEndRealtime - mStats.mTimePeriodStartRealtime;
}
public void setDuration(long duration) {
if (duration != mDuration) {
mDuration = duration;
refreshStats(true);
}
}
public long getDuration() {
return mDuration;
}
public List<ProcStatsPackageEntry> getEntries() {
return pkgEntries;
}
public void refreshStats(boolean forceLoad) {
if (mStats == null || forceLoad) {
load();
}
pkgEntries = new ArrayList<>();
long now = SystemClock.uptimeMillis();
memTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations,
mStats.mMemFactor, mStats.mStartTime, now);
ProcessStats.TotalMemoryUseCollection totalMem = new ProcessStats.TotalMemoryUseCollection(
ProcessStats.ALL_SCREEN_ADJ, mMemStates);
mStats.computeTotalMemoryUse(totalMem, now);
mMemInfo = new MemInfo(mContext, totalMem, memTotalTime);
ProcessDataCollection bgTotals = new ProcessDataCollection(
ProcessStats.ALL_SCREEN_ADJ, mMemStates, mStates);
ProcessDataCollection runTotals = new ProcessDataCollection(
ProcessStats.ALL_SCREEN_ADJ, mMemStates, ProcessStats.NON_CACHED_PROC_STATES);
createPkgMap(getProcs(bgTotals, runTotals), bgTotals, runTotals);
ProcStatsPackageEntry osPkg = createOsEntry(bgTotals, runTotals, totalMem,
mMemInfo.baseCacheRam);
pkgEntries.add(osPkg);
}
private void createPkgMap(ArrayList<ProcStatsEntry> procEntries, ProcessDataCollection bgTotals,
ProcessDataCollection runTotals) {
// Combine processes into packages.
ArrayMap<String, ProcStatsPackageEntry> pkgMap = new ArrayMap<>();
for (int i = procEntries.size() - 1; i >= 0; i--) {
ProcStatsEntry proc = procEntries.get(i);
proc.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
ProcStatsPackageEntry pkg = pkgMap.get(proc.mBestTargetPackage);
if (pkg == null) {
pkg = new ProcStatsPackageEntry(proc.mBestTargetPackage, memTotalTime);
pkgMap.put(proc.mBestTargetPackage, pkg);
pkgEntries.add(pkg);
}
pkg.addEntry(proc);
}
}
private ProcStatsPackageEntry createOsEntry(ProcessDataCollection bgTotals,
ProcessDataCollection runTotals, TotalMemoryUseCollection totalMem, long baseCacheRam) {
// Add in fake entry representing the OS itself.
ProcStatsPackageEntry osPkg = new ProcStatsPackageEntry("os", memTotalTime);
ProcStatsEntry osEntry;
if (totalMem.sysMemNativeWeight > 0) {
osEntry = new ProcStatsEntry("os", 0,
mContext.getString(R.string.process_stats_os_native), memTotalTime,
(long) (totalMem.sysMemNativeWeight / memTotalTime));
osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
osPkg.addEntry(osEntry);
}
if (totalMem.sysMemKernelWeight > 0) {
osEntry = new ProcStatsEntry("os", 0,
mContext.getString(R.string.process_stats_os_kernel), memTotalTime,
(long) (totalMem.sysMemKernelWeight / memTotalTime));
osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
osPkg.addEntry(osEntry);
}
if (totalMem.sysMemZRamWeight > 0) {
osEntry = new ProcStatsEntry("os", 0,
mContext.getString(R.string.process_stats_os_zram), memTotalTime,
(long) (totalMem.sysMemZRamWeight / memTotalTime));
osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
osPkg.addEntry(osEntry);
}
if (baseCacheRam > 0) {
osEntry = new ProcStatsEntry("os", 0,
mContext.getString(R.string.process_stats_os_cache), memTotalTime,
baseCacheRam / 1024);
osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
osPkg.addEntry(osEntry);
}
return osPkg;
}
private ArrayList<ProcStatsEntry> getProcs(ProcessDataCollection bgTotals,
ProcessDataCollection runTotals) {
final ArrayList<ProcStatsEntry> procEntries = new ArrayList<>();
if (DEBUG) Log.d(TAG, "-------------------- PULLING PROCESSES");
final ProcessMap<ProcStatsEntry> entriesMap = new ProcessMap<ProcStatsEntry>();
for (int ipkg = 0, N = mStats.mPackages.getMap().size(); ipkg < N; ipkg++) {
final SparseArray<SparseArray<ProcessStats.PackageState>> pkgUids = mStats.mPackages
.getMap().valueAt(ipkg);
for (int iu = 0; iu < pkgUids.size(); iu++) {
final SparseArray<ProcessStats.PackageState> vpkgs = pkgUids.valueAt(iu);
for (int iv = 0; iv < vpkgs.size(); iv++) {
final ProcessStats.PackageState st = vpkgs.valueAt(iv);
for (int iproc = 0; iproc < st.mProcesses.size(); iproc++) {
final ProcessStats.ProcessState pkgProc = st.mProcesses.valueAt(iproc);
final ProcessStats.ProcessState proc = mStats.mProcesses.get(pkgProc.mName,
pkgProc.mUid);
if (proc == null) {
Log.w(TAG, "No process found for pkg " + st.mPackageName
+ "/" + st.mUid + " proc name " + pkgProc.mName);
continue;
}
ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid);
if (ent == null) {
ent = new ProcStatsEntry(proc, st.mPackageName, bgTotals, runTotals,
mUseUss);
if (ent.mRunWeight > 0) {
if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
+ proc.mUid + ": time="
+ ProcessStatsUi.makeDuration(ent.mRunDuration) + " ("
+ ((((double) ent.mRunDuration) / memTotalTime) * 100)
+ "%)"
+ " pss=" + ent.mAvgRunMem);
entriesMap.put(proc.mName, proc.mUid, ent);
procEntries.add(ent);
}
} else {
ent.addPackage(st.mPackageName);
}
}
}
}
}
if (DEBUG) Log.d(TAG, "-------------------- MAPPING SERVICES");
// Add in service info.
for (int ip = 0, N = mStats.mPackages.getMap().size(); ip < N; ip++) {
SparseArray<SparseArray<ProcessStats.PackageState>> uids = mStats.mPackages.getMap()
.valueAt(ip);
for (int iu = 0; iu < uids.size(); iu++) {
SparseArray<ProcessStats.PackageState> vpkgs = uids.valueAt(iu);
for (int iv = 0; iv < vpkgs.size(); iv++) {
ProcessStats.PackageState ps = vpkgs.valueAt(iv);
for (int is = 0, NS = ps.mServices.size(); is < NS; is++) {
ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
if (ss.mProcessName != null) {
ProcStatsEntry ent = entriesMap.get(ss.mProcessName,
uids.keyAt(iu));
if (ent != null) {
if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName
+ "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc "
+ ss.mProcessName);
ent.addService(ss);
} else {
Log.w(TAG, "No process " + ss.mProcessName + "/" + uids.keyAt(iu)
+ " for service " + ss.mName);
}
}
}
}
}
}
return procEntries;
}
private void load() {
try {
mMemState = mProcessStats.getCurrentMemoryState();
ParcelFileDescriptor pfd = mProcessStats.getStatsOverTime(mDuration);
mStats = new ProcessStats(false);
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
mStats.read(is);
try {
is.close();
} catch (IOException e) {
}
if (mStats.mReadError != null) {
Log.w(TAG, "Failure reading process stats: " + mStats.mReadError);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException:", e);
}
}
public static class MemInfo {
double realUsedRam;
double realFreeRam;
double realTotalRam;
long baseCacheRam;
double[] mMemStateWeights = new double[ProcessStats.STATE_COUNT];
double freeWeight;
double usedWeight;
double weightToRam;
double totalRam;
double totalScale;
private MemInfo(Context context, ProcessStats.TotalMemoryUseCollection totalMem,
long memTotalTime) {
calculateWeightInfo(context, totalMem, memTotalTime);
double usedRam = (usedWeight * 1024) / memTotalTime;
double freeRam = (freeWeight * 1024) / memTotalTime;
totalRam = usedRam + freeRam;
totalScale = realTotalRam / totalRam;
weightToRam = totalScale / memTotalTime * 1024;
realUsedRam = usedRam * totalScale;
realFreeRam = freeRam * totalScale;
if (DEBUG) {
Log.i(TAG, "Scaled Used RAM: " + Formatter.formatShortFileSize(context,
(long) realUsedRam));
Log.i(TAG, "Scaled Free RAM: " + Formatter.formatShortFileSize(context,
(long) realFreeRam));
}
if (DEBUG) {
Log.i(TAG, "Adj Scaled Used RAM: " + Formatter.formatShortFileSize(context,
(long) realUsedRam));
Log.i(TAG, "Adj Scaled Free RAM: " + Formatter.formatShortFileSize(context,
(long) realFreeRam));
}
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(
memInfo);
if (memInfo.hiddenAppThreshold >= realFreeRam) {
realUsedRam = freeRam;
realFreeRam = 0;
baseCacheRam = (long) realFreeRam;
} else {
realUsedRam += memInfo.hiddenAppThreshold;
realFreeRam -= memInfo.hiddenAppThreshold;
baseCacheRam = memInfo.hiddenAppThreshold;
}
}
private void calculateWeightInfo(Context context, TotalMemoryUseCollection totalMem,
long memTotalTime) {
MemInfoReader memReader = new MemInfoReader();
memReader.readMemInfo();
realTotalRam = memReader.getTotalSize();
freeWeight = totalMem.sysMemFreeWeight + totalMem.sysMemCachedWeight;
usedWeight = totalMem.sysMemKernelWeight + totalMem.sysMemNativeWeight
+ totalMem.sysMemZRamWeight;
for (int i = 0; i < ProcessStats.STATE_COUNT; i++) {
if (i == ProcessStats.STATE_SERVICE_RESTARTING) {
// These don't really run.
mMemStateWeights[i] = 0;
} else {
mMemStateWeights[i] = totalMem.processStateWeight[i];
if (i >= ProcessStats.STATE_HOME) {
freeWeight += totalMem.processStateWeight[i];
} else {
usedWeight += totalMem.processStateWeight[i];
}
}
}
if (DEBUG) {
Log.i(TAG, "Used RAM: " + Formatter.formatShortFileSize(context,
(long) ((usedWeight * 1024) / memTotalTime)));
Log.i(TAG, "Free RAM: " + Formatter.formatShortFileSize(context,
(long) ((freeWeight * 1024) / memTotalTime)));
Log.i(TAG, "Total RAM: " + Formatter.formatShortFileSize(context,
(long) (((freeWeight + usedWeight) * 1024) / memTotalTime)));
}
}
}
final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
@Override
public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
if (lhs.mRunWeight < rhs.mRunWeight) {
return 1;
} else if (lhs.mRunWeight > rhs.mRunWeight) {
return -1;
} else if (lhs.mRunDuration < rhs.mRunDuration) {
return 1;
} else if (lhs.mRunDuration > rhs.mRunDuration) {
return -1;
}
return 0;
}
};
}

View File

@@ -36,6 +36,7 @@ public final class ProcStatsEntry implements Parcelable {
final String mPackage;
final int mUid;
final String mName;
public CharSequence mLabel;
final ArrayList<String> mPackages = new ArrayList<String>();
final long mBgDuration;
final long mAvgBgMem;

View File

@@ -30,6 +30,9 @@ public class ProcStatsPackageEntry implements Parcelable {
private static final String TAG = "ProcStatsEntry";
private static boolean DEBUG = ProcessStatsUi.DEBUG;
private static final float ALWAYS_THRESHOLD = .95f;
private static final float SOMETIMES_THRESHOLD = .25f;
final String mPackage;
final ArrayList<ProcStatsEntry> mEntries = new ArrayList<ProcStatsEntry>();
@@ -44,9 +47,11 @@ public class ProcStatsPackageEntry implements Parcelable {
public ApplicationInfo mUiTargetApp;
public String mUiLabel;
private long mWindowLength;
public ProcStatsPackageEntry(String pkg) {
public ProcStatsPackageEntry(String pkg, long windowLength) {
mPackage = pkg;
mWindowLength = windowLength;
}
public ProcStatsPackageEntry(Parcel in) {
@@ -62,6 +67,16 @@ public class ProcStatsPackageEntry implements Parcelable {
mRunWeight = in.readDouble();
}
public CharSequence getRunningFrequency(Context context) {
float amountRunning = mRunDuration / (float) mWindowLength;
return getFrequency(amountRunning, context);
}
public CharSequence getBackgroundFrequency(Context context) {
float amountRunning = mBgDuration / (float) mWindowLength;
return getFrequency(amountRunning, context);
}
public void addEntry(ProcStatsEntry entry) {
mEntries.add(entry);
}
@@ -72,23 +87,28 @@ public class ProcStatsPackageEntry implements Parcelable {
mRunDuration = mAvgRunMem = mMaxRunMem = 0;
mRunWeight = 0;
final int N = mEntries.size();
for (int i=0; i<N; i++) {
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;
}
mAvgBgMem += entry.mAvgBgMem * entry.mBgDuration;
mBgWeight += entry.mBgWeight;
mRunDuration += entry.mRunDuration;
mAvgRunMem += entry.mAvgRunMem;
if (entry.mMaxRunMem > mMaxRunMem) {
mMaxRunMem = entry.mMaxRunMem;
}
mAvgRunMem += entry.mAvgRunMem * entry.mRunDuration;
mRunWeight += entry.mRunWeight;
// Each entry is generally a process or something similar. Since it is extremely
// unlikely that any apps are going to avoid running processes at the same time
// to avoid memory usage, we will sum the maximum memory usage to create a
// hypothetical worst case scenario of memory.
mMaxBgMem += entry.mMaxBgMem;
mMaxRunMem += entry.mMaxRunMem;
}
if (mBgDuration != 0) {
mAvgBgMem = mAvgBgMem * N / mBgDuration;
}
if (mRunDuration != 0) {
mAvgRunMem = mAvgRunMem * N / mRunDuration;
}
mAvgBgMem /= N;
mAvgRunMem /= N;
}
public void retrieveUiData(Context context, PackageManager pm) {
@@ -142,4 +162,15 @@ public class ProcStatsPackageEntry implements Parcelable {
return new ProcStatsPackageEntry[size];
}
};
// TODO: Find better place for this.
public static CharSequence getFrequency(float amount, Context context) {
if (amount> ALWAYS_THRESHOLD) {
return context.getString(R.string.always_running);
} else if (amount> SOMETIMES_THRESHOLD) {
return context.getString(R.string.sometimes_running);
} else {
return context.getString(R.string.rarely_running);
}
}
}

View File

@@ -17,60 +17,77 @@
package com.android.settings.applications;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Process;
import android.preference.PreferenceCategory;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.settings.InstrumentedFragment;
import com.android.settings.AppHeader;
import com.android.settings.CancellablePreference;
import com.android.settings.CancellablePreference.OnCancelListener;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.ProcStatsEntry.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import static com.android.settings.Utils.prepareCustomPreferencesList;
public class ProcessStatsDetail extends SettingsPreferenceFragment
implements Button.OnClickListener {
public class ProcessStatsDetail extends InstrumentedFragment implements Button.OnClickListener {
private static final String TAG = "ProcessStatsDetail";
public static final int ACTION_FORCE_STOP = 1;
public static final String EXTRA_PACKAGE_ENTRY = "package_entry";
public static final String EXTRA_USE_USS = "use_uss";
public static final String EXTRA_MAX_WEIGHT = "max_weight";
public static final String EXTRA_WEIGHT_TO_RAM = "weight_to_ram";
public static final String EXTRA_TOTAL_TIME = "total_time";
public static final String EXTRA_MAX_MEMORY_USAGE = "max_memory_usage";
public static final String EXTRA_TOTAL_SCALE = "total_scale";
private static final String KEY_DETAILS_HEADER = "details_header";
private final ArrayMap<ComponentName, CancellablePreference> mServiceMap = new ArrayMap<>();
private PackageManager mPm;
private DevicePolicyManager mDpm;
private ProcStatsPackageEntry mApp;
private boolean mUseUss;
private double mMaxWeight;
private double mWeightToRam;
private long mTotalTime;
private long mOnePercentTime;
private View mRootView;
private TextView mTitleView;
private ViewGroup mTwoButtonsPanel;
private Button mForceStopButton;
private Button mReportButton;
private ViewGroup mProcessesParent;
private ViewGroup mServicesParent;
private LinearColorBar mColorBar;
private float mMaxMemoryUsage;
private double mTotalScale;
@Override
public void onCreate(Bundle icicle) {
@@ -81,21 +98,23 @@ public class ProcessStatsDetail extends InstrumentedFragment implements Button.O
mApp = args.getParcelable(EXTRA_PACKAGE_ENTRY);
mApp.retrieveUiData(getActivity(), mPm);
mUseUss = args.getBoolean(EXTRA_USE_USS);
mMaxWeight = args.getDouble(EXTRA_MAX_WEIGHT);
mWeightToRam = args.getDouble(EXTRA_WEIGHT_TO_RAM);
mTotalTime = args.getLong(EXTRA_TOTAL_TIME);
mMaxMemoryUsage = args.getFloat(EXTRA_MAX_MEMORY_USAGE);
mTotalScale = args.getDouble(EXTRA_TOTAL_SCALE);
mOnePercentTime = mTotalTime/100;
mServiceMap.clear();
createDetails();
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.process_stats_details, container, false);
prepareCustomPreferencesList(container, view, view, false);
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mRootView = view;
createDetails();
return view;
AppHeader.createAppHeader(getActivity(),
mApp.mUiTargetApp != null ? mApp.mUiTargetApp.loadIcon(mPm) : new ColorDrawable(0),
mApp.mUiLabel, null);
}
@Override
@@ -107,56 +126,88 @@ public class ProcessStatsDetail extends InstrumentedFragment implements Button.O
public void onResume() {
super.onResume();
checkForceStop();
updateRunningServices();
}
@Override
public void onPause() {
super.onPause();
private void updateRunningServices() {
ActivityManager activityManager = (ActivityManager)
getActivity().getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> runningServices =
activityManager.getRunningServices(Integer.MAX_VALUE);
// Set all services as not running, then turn back on the ones we find.
int N = mServiceMap.size();
for (int i = 0; i < N; i++) {
mServiceMap.valueAt(i).setCancellable(false);
}
N = runningServices.size();
for (int i = 0; i < N; i++) {
RunningServiceInfo runningService = runningServices.get(i);
if (!runningService.started && runningService.clientLabel == 0) {
continue;
}
if ((runningService.flags & RunningServiceInfo.FLAG_PERSISTENT_PROCESS) != 0) {
continue;
}
final ComponentName service = runningService.service;
CancellablePreference pref = mServiceMap.get(service);
if (pref != null) {
pref.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(CancellablePreference preference) {
stopService(service.getPackageName(), service.getClassName());
}
});
pref.setCancellable(true);
}
}
}
private void createDetails() {
final double percentOfWeight = (mApp.mBgWeight / mMaxWeight) * 100;
int appLevel = (int) Math.ceil(percentOfWeight);
String appLevelText = Formatter.formatShortFileSize(getActivity(),
(long)(mApp.mRunWeight * mWeightToRam));
// Set all values in the header.
mTitleView = (TextView) mRootView.findViewById(android.R.id.title);
mTitleView.setText(mApp.mUiLabel);
final TextView text1 = (TextView)mRootView.findViewById(android.R.id.text1);
text1.setText(appLevelText);
final ProgressBar progress = (ProgressBar) mRootView.findViewById(android.R.id.progress);
progress.setProgress(appLevel);
final ImageView icon = (ImageView) mRootView.findViewById(android.R.id.icon);
if (mApp.mUiTargetApp != null) {
icon.setImageDrawable(mApp.mUiTargetApp.loadIcon(mPm));
}
mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel);
mForceStopButton = (Button)mRootView.findViewById(R.id.right_button);
mReportButton = (Button)mRootView.findViewById(R.id.left_button);
mForceStopButton.setEnabled(false);
mReportButton.setVisibility(View.INVISIBLE);
mProcessesParent = (ViewGroup)mRootView.findViewById(R.id.processes);
mServicesParent = (ViewGroup)mRootView.findViewById(R.id.services);
addPreferencesFromResource(R.xml.app_memory_settings);
fillProcessesSection();
fillServicesSection();
if (mServicesParent.getChildCount() <= 0) {
mServicesParent.setVisibility(View.GONE);
mRootView.findViewById(R.id.services_label).setVisibility(View.GONE);
}
LayoutPreference headerLayout = (LayoutPreference) findPreference(KEY_DETAILS_HEADER);
TextView avgUsed = (TextView) headerLayout.findViewById(R.id.memory_avg);
TextView maxUsed = (TextView) headerLayout.findViewById(R.id.memory_max);
avgUsed.setText(getString(R.string.memory_avg_desc,
Formatter.formatShortFileSize(getActivity(),
(long) (Math.max(mApp.mBgWeight, mApp.mRunWeight) * mWeightToRam))));
maxUsed.setText(getString(R.string.memory_max_desc,
Formatter.formatShortFileSize(getActivity(),
(long) (Math.max(mApp.mMaxBgMem, mApp.mMaxRunMem) * 1024 * mTotalScale))));
mForceStopButton = (Button) headerLayout.findViewById(R.id.right_button);
mReportButton = (Button) headerLayout.findViewById(R.id.left_button);
if (mApp.mEntries.get(0).mUid >= android.os.Process.FIRST_APPLICATION_UID) {
mForceStopButton.setEnabled(false);
mReportButton.setVisibility(View.INVISIBLE);
mForceStopButton.setText(R.string.force_stop);
mForceStopButton.setTag(ACTION_FORCE_STOP);
mForceStopButton.setOnClickListener(this);
mTwoButtonsPanel.setVisibility(View.VISIBLE);
} else {
mTwoButtonsPanel.setVisibility(View.GONE);
mReportButton.setVisibility(View.GONE);
mForceStopButton.setVisibility(View.GONE);
}
// TODO: Find way to share this code with ProcessStatsPreference.
boolean statsForeground = mApp.mRunWeight > mApp.mBgWeight;
float mAvgRatio = (statsForeground ? mApp.mAvgRunMem : mApp.mAvgBgMem) / mMaxMemoryUsage;
float mMaxRatio = (statsForeground ? mApp.mMaxRunMem : mApp.mMaxBgMem) / mMaxMemoryUsage
- mAvgRatio;
float mRemainingRatio = 1 - mAvgRatio - mMaxRatio;
mColorBar = (LinearColorBar) headerLayout.findViewById(R.id.color_bar);
Context context = getActivity();
mColorBar.setColors(context.getColor(R.color.memory_avg_use),
context.getColor(R.color.memory_max_use),
context.getColor(R.color.memory_remaining));
mColorBar.setRatios(mAvgRatio, mMaxRatio, mRemainingRatio);
}
public void onClick(View v) {
@@ -171,34 +222,6 @@ public class ProcessStatsDetail extends InstrumentedFragment implements Button.O
}
}
private void addPackageHeaderItem(ViewGroup parent, String packageName) {
LayoutInflater inflater = getActivity().getLayoutInflater();
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.running_processes_item,
null);
parent.addView(item);
final ImageView icon = (ImageView) item.findViewById(R.id.icon);
TextView nameView = (TextView) item.findViewById(R.id.name);
TextView descriptionView = (TextView) item.findViewById(R.id.description);
try {
ApplicationInfo ai = mPm.getApplicationInfo(packageName, 0);
icon.setImageDrawable(ai.loadIcon(mPm));
nameView.setText(ai.loadLabel(mPm));
} catch (PackageManager.NameNotFoundException e) {
}
descriptionView.setText(packageName);
}
private void addDetailsItem(ViewGroup parent, CharSequence label, CharSequence value) {
LayoutInflater inflater = getActivity().getLayoutInflater();
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text,
null);
parent.addView(item);
TextView labelView = (TextView) item.findViewById(R.id.label);
TextView valueView = (TextView) item.findViewById(R.id.value);
labelView.setText(label);
valueView.setText(value);
}
final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
@Override
public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
@@ -213,28 +236,35 @@ public class ProcessStatsDetail extends InstrumentedFragment implements Button.O
private void fillProcessesSection() {
final ArrayList<ProcStatsEntry> entries = new ArrayList<>();
for (int ie=0; ie<mApp.mEntries.size(); ie++) {
for (int ie = 0; ie < mApp.mEntries.size(); ie++) {
ProcStatsEntry entry = mApp.mEntries.get(ie);
if (entry.mPackage.equals("os")) {
entry.mLabel = entry.mName;
} else {
if (mApp.mEntries.size() > 1) {
entry.mLabel = getString(R.string.process_format, (ie + 1));
} else {
entry.mLabel = getString(R.string.process);
}
}
entries.add(entry);
}
Collections.sort(entries, sEntryCompare);
for (int ie=0; ie<entries.size(); ie++) {
for (int ie = 0; ie < entries.size(); ie++) {
ProcStatsEntry entry = entries.get(ie);
LayoutInflater inflater = getActivity().getLayoutInflater();
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.process_stats_proc_details,
null);
mProcessesParent.addView(item);
((TextView)item.findViewById(R.id.processes_name)).setText(entry.mName);
addDetailsItem(item, getResources().getText(R.string.process_stats_ram_use),
Formatter.formatShortFileSize(getActivity(),
(long)(entry.mRunWeight * mWeightToRam)));
if (entry.mBgWeight > 0) {
addDetailsItem(item, getResources().getText(R.string.process_stats_bg_ram_use),
Formatter.formatShortFileSize(getActivity(),
(long)(entry.mBgWeight * mWeightToRam)));
}
addDetailsItem(item, getResources().getText(R.string.process_stats_run_time),
Utils.formatPercentage(entry.mRunDuration, mTotalTime));
PreferenceCategory processPref = new PreferenceCategory(getActivity());
processPref.setLayoutResource(R.layout.process_preference_category);
processPref.setTitle(entry.mLabel);
long memoryUse = Math.max((long)(entry.mRunWeight * mWeightToRam),
(long)(entry.mBgWeight * mWeightToRam));
String memoryString = Formatter.formatShortFileSize(getActivity(), memoryUse);
CharSequence frequency = ProcStatsPackageEntry.getFrequency(entry.mRunDuration
/ (float)mTotalTime, getActivity());
processPref.setSummary(
getString(R.string.memory_use_running_format, memoryString, frequency));
getPreferenceScreen().addPreference(processPref);
fillServicesSection(entry, processPref);
}
}
@@ -268,52 +298,97 @@ public class ProcessStatsDetail extends InstrumentedFragment implements Button.O
long mDuration;
}
private void fillServicesSection() {
private void fillServicesSection(ProcStatsEntry entry, PreferenceCategory processPref) {
final HashMap<String, PkgService> pkgServices = new HashMap<>();
final ArrayList<PkgService> pkgList = new ArrayList<>();
for (int ie=0; ie< mApp.mEntries.size(); ie++) {
ProcStatsEntry ent = mApp.mEntries.get(ie);
for (int ip=0; ip<ent.mServices.size(); ip++) {
String pkg = ent.mServices.keyAt(ip);
PkgService psvc = null;
ArrayList<ProcStatsEntry.Service> services = ent.mServices.valueAt(ip);
for (int is=services.size()-1; is>=0; is--) {
ProcStatsEntry.Service pent = services.get(is);
if (pent.mDuration >= mOnePercentTime) {
for (int ip = 0; ip < entry.mServices.size(); ip++) {
String pkg = entry.mServices.keyAt(ip);
PkgService psvc = null;
ArrayList<ProcStatsEntry.Service> services = entry.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 = pkgServices.get(pkg);
if (psvc == null) {
psvc = new PkgService();
pkgServices.put(pkg, psvc);
pkgList.add(psvc);
}
psvc = new PkgService();
pkgServices.put(pkg, psvc);
pkgList.add(psvc);
}
psvc.mServices.add(pent);
psvc.mDuration += pent.mDuration;
}
psvc.mServices.add(pent);
psvc.mDuration += pent.mDuration;
}
}
}
Collections.sort(pkgList, sServicePkgCompare);
for (int ip=0; ip<pkgList.size(); ip++) {
for (int ip = 0; ip < pkgList.size(); ip++) {
ArrayList<ProcStatsEntry.Service> services = pkgList.get(ip).mServices;
Collections.sort(services, sServiceCompare);
if (pkgList.size() > 1) {
addPackageHeaderItem(mServicesParent, services.get(0).mPackage);
}
for (int is=0; is<services.size(); is++) {
ProcStatsEntry.Service service = services.get(is);
String label = service.mName;
int tail = label.lastIndexOf('.');
if (tail >= 0 && tail < (label.length()-1)) {
label = label.substring(tail+1);
}
String percentage = Utils.formatPercentage(service.mDuration, mTotalTime);
addDetailsItem(mServicesParent, label, percentage);
final ProcStatsEntry.Service service = services.get(is);
CharSequence label = getLabel(service);
CancellablePreference servicePref = new CancellablePreference(getActivity());
servicePref.setSelectable(false);
servicePref.setTitle(label);
servicePref.setSummary(ProcStatsPackageEntry.getFrequency(
service.mDuration / (float) mTotalTime, getActivity()));
processPref.addPreference(servicePref);
mServiceMap.put(new ComponentName(service.mPackage, service.mName), servicePref);
}
}
}
private CharSequence getLabel(Service service) {
// Try to get the service label, on the off chance that one exists.
try {
ServiceInfo serviceInfo = getPackageManager().getServiceInfo(
new ComponentName(service.mPackage, service.mName), 0);
if (serviceInfo.labelRes != 0) {
return serviceInfo.loadLabel(getPackageManager());
}
} catch (NameNotFoundException e) {
}
String label = service.mName;
int tail = label.lastIndexOf('.');
if (tail >= 0 && tail < (label.length()-1)) {
label = label.substring(tail+1);
}
return label;
}
private void stopService(String pkg, String name) {
try {
ApplicationInfo appInfo = getActivity().getPackageManager().getApplicationInfo(pkg, 0);
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
showStopServiceDialog(pkg, name);
return;
}
} catch (NameNotFoundException e) {
Log.e(TAG, "Can't find app " + pkg, e);
return;
}
doStopService(pkg, name);
}
private void showStopServiceDialog(final String pkg, final String name) {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.runningservicedetails_stop_dlg_title)
.setMessage(R.string.runningservicedetails_stop_dlg_text)
.setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
doStopService(pkg, name);
}
})
.setNegativeButton(R.string.dlg_cancel, null)
.show();
}
private void doStopService(String pkg, String name) {
getActivity().stopService(new Intent().setClassName(pkg, name));
updateRunningServices();
}
private void killProcesses() {
ActivityManager am = (ActivityManager)getActivity().getSystemService(
Context.ACTIVITY_SERVICE);

View File

@@ -17,20 +17,25 @@
package com.android.settings.applications;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.preference.Preference;
import android.text.format.Formatter;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.settings.R;
public class ProcessStatsPreference extends Preference {
private ProcStatsPackageEntry mEntry;
private int mProgress;
private CharSequence mProgressText;
private final int mAvgColor;
private final int mMaxColor;
private final int mRemainingColor;
private float mAvgRatio;
private float mMaxRatio;
private float mRemainingRatio;
public ProcessStatsPreference(Context context) {
this(context, null);
@@ -47,33 +52,38 @@ public class ProcessStatsPreference extends Preference {
public ProcessStatsPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutResource(R.layout.preference_app_percentage);
setLayoutResource(R.layout.app_item_linear_color);
mAvgColor = context.getColor(R.color.memory_avg_use);
mMaxColor = context.getColor(R.color.memory_max_use);
mRemainingColor = context.getColor(R.color.memory_remaining);
}
public void init(Drawable icon, ProcStatsPackageEntry entry) {
public void init(ProcStatsPackageEntry entry, PackageManager pm, float maxMemory) {
mEntry = entry;
setIcon(icon != null ? icon : new ColorDrawable(0));
setTitle(TextUtils.isEmpty(entry.mUiLabel) ? entry.mPackage : entry.mUiLabel);
if (entry.mUiTargetApp != null) {
setIcon(entry.mUiTargetApp.loadIcon(pm));
} else {
setIcon(new ColorDrawable(0));
}
boolean statsForeground = entry.mRunWeight > entry.mBgWeight;
setSummary(statsForeground ? entry.getRunningFrequency(getContext())
: entry.getBackgroundFrequency(getContext()));
mAvgRatio = (statsForeground ? entry.mAvgRunMem : entry.mAvgBgMem) / maxMemory;
mMaxRatio = (statsForeground ? entry.mMaxRunMem : entry.mMaxBgMem) / maxMemory - mAvgRatio;
mRemainingRatio = 1 - mAvgRatio - mMaxRatio;
}
public ProcStatsPackageEntry getEntry() {
return mEntry;
}
public void setPercent(double percentOfWeight, double percentOfTime, long memory) {
mProgress = (int) Math.ceil(percentOfWeight);
//mProgressText = Utils.formatPercentage((int) percentOfTime);
mProgressText = Formatter.formatShortFileSize(getContext(), memory);
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);
LinearColorBar linearColorBar = (LinearColorBar) view.findViewById(R.id.linear_color_bar);
linearColorBar.setColors(mAvgColor, mMaxColor, mRemainingColor);
linearColorBar.setRatios(mAvgRatio, mMaxRatio, mRemainingRatio);
}
}

View File

@@ -16,82 +16,59 @@
package com.android.settings.applications;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
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.text.format.Formatter;
import android.util.Log;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import com.android.internal.app.IProcessStats;
import com.android.internal.app.ProcessMap;
import android.widget.TextView;
import com.android.internal.app.ProcessStats;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.MemInfoReader;
import com.android.settings.InstrumentedPreferenceFragment;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.applications.ProcStatsData.MemInfo;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
public class ProcessStatsUi extends InstrumentedPreferenceFragment
implements LinearColorBar.OnRegionTappedListener {
public class ProcessStatsUi extends InstrumentedPreferenceFragment {
private static final String MEM_REGION = "mem_region";
private static final String STATS_TYPE = "stats_type";
private static final String USE_USS = "use_uss";
private static final String SHOW_SYSTEM = "show_system";
private static final String SHOW_PERCENTAGE = "show_percentage";
private static final String DURATION = "duration";
static final String TAG = "ProcessStatsUi";
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 String KEY_STATUS_HEADER = "status_header";
private static final int NUM_DURATIONS = 4;
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_SHOW_PERCENTAGE = MENU_DURATION + NUM_DURATIONS;
private static final int MENU_SHOW_SYSTEM = MENU_SHOW_PERCENTAGE + 1;
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>() {
@Override
public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
if (lhs.mRunWeight < rhs.mRunWeight) {
return 1;
} else if (lhs.mRunWeight > rhs.mRunWeight) {
return -1;
} else if (lhs.mRunDuration < rhs.mRunDuration) {
return 1;
} else if (lhs.mRunDuration > rhs.mRunDuration) {
return -1;
}
return 0;
}
};
final static Comparator<ProcStatsPackageEntry> sPackageEntryCompare
= new Comparator<ProcStatsPackageEntry>() {
@Override
@@ -109,21 +86,13 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
}
};
private static ProcessStats sStatsXfer;
IProcessStats mProcessStats;
UserManager mUm;
ProcessStats mStats;
int mMemState;
private long mDuration;
private long mLastDuration;
private boolean mShowPercentage;
private boolean mShowSystem;
private boolean mUseUss;
private int mStatsType;
private int mMemRegion;
private MenuItem[] mDurationMenus = new MenuItem[NUM_DURATIONS];
private MenuItem mShowPercentageMenu;
private MenuItem mShowSystemMenu;
private MenuItem mUseUssMenu;
private MenuItem mTypeBackgroundMenu;
@@ -131,20 +100,18 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
private MenuItem mTypeCachedMenu;
private PreferenceGroup mAppListGroup;
private Preference mMemStatusPref;
private TextView mMemStatus;
double mMaxWeight;
long mTotalTime;
private long mTotalTime;
long[] mMemTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT];
double[] mMemStateWeights = new double[ProcessStats.STATE_COUNT];
double mMemCachedWeight;
double mMemFreeWeight;
double mMemZRamWeight;
double mMemKernelWeight;
double mMemNativeWeight;
double mMemTotalWeight;
double mWeightToRam;
private long[] mMemTimes = new long[ProcessStats.ADJ_MEM_FACTOR_COUNT];
private LinearColorBar mColors;
private TextView mMemUsed;
private LayoutPreference mHeader;
private PackageManager mPm;
private long memTotalTime;
private int mStatsType;
// The actual duration value to use for each duration option. Note these
// are lower than the actual duration, since our durations are computed in
@@ -161,26 +128,31 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
R.string.menu_duration_12h, R.string.menu_duration_1d
};
private ProcStatsData mStatsManager;
private float mMaxMemoryUsage;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (icicle != null) {
mStats = sStatsXfer;
}
mStatsManager = new ProcStatsData(getActivity(), icicle != null);
mPm = getActivity().getPackageManager();
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);
mDuration = icicle != null ? icicle.getLong("duration", sDurations[0]) : sDurations[0];
mShowSystem = icicle != null ? icicle.getBoolean("show_system") : false;
mUseUss = icicle != null ? icicle.getBoolean("use_uss") : false;
mStatsType = icicle != null ? icicle.getInt("stats_type", MENU_TYPE_BACKGROUND)
mHeader = (LayoutPreference)mAppListGroup.findPreference(KEY_STATUS_HEADER);
mMemStatus = (TextView) mHeader.findViewById(R.id.memory_state);
mColors = (LinearColorBar) mHeader.findViewById(R.id.color_bar);
mMemUsed = (TextView) mHeader.findViewById(R.id.memory_used);
mStatsManager.setDuration(icicle != null
? icicle.getLong(DURATION, sDurations[0]) : sDurations[0]);
mShowPercentage = icicle != null ? icicle.getBoolean(SHOW_PERCENTAGE) : true;
mShowSystem = icicle != null ? icicle.getBoolean(SHOW_SYSTEM) : false;
mUseUss = icicle != null ? icicle.getBoolean(USE_USS) : false;
mStatsType = icicle != null ? icicle.getInt(STATS_TYPE, MENU_TYPE_BACKGROUND)
: MENU_TYPE_BACKGROUND;
mMemRegion = icicle != null ? icicle.getInt("mem_region", LinearColorBar.REGION_GREEN)
mMemRegion = icicle != null ? icicle.getInt(MEM_REGION, LinearColorBar.REGION_GREEN)
: LinearColorBar.REGION_GREEN;
setHasOptionsMenu(true);
}
@@ -193,47 +165,31 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
@Override
public void onResume() {
super.onResume();
refreshStats();
mStatsManager.refreshStats(false);
refreshUi();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putLong("duration", mDuration);
outState.putBoolean("show_system", mShowSystem);
outState.putBoolean("use_uss", mUseUss);
outState.putInt("stats_type", mStatsType);
outState.putInt("mem_region", mMemRegion);
outState.putLong(DURATION, mStatsManager.getDuration());
outState.putBoolean(SHOW_PERCENTAGE, mShowPercentage);
outState.putBoolean(SHOW_SYSTEM, mShowSystem);
outState.putBoolean(USE_USS, mUseUss);
outState.putInt(STATS_TYPE, mStatsType);
outState.putInt(MEM_REGION, mMemRegion);
}
@Override
public void onDestroy() {
super.onDestroy();
if (getActivity().isChangingConfigurations()) {
sStatsXfer = mStats;
mStatsManager.xferStats();
}
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference instanceof LinearColorPreference) {
Bundle args = new Bundle();
args.putLongArray(ProcessStatsMemDetail.EXTRA_MEM_TIMES, mMemTimes);
args.putDoubleArray(ProcessStatsMemDetail.EXTRA_MEM_STATE_WEIGHTS, mMemStateWeights);
args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_CACHED_WEIGHT, mMemCachedWeight);
args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_FREE_WEIGHT, mMemFreeWeight);
args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_ZRAM_WEIGHT, mMemZRamWeight);
args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_KERNEL_WEIGHT, mMemKernelWeight);
args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_NATIVE_WEIGHT, mMemNativeWeight);
args.putDouble(ProcessStatsMemDetail.EXTRA_MEM_TOTAL_WEIGHT, mMemTotalWeight);
args.putBoolean(ProcessStatsMemDetail.EXTRA_USE_USS, mUseUss);
args.putLong(ProcessStatsMemDetail.EXTRA_TOTAL_TIME, mTotalTime);
((SettingsActivity) getActivity()).startPreferencePanel(
ProcessStatsMemDetail.class.getName(), args, R.string.mem_details_title,
null, null, 0);
return true;
}
if (!(preference instanceof ProcessStatsPreference)) {
return false;
}
@@ -242,9 +198,11 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
Bundle args = new Bundle();
args.putParcelable(ProcessStatsDetail.EXTRA_PACKAGE_ENTRY, pgp.getEntry());
args.putBoolean(ProcessStatsDetail.EXTRA_USE_USS, mUseUss);
args.putDouble(ProcessStatsDetail.EXTRA_MAX_WEIGHT, mMaxWeight);
args.putDouble(ProcessStatsDetail.EXTRA_WEIGHT_TO_RAM, mWeightToRam);
args.putDouble(ProcessStatsDetail.EXTRA_WEIGHT_TO_RAM,
mStatsManager.getMemInfo().weightToRam);
args.putLong(ProcessStatsDetail.EXTRA_TOTAL_TIME, mTotalTime);
args.putFloat(ProcessStatsDetail.EXTRA_MAX_MEMORY_USAGE, mMaxMemoryUsage);
args.putDouble(ProcessStatsDetail.EXTRA_TOTAL_SCALE, mStatsManager.getMemInfo().totalScale);
((SettingsActivity) getActivity()).startPreferencePanel(
ProcessStatsDetail.class.getName(), args, R.string.details_title, null, null, 0);
@@ -263,41 +221,37 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
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)
.setAlphabeticShortcut('s')
.setCheckable(true);
mUseUssMenu = menu.add(0, MENU_USE_USS, 0, R.string.menu_use_uss)
.setAlphabeticShortcut('u')
.setCheckable(true);
subMenu = menu.addSubMenu(R.string.menu_proc_stats_type);
mTypeBackgroundMenu = subMenu.add(0, MENU_TYPE_BACKGROUND, 0,
R.string.menu_proc_stats_type_background)
.setAlphabeticShortcut('b')
.setCheckable(true);
mTypeForegroundMenu = subMenu.add(0, MENU_TYPE_FOREGROUND, 0,
R.string.menu_proc_stats_type_foreground)
.setAlphabeticShortcut('f')
.setCheckable(true);
mTypeCachedMenu = subMenu.add(0, MENU_TYPE_CACHED, 0,
R.string.menu_proc_stats_type_cached)
.setCheckable(true);
// Hide these for now, until their need is determined.
// mShowPercentageMenu = menu.add(0, MENU_SHOW_PERCENTAGE, 0, R.string.menu_show_percentage)
// .setAlphabeticShortcut('p')
// .setCheckable(true);
// mShowSystemMenu = menu.add(0, MENU_SHOW_SYSTEM, 0, R.string.menu_show_system)
// .setAlphabeticShortcut('s')
// .setCheckable(true);
// mUseUssMenu = menu.add(0, MENU_USE_USS, 0, R.string.menu_use_uss)
// .setAlphabeticShortcut('u')
// .setCheckable(true);
// subMenu = menu.addSubMenu(R.string.menu_proc_stats_type);
// mTypeBackgroundMenu = subMenu.add(0, MENU_TYPE_BACKGROUND, 0,
// R.string.menu_proc_stats_type_background)
// .setAlphabeticShortcut('b')
// .setCheckable(true);
// mTypeForegroundMenu = subMenu.add(0, MENU_TYPE_FOREGROUND, 0,
// R.string.menu_proc_stats_type_foreground)
// .setAlphabeticShortcut('f')
// .setCheckable(true);
// mTypeCachedMenu = subMenu.add(0, MENU_TYPE_CACHED, 0,
// R.string.menu_proc_stats_type_cached)
// .setCheckable(true);
updateMenus();
/*
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);
}
*/
}
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);
long closestDelta = Math.abs(sDurations[0] - mStatsManager.getDuration());
for (int i = 1; i < NUM_DURATIONS; i++) {
long delta = Math.abs(sDurations[i] - mStatsManager.getDuration());
if (delta < closestDelta) {
closestDelta = delta;
closestIndex = i;
@@ -308,7 +262,10 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
mDurationMenus[i].setChecked(i == closestIndex);
}
}
mDuration = sDurations[closestIndex];
mStatsManager.setDuration(sDurations[closestIndex]);
if (mShowPercentageMenu != null) {
mShowPercentageMenu.setChecked(mShowPercentage);
}
if (mShowSystemMenu != null) {
mShowSystemMenu.setChecked(mShowSystem);
mShowSystemMenu.setEnabled(mStatsType == MENU_TYPE_BACKGROUND);
@@ -332,46 +289,44 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
final int id = item.getItemId();
switch (id) {
case MENU_STATS_REFRESH:
mStats = null;
refreshStats();
mStatsManager.refreshStats(false);
refreshUi();
return true;
case MENU_SHOW_PERCENTAGE:
mShowPercentage = !mShowPercentage;
refreshUi();
return true;
case MENU_SHOW_SYSTEM:
mShowSystem = !mShowSystem;
refreshStats();
refreshUi();
return true;
case MENU_USE_USS:
mUseUss = !mUseUss;
refreshStats();
refreshUi();
return true;
case MENU_TYPE_BACKGROUND:
case MENU_TYPE_FOREGROUND:
case MENU_TYPE_CACHED:
mStatsType = item.getItemId();
refreshStats();
if (mStatsType == MENU_TYPE_FOREGROUND) {
mStatsManager.setStats(FOREGROUND_PROC_STATES);
} else if (mStatsType == MENU_TYPE_CACHED) {
mStatsManager.setStats(CACHED_PROC_STATES);
} else {
mStatsManager.setStats(mShowSystem ? BACKGROUND_AND_SYSTEM_PROC_STATES
: ProcessStats.BACKGROUND_PROC_STATES);
}
refreshUi();
return true;
default:
if (id >= MENU_DURATION && id < (MENU_DURATION+NUM_DURATIONS)) {
mDuration = sDurations[id-MENU_DURATION];
refreshStats();
if (id >= MENU_DURATION && id < (MENU_DURATION + NUM_DURATIONS)) {
mStatsManager.setDuration(sDurations[id - MENU_DURATION]);
refreshUi();
}
return false;
}
}
@Override
public void onRegionTapped(int region) {
if (mMemRegion != region) {
mMemRegion = region;
refreshStats();
}
}
private void addNotAvailableMessage() {
Preference notAvailable = new Preference(getActivity());
notAvailable.setTitle(R.string.power_usage_not_available);
mAppListGroup.addPreference(notAvailable);
}
/**
* All states in which we consider a process to be actively running (rather than
* something that can be freely killed to reclaim RAM). Note this also includes
@@ -396,385 +351,75 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
ProcessStats.STATE_CACHED_EMPTY
};
public static final int[] RED_MEM_STATES = new int[] {
ProcessStats.ADJ_MEM_FACTOR_CRITICAL
};
public static final int[] YELLOW_MEM_STATES = new int[] {
ProcessStats.ADJ_MEM_FACTOR_CRITICAL, ProcessStats.ADJ_MEM_FACTOR_LOW,
ProcessStats.ADJ_MEM_FACTOR_MODERATE
};
private String makeDuration(long time) {
public static String makeDuration(long time) {
StringBuilder sb = new StringBuilder(32);
TimeUtils.formatDuration(time, sb);
return sb.toString();
}
private void refreshStats() {
private void refreshUi() {
updateMenus();
if (mStats == null || mLastDuration != mDuration) {
load();
}
int[] stats;
int statsLabel;
if (mStatsType == MENU_TYPE_FOREGROUND) {
stats = FOREGROUND_PROC_STATES;
statsLabel = R.string.process_stats_type_foreground;
} else if (mStatsType == MENU_TYPE_CACHED) {
stats = CACHED_PROC_STATES;
statsLabel = R.string.process_stats_type_cached;
} else {
stats = mShowSystem ? BACKGROUND_AND_SYSTEM_PROC_STATES
: ProcessStats.BACKGROUND_PROC_STATES;
statsLabel = R.string.process_stats_type_background;
}
mAppListGroup.removeAll();
mAppListGroup.setOrderingAsAdded(false);
mHeader.setOrder(-1);
mAppListGroup.addPreference(mHeader);
final long elapsedTime = mStats.mTimePeriodEndRealtime-mStats.mTimePeriodStartRealtime;
final long elapsedTime = mStatsManager.getElapsedTime();
long now = SystemClock.uptimeMillis();
final PackageManager pm = getActivity().getPackageManager();
mTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations,
mStats.mMemFactor, mStats.mStartTime, now);
if (DEBUG) Log.d(TAG, "Total time of stats: " + makeDuration(mTotalTime));
for (int i=0; i<mMemTimes.length; i++) {
mMemTimes[i] = 0;
}
for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) {
for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) {
int state = imem+iscreen;
mMemTimes[imem] += mStats.mMemFactorDurations[state];
}
}
long memTotalTime;
int[] memStates;
LinearColorPreference colors = new LinearColorPreference(getActivity());
colors.setOrder(-1);
switch (mMemRegion) {
case LinearColorBar.REGION_RED:
memTotalTime = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL];
memStates = RED_MEM_STATES;
break;
case LinearColorBar.REGION_YELLOW:
memTotalTime = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL]
+ mMemTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]
+ mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE];
memStates = YELLOW_MEM_STATES;
break;
default:
memTotalTime = mTotalTime;
memStates = ProcessStats.ALL_MEM_ADJ;
break;
}
memTotalTime = mTotalTime;
final Context context = getActivity();
colors.setColors(context.getColor(R.color.running_processes_apps_ram),
// TODO: More Colors.
mColors.setColors(context.getColor(R.color.running_processes_apps_ram),
context.getColor(R.color.running_processes_apps_ram),
context.getColor(R.color.running_processes_free_ram));
// Compute memory badness for chart color.
/*
int[] badColors = com.android.settings.Utils.BADNESS_COLORS;
long timeGood = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL];
timeGood += (mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]*2)/3;
timeGood += mMemTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]/3;
float memBadness = ((float)timeGood)/mTotalTime;
int badnessColor = badColors[1 + Math.round(memBadness*(badColors.length-2))];
colors.setColors(badnessColor, badnessColor, badnessColor);
*/
// We are now going to scale the mMemTimes to match the total elapsed time.
// These are in uptime, so they will often be smaller than the elapsed time,
// but if the user taps on the bar we want to show the times to them. It is confusing
// to see them be smaller than what we told them the measured duration is, so just
// scaling them up with make things look reasonable with them none the wiser.
for (int i=0; i<ProcessStats.ADJ_MEM_FACTOR_COUNT; i++) {
mMemTimes[i] = (long)((mMemTimes[i]*(double)elapsedTime)/mTotalTime);
}
ProcessStats.TotalMemoryUseCollection totalMem = new ProcessStats.TotalMemoryUseCollection(
ProcessStats.ALL_SCREEN_ADJ, memStates);
mStats.computeTotalMemoryUse(totalMem, now);
double freeWeight = totalMem.sysMemFreeWeight + totalMem.sysMemCachedWeight;
double usedWeight = totalMem.sysMemKernelWeight + totalMem.sysMemNativeWeight
+ totalMem.sysMemZRamWeight;
double backgroundWeight = 0, persBackgroundWeight = 0;
mMemCachedWeight = totalMem.sysMemCachedWeight;
mMemFreeWeight = totalMem.sysMemFreeWeight;
mMemZRamWeight = totalMem.sysMemZRamWeight;
mMemKernelWeight = totalMem.sysMemKernelWeight;
mMemNativeWeight = totalMem.sysMemNativeWeight;
for (int i=0; i<ProcessStats.STATE_COUNT; i++) {
if (i == ProcessStats.STATE_SERVICE_RESTARTING) {
// These don't really run.
mMemStateWeights[i] = 0;
} else {
mMemStateWeights[i] = totalMem.processStateWeight[i];
if (i >= ProcessStats.STATE_HOME) {
freeWeight += totalMem.processStateWeight[i];
} else {
usedWeight += totalMem.processStateWeight[i];
}
if (i >= ProcessStats.STATE_IMPORTANT_FOREGROUND) {
backgroundWeight += totalMem.processStateWeight[i];
persBackgroundWeight += totalMem.processStateWeight[i];
}
if (i == ProcessStats.STATE_PERSISTENT) {
persBackgroundWeight += totalMem.processStateWeight[i];
}
}
}
if (DEBUG) {
Log.i(TAG, "Used RAM: " + Formatter.formatShortFileSize(getActivity(),
(long)((usedWeight * 1024) / memTotalTime)));
Log.i(TAG, "Free RAM: " + Formatter.formatShortFileSize(getActivity(),
(long)((freeWeight * 1024) / memTotalTime)));
Log.i(TAG, "Total RAM: " + Formatter.formatShortFileSize(getActivity(),
(long)(((freeWeight+usedWeight) * 1024) / memTotalTime)));
Log.i(TAG, "Background+Cached RAM: " + Formatter.formatShortFileSize(getActivity(),
(long)((backgroundWeight * 1024) / memTotalTime)));
}
mMemTotalWeight = freeWeight + usedWeight;
// For computing the ratio to show, we want to count the baseline cached RAM we
// need (at which point we start killing processes) as used RAM, so that if we
// reach the point of thrashing due to no RAM for any background processes we
// report that as RAM being full. To do this, we need to first convert the weights
// back to actual RAM... and since the RAM values we compute here won't exactly
// match the real physical RAM, scale those to the actual physical RAM. No problem!
double usedRam = (usedWeight*1024)/memTotalTime;
double freeRam = (freeWeight*1024)/memTotalTime;
double totalRam = usedRam + freeRam;
MemInfoReader memReader = new MemInfoReader();
memReader.readMemInfo();
double realTotalRam = memReader.getTotalSize();
double totalScale = realTotalRam / totalRam;
mWeightToRam = totalScale / memTotalTime * 1024;
mMaxWeight = totalRam / mWeightToRam;
double realUsedRam = usedRam * totalScale;
double realFreeRam = freeRam * totalScale;
if (DEBUG) {
Log.i(TAG, "Scaled Used RAM: " + Formatter.formatShortFileSize(getActivity(),
(long)realUsedRam));
Log.i(TAG, "Scaled Free RAM: " + Formatter.formatShortFileSize(getActivity(),
(long)realFreeRam));
}
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
((ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(
memInfo);
long baseCacheRam;
if (memInfo.hiddenAppThreshold >= realFreeRam) {
realUsedRam = realFreeRam;
realFreeRam = 0;
baseCacheRam = (long)realFreeRam;
} else {
realUsedRam += memInfo.hiddenAppThreshold;
realFreeRam -= memInfo.hiddenAppThreshold;
baseCacheRam = memInfo.hiddenAppThreshold;
}
if (DEBUG) {
Log.i(TAG, "Adj Scaled Used RAM: " + Formatter.formatShortFileSize(getActivity(),
(long)realUsedRam));
Log.i(TAG, "Adj Scaled Free RAM: " + Formatter.formatShortFileSize(getActivity(),
(long)realFreeRam));
}
MemInfo memInfo = mStatsManager.getMemInfo();
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);
String durationString = Utils.formatElapsedTime(context, elapsedTime, false);
String usedString = Formatter.formatShortFileSize(context, (long) memInfo.realUsedRam);
String totalString = Formatter.formatShortFileSize(context, (long) memInfo.realTotalRam);
CharSequence memString;
CharSequence[] memStatesStr = getResources().getTextArray(R.array.ram_states);
if (mMemState >= 0 && mMemState < memStatesStr.length) {
memString = memStatesStr[mMemState];
int memState = mStatsManager.getMemState();
if (memState >= 0 && memState < memStatesStr.length) {
memString = memStatesStr[memState];
} else {
memString = "?";
}
mMemStatusPref.setTitle(getActivity().getString(R.string.process_stats_total_duration,
usedString, totalString, durationString));
mMemStatusPref.setSummary(getActivity().getString(R.string.process_stats_memory_status,
memString));
float usedRatio = (float)(realUsedRam/(realFreeRam+realUsedRam));
colors.setRatios(usedRatio, 0, 1-usedRatio);
if (false) {
colors.setOnRegionTappedListener(this);
switch (mMemRegion) {
case LinearColorBar.REGION_RED:
colors.setColoredRegions(LinearColorBar.REGION_RED);
memTotalTime = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL];
memStates = RED_MEM_STATES;
break;
case LinearColorBar.REGION_YELLOW:
colors.setColoredRegions(LinearColorBar.REGION_RED
| LinearColorBar.REGION_YELLOW);
memTotalTime = mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL]
+ mMemTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]
+ mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE];
memStates = YELLOW_MEM_STATES;
break;
default:
colors.setColoredRegions(LinearColorBar.REGION_ALL);
memTotalTime = mTotalTime;
memStates = ProcessStats.ALL_MEM_ADJ;
break;
}
colors.setRatios(mMemTimes[ProcessStats.ADJ_MEM_FACTOR_CRITICAL] / (float)mTotalTime,
(mMemTimes[ProcessStats.ADJ_MEM_FACTOR_LOW]
+ mMemTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]) / (float)mTotalTime,
mMemTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL] / (float)mTotalTime);
if (mShowPercentage) {
mMemUsed.setText(context.getString(
R.string.process_stats_total_duration_percentage,
Utils.formatPercentage((long) memInfo.realUsedRam, (long) memInfo.realTotalRam),
durationString));
} else {
mMemUsed.setText(context.getString(R.string.process_stats_total_duration,
usedString, totalString, durationString));
}
mMemStatus.setText(context.getString(R.string.process_stats_memory_status,
memString));
float usedRatio = (float)(memInfo.realUsedRam
/ (memInfo.realFreeRam + memInfo.realUsedRam));
mColors.setRatios(usedRatio, 0, 1-usedRatio);
mAppListGroup.addPreference(colors);
ProcessStats.ProcessDataCollection bgTotals = new ProcessStats.ProcessDataCollection(
ProcessStats.ALL_SCREEN_ADJ, memStates, stats);
ProcessStats.ProcessDataCollection runTotals = new ProcessStats.ProcessDataCollection(
ProcessStats.ALL_SCREEN_ADJ, memStates, ProcessStats.NON_CACHED_PROC_STATES);
final ArrayList<ProcStatsEntry> procEntries = new ArrayList<>();
final ArrayList<ProcStatsPackageEntry> pkgEntries = new ArrayList<>();
/*
ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked(
ProcessStats.ALL_SCREEN_ADJ, ProcessStats.ALL_MEM_ADJ,
ProcessStats.BACKGROUND_PROC_STATES, now, null);
for (int i=0, N=(rawProcs != null ? rawProcs.size() : 0); i<N; i++) {
procs.add(new ProcStatsEntry(rawProcs.get(i), bgTotals));
}
*/
if (DEBUG) Log.d(TAG, "-------------------- PULLING PROCESSES");
final ProcessMap<ProcStatsEntry> entriesMap = new ProcessMap<ProcStatsEntry>();
for (int ipkg=0, N=mStats.mPackages.getMap().size(); ipkg<N; ipkg++) {
final SparseArray<SparseArray<ProcessStats.PackageState>> pkgUids
= mStats.mPackages.getMap().valueAt(ipkg);
for (int iu=0; iu<pkgUids.size(); iu++) {
final SparseArray<ProcessStats.PackageState> vpkgs = pkgUids.valueAt(iu);
for (int iv=0; iv<vpkgs.size(); iv++) {
final ProcessStats.PackageState st = vpkgs.valueAt(iv);
for (int iproc=0; iproc<st.mProcesses.size(); iproc++) {
final ProcessStats.ProcessState pkgProc = st.mProcesses.valueAt(iproc);
final ProcessStats.ProcessState proc = mStats.mProcesses.get(pkgProc.mName,
pkgProc.mUid);
if (proc == null) {
Log.w(TAG, "No process found for pkg " + st.mPackageName
+ "/" + st.mUid + " proc name " + pkgProc.mName);
continue;
}
ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid);
if (ent == null) {
ent = new ProcStatsEntry(proc, st.mPackageName, bgTotals, runTotals,
mUseUss);
if (ent.mRunWeight > 0) {
if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
+ proc.mUid + ": time=" + makeDuration(ent.mRunDuration) + " ("
+ ((((double)ent.mRunDuration) / memTotalTime) * 100) + "%)"
+ " pss=" + ent.mAvgRunMem);
entriesMap.put(proc.mName, proc.mUid, ent);
procEntries.add(ent);
}
} else {
ent.addPackage(st.mPackageName);
}
}
}
}
}
if (DEBUG) Log.d(TAG, "-------------------- MAPPING SERVICES");
// Add in service info.
if (mStatsType == MENU_TYPE_BACKGROUND) {
for (int ip=0, N=mStats.mPackages.getMap().size(); ip<N; ip++) {
SparseArray<SparseArray<ProcessStats.PackageState>> uids
= mStats.mPackages.getMap().valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
SparseArray<ProcessStats.PackageState> vpkgs = uids.valueAt(iu);
for (int iv=0; iv<vpkgs.size(); iv++) {
ProcessStats.PackageState ps = vpkgs.valueAt(iv);
for (int is=0, NS=ps.mServices.size(); is<NS; is++) {
ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
if (ss.mProcessName != null) {
ProcStatsEntry ent = entriesMap.get(ss.mProcessName,
uids.keyAt(iu));
if (ent != null) {
if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName
+ "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc "
+ ss.mProcessName);
ent.addService(ss);
} else {
Log.w(TAG, "No process " + ss.mProcessName + "/" + uids.keyAt(iu)
+ " for service " + ss.mName);
}
}
}
}
}
}
}
// Combine processes into packages.
HashMap<String, ProcStatsPackageEntry> pkgMap = new HashMap<>();
for (int i=procEntries.size()-1; i>=0; i--) {
ProcStatsEntry proc = procEntries.get(i);
proc.evaluateTargetPackage(pm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
ProcStatsPackageEntry pkg = pkgMap.get(proc.mBestTargetPackage);
if (pkg == null) {
pkg = new ProcStatsPackageEntry(proc.mBestTargetPackage);
pkgMap.put(proc.mBestTargetPackage, pkg);
pkgEntries.add(pkg);
}
pkg.addEntry(proc);
}
// 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);
}
List<ProcStatsPackageEntry> pkgEntries = mStatsManager.getEntries();
// Update everything and get the absolute maximum of memory usage for scaling.
mMaxMemoryUsage = 0;
for (int i=0, N=pkgEntries.size(); i<N; i++) {
ProcStatsPackageEntry pkg = pkgEntries.get(i);
pkg.updateMetrics();
float maxMem = Math.max(pkg.mMaxBgMem, pkg.mMaxRunMem);
if (maxMem > mMaxMemoryUsage) {
mMaxMemoryUsage = maxMem;
}
}
Collections.sort(pkgEntries, sPackageEntryCompare);
@@ -789,62 +434,25 @@ public class ProcessStatsUi extends InstrumentedPreferenceFragment
int end = pkgEntries.size()-1;
while (end >= 0) {
ProcStatsPackageEntry pkg = pkgEntries.get(end);
final double percentOfWeight = (pkg.mRunWeight / mMaxWeight) * 100;
final double percentOfTime = (((double)pkg.mRunDuration) / memTotalTime) * 100;
final double percentOfWeight = (pkg.mRunWeight
/ (memInfo.totalRam / memInfo.weightToRam)) * 100;
final double percentOfTime = (((double) pkg.mRunDuration) / memTotalTime) * 100;
if (percentOfWeight >= .01 || percentOfTime >= 25) {
break;
}
end--;
}
for (int i=0; i<=end; i++) {
for (int i=0; i <= end; i++) {
ProcStatsPackageEntry pkg = pkgEntries.get(i);
final double percentOfWeight = (pkg.mRunWeight / mMaxWeight) * 100;
final double percentOfTime = (((double)pkg.mRunDuration) / memTotalTime) * 100;
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity());
pref.init(null, pkg);
pkg.retrieveUiData(getActivity(), pm);
pref.setTitle(pkg.mUiLabel);
if (pkg.mUiTargetApp != null) {
pref.setIcon(pkg.mUiTargetApp.loadIcon(pm));
}
ProcessStatsPreference pref = new ProcessStatsPreference(context);
pkg.retrieveUiData(context, mPm);
pref.init(pkg, mPm, mMaxMemoryUsage);
pref.setOrder(i);
pref.setPercent(percentOfWeight, percentOfTime,
(long)(pkg.mRunWeight * mWeightToRam));
mAppListGroup.addPreference(pref);
if (mStatsType == MENU_TYPE_BACKGROUND) {
if (DEBUG) {
Log.i(TAG, "App " + pkg.mUiLabel + ": weightedRam="
+ Formatter.formatShortFileSize(getActivity(),
(long)((pkg.mRunWeight * 1024) / memTotalTime))
+ ", avgRam=" + Formatter.formatShortFileSize(getActivity(),
(pkg.mAvgRunMem *1024)));
}
}
if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) {
if (DEBUG) Log.d(TAG, "Done with UI, hit item limit!");
break;
}
}
}
private void load() {
try {
mLastDuration = mDuration;
mMemState = mProcessStats.getCurrentMemoryState();
ParcelFileDescriptor pfd = mProcessStats.getStatsOverTime(mDuration);
mStats = new ProcessStats(false);
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
mStats.read(is);
try {
is.close();
} catch (IOException e) {
}
if (mStats.mReadError != null) {
Log.w(TAG, "Failure reading process stats: " + mStats.mReadError);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException:", e);
}
}
}