diff options
Diffstat (limited to 'src/com/android/settings')
9 files changed, 909 insertions, 712 deletions
diff --git a/src/com/android/settings/CancellablePreference.java b/src/com/android/settings/CancellablePreference.java new file mode 100644 index 0000000..ab723ca --- /dev/null +++ b/src/com/android/settings/CancellablePreference.java @@ -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); + } + +} diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java index 5c7e0e9..6c2f135 100644 --- a/src/com/android/settings/DevelopmentSettings.java +++ b/src/com/android/settings/DevelopmentSettings.java @@ -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) { diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index caf2491..ee2b1b4 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -340,6 +340,7 @@ public class SettingsActivity extends Activity ZenModePrioritySettings.class.getName(), ZenModeScheduleRuleSettings.class.getName(), ZenModeExternalRuleSettings.class.getName(), + ProcessStatsUi.class.getName(), }; diff --git a/src/com/android/settings/applications/ProcStatsData.java b/src/com/android/settings/applications/ProcStatsData.java new file mode 100644 index 0000000..1e32cc9 --- /dev/null +++ b/src/com/android/settings/applications/ProcStatsData.java @@ -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; + } + }; +} diff --git a/src/com/android/settings/applications/ProcStatsEntry.java b/src/com/android/settings/applications/ProcStatsEntry.java index 41f7a53..637003c 100644 --- a/src/com/android/settings/applications/ProcStatsEntry.java +++ b/src/com/android/settings/applications/ProcStatsEntry.java @@ -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; diff --git a/src/com/android/settings/applications/ProcStatsPackageEntry.java b/src/com/android/settings/applications/ProcStatsPackageEntry.java index 3925d1d..feb11d8 100644 --- a/src/com/android/settings/applications/ProcStatsPackageEntry.java +++ b/src/com/android/settings/applications/ProcStatsPackageEntry.java @@ -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); + } + } } diff --git a/src/com/android/settings/applications/ProcessStatsDetail.java b/src/com/android/settings/applications/ProcessStatsDetail.java index 1e7cf09..191e7e9 100644 --- a/src/com/android/settings/applications/ProcessStatsDetail.java +++ b/src/com/android/settings/applications/ProcessStatsDetail.java @@ -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(); - } - @Override - public void onPause() { - super.onPause(); + updateRunningServices(); } - 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)); + 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); } - 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); + 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); + } + } + } - mProcessesParent = (ViewGroup)mRootView.findViewById(R.id.processes); - mServicesParent = (ViewGroup)mRootView.findViewById(R.id.services); + private void createDetails() { + 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); diff --git a/src/com/android/settings/applications/ProcessStatsPreference.java b/src/com/android/settings/applications/ProcessStatsPreference.java index 182cf0e..a1725e3 100644 --- a/src/com/android/settings/applications/ProcessStatsPreference.java +++ b/src/com/android/settings/applications/ProcessStatsPreference.java @@ -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); } } diff --git a/src/com/android/settings/applications/ProcessStatsUi.java b/src/com/android/settings/applications/ProcessStatsUi.java index 45e24dd..96f76c0 100644 --- a/src/com/android/settings/applications/ProcessStatsUi.java +++ b/src/com/android/settings/applications/ProcessStatsUi.java @@ -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; - -public class ProcessStatsUi extends InstrumentedPreferenceFragment - implements LinearColorBar.OnRegionTappedListener { +import java.util.List; + +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; - - 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; + final long elapsedTime = mStatsManager.getElapsedTime(); - 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); - } - - 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); + 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); - // 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); - } - } } |