2 * Copyright (C) 2015 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.settings.applications;
19 import android.app.ActivityManager;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.os.ParcelFileDescriptor;
23 import android.os.RemoteException;
24 import android.os.ServiceManager;
25 import android.os.SystemClock;
26 import android.text.format.Formatter;
27 import android.util.ArrayMap;
28 import android.util.Log;
29 import android.util.SparseArray;
31 import com.android.internal.app.IProcessStats;
32 import com.android.internal.app.ProcessMap;
33 import com.android.internal.app.ProcessStats;
34 import com.android.internal.app.ProcessStats.ProcessDataCollection;
35 import com.android.internal.app.ProcessStats.TotalMemoryUseCollection;
36 import com.android.internal.util.MemInfoReader;
37 import com.android.settings.R;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.util.ArrayList;
42 import java.util.Comparator;
43 import java.util.List;
45 public class ProcStatsData {
47 private static final String TAG = "ProcStatsManager";
49 private static final boolean DEBUG = ProcessStatsUi.DEBUG;
51 private static ProcessStats sStatsXfer;
53 private PackageManager mPm;
54 private Context mContext;
55 private long memTotalTime;
57 private IProcessStats mProcessStats;
58 private ProcessStats mStats;
60 private int mMemState;
62 private boolean mUseUss;
63 private long mDuration;
65 private int[] mMemStates;
67 private int[] mStates;
69 private MemInfo mMemInfo;
71 private ArrayList<ProcStatsPackageEntry> pkgEntries;
73 public ProcStatsData(Context context, boolean useXfer) {
75 mPm = context.getPackageManager();
76 mProcessStats = IProcessStats.Stub.asInterface(
77 ServiceManager.getService(ProcessStats.SERVICE_NAME));
78 mMemStates = ProcessStats.ALL_MEM_ADJ;
79 mStates = ProcessStats.BACKGROUND_PROC_STATES;
85 public void setTotalTime(int totalTime) {
86 memTotalTime = totalTime;
89 public void xferStats() {
93 public void setMemStates(int[] memStates) {
94 mMemStates = memStates;
98 public void setStats(int[] stats) {
103 public int getMemState() {
104 int factor = mStats.mMemFactor;
105 if (factor == ProcessStats.ADJ_NOTHING) {
106 return ProcessStats.ADJ_MEM_FACTOR_NORMAL;
108 if (factor >= ProcessStats.ADJ_SCREEN_ON) {
109 factor -= ProcessStats.ADJ_SCREEN_ON;
114 public MemInfo getMemInfo() {
118 public long getElapsedTime() {
119 return mStats.mTimePeriodEndRealtime - mStats.mTimePeriodStartRealtime;
122 public void setDuration(long duration) {
123 if (duration != mDuration) {
124 mDuration = duration;
129 public long getDuration() {
133 public List<ProcStatsPackageEntry> getEntries() {
137 public void refreshStats(boolean forceLoad) {
138 if (mStats == null || forceLoad) {
142 pkgEntries = new ArrayList<>();
144 long now = SystemClock.uptimeMillis();
146 memTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations,
147 mStats.mMemFactor, mStats.mStartTime, now);
149 ProcessStats.TotalMemoryUseCollection totalMem = new ProcessStats.TotalMemoryUseCollection(
150 ProcessStats.ALL_SCREEN_ADJ, mMemStates);
151 mStats.computeTotalMemoryUse(totalMem, now);
153 mMemInfo = new MemInfo(mContext, totalMem, memTotalTime);
155 ProcessDataCollection bgTotals = new ProcessDataCollection(
156 ProcessStats.ALL_SCREEN_ADJ, mMemStates, mStates);
157 ProcessDataCollection runTotals = new ProcessDataCollection(
158 ProcessStats.ALL_SCREEN_ADJ, mMemStates, ProcessStats.NON_CACHED_PROC_STATES);
160 createPkgMap(getProcs(bgTotals, runTotals), bgTotals, runTotals);
162 ProcStatsPackageEntry osPkg = createOsEntry(bgTotals, runTotals, totalMem,
163 mMemInfo.baseCacheRam);
164 pkgEntries.add(osPkg);
167 private void createPkgMap(ArrayList<ProcStatsEntry> procEntries, ProcessDataCollection bgTotals,
168 ProcessDataCollection runTotals) {
169 // Combine processes into packages.
170 ArrayMap<String, ProcStatsPackageEntry> pkgMap = new ArrayMap<>();
171 for (int i = procEntries.size() - 1; i >= 0; i--) {
172 ProcStatsEntry proc = procEntries.get(i);
173 proc.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
174 ProcStatsPackageEntry pkg = pkgMap.get(proc.mBestTargetPackage);
176 pkg = new ProcStatsPackageEntry(proc.mBestTargetPackage, memTotalTime);
177 pkgMap.put(proc.mBestTargetPackage, pkg);
184 private ProcStatsPackageEntry createOsEntry(ProcessDataCollection bgTotals,
185 ProcessDataCollection runTotals, TotalMemoryUseCollection totalMem, long baseCacheRam) {
186 // Add in fake entry representing the OS itself.
187 ProcStatsPackageEntry osPkg = new ProcStatsPackageEntry("os", memTotalTime);
188 ProcStatsEntry osEntry;
189 if (totalMem.sysMemNativeWeight > 0) {
190 osEntry = new ProcStatsEntry("os", 0,
191 mContext.getString(R.string.process_stats_os_native), memTotalTime,
192 (long) (totalMem.sysMemNativeWeight / memTotalTime));
193 osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
194 osPkg.addEntry(osEntry);
196 if (totalMem.sysMemKernelWeight > 0) {
197 osEntry = new ProcStatsEntry("os", 0,
198 mContext.getString(R.string.process_stats_os_kernel), memTotalTime,
199 (long) (totalMem.sysMemKernelWeight / memTotalTime));
200 osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
201 osPkg.addEntry(osEntry);
203 if (totalMem.sysMemZRamWeight > 0) {
204 osEntry = new ProcStatsEntry("os", 0,
205 mContext.getString(R.string.process_stats_os_zram), memTotalTime,
206 (long) (totalMem.sysMemZRamWeight / memTotalTime));
207 osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
208 osPkg.addEntry(osEntry);
210 if (baseCacheRam > 0) {
211 osEntry = new ProcStatsEntry("os", 0,
212 mContext.getString(R.string.process_stats_os_cache), memTotalTime,
213 baseCacheRam / 1024);
214 osEntry.evaluateTargetPackage(mPm, mStats, bgTotals, runTotals, sEntryCompare, mUseUss);
215 osPkg.addEntry(osEntry);
220 private ArrayList<ProcStatsEntry> getProcs(ProcessDataCollection bgTotals,
221 ProcessDataCollection runTotals) {
222 final ArrayList<ProcStatsEntry> procEntries = new ArrayList<>();
223 if (DEBUG) Log.d(TAG, "-------------------- PULLING PROCESSES");
225 final ProcessMap<ProcStatsEntry> entriesMap = new ProcessMap<ProcStatsEntry>();
226 for (int ipkg = 0, N = mStats.mPackages.getMap().size(); ipkg < N; ipkg++) {
227 final SparseArray<SparseArray<ProcessStats.PackageState>> pkgUids = mStats.mPackages
228 .getMap().valueAt(ipkg);
229 for (int iu = 0; iu < pkgUids.size(); iu++) {
230 final SparseArray<ProcessStats.PackageState> vpkgs = pkgUids.valueAt(iu);
231 for (int iv = 0; iv < vpkgs.size(); iv++) {
232 final ProcessStats.PackageState st = vpkgs.valueAt(iv);
233 for (int iproc = 0; iproc < st.mProcesses.size(); iproc++) {
234 final ProcessStats.ProcessState pkgProc = st.mProcesses.valueAt(iproc);
235 final ProcessStats.ProcessState proc = mStats.mProcesses.get(pkgProc.mName,
238 Log.w(TAG, "No process found for pkg " + st.mPackageName
239 + "/" + st.mUid + " proc name " + pkgProc.mName);
242 ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid);
244 ent = new ProcStatsEntry(proc, st.mPackageName, bgTotals, runTotals,
246 if (ent.mRunWeight > 0) {
247 if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
248 + proc.mUid + ": time="
249 + ProcessStatsUi.makeDuration(ent.mRunDuration) + " ("
250 + ((((double) ent.mRunDuration) / memTotalTime) * 100)
252 + " pss=" + ent.mAvgRunMem);
253 entriesMap.put(proc.mName, proc.mUid, ent);
254 procEntries.add(ent);
257 ent.addPackage(st.mPackageName);
264 if (DEBUG) Log.d(TAG, "-------------------- MAPPING SERVICES");
266 // Add in service info.
267 for (int ip = 0, N = mStats.mPackages.getMap().size(); ip < N; ip++) {
268 SparseArray<SparseArray<ProcessStats.PackageState>> uids = mStats.mPackages.getMap()
270 for (int iu = 0; iu < uids.size(); iu++) {
271 SparseArray<ProcessStats.PackageState> vpkgs = uids.valueAt(iu);
272 for (int iv = 0; iv < vpkgs.size(); iv++) {
273 ProcessStats.PackageState ps = vpkgs.valueAt(iv);
274 for (int is = 0, NS = ps.mServices.size(); is < NS; is++) {
275 ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
276 if (ss.mProcessName != null) {
277 ProcStatsEntry ent = entriesMap.get(ss.mProcessName,
280 if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName
281 + "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc "
285 Log.w(TAG, "No process " + ss.mProcessName + "/" + uids.keyAt(iu)
286 + " for service " + ss.mName);
297 private void load() {
299 mMemState = mProcessStats.getCurrentMemoryState();
300 ParcelFileDescriptor pfd = mProcessStats.getStatsOverTime(mDuration);
301 mStats = new ProcessStats(false);
302 InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
306 } catch (IOException e) {
308 if (mStats.mReadError != null) {
309 Log.w(TAG, "Failure reading process stats: " + mStats.mReadError);
311 } catch (RemoteException e) {
312 Log.e(TAG, "RemoteException:", e);
316 public static class MemInfo {
322 double[] mMemStateWeights = new double[ProcessStats.STATE_COUNT];
330 private MemInfo(Context context, ProcessStats.TotalMemoryUseCollection totalMem,
332 this.memTotalTime = memTotalTime;
333 calculateWeightInfo(context, totalMem, memTotalTime);
335 double usedRam = (usedWeight * 1024) / memTotalTime;
336 double freeRam = (freeWeight * 1024) / memTotalTime;
337 totalRam = usedRam + freeRam;
338 totalScale = realTotalRam / totalRam;
339 weightToRam = totalScale / memTotalTime * 1024;
341 realUsedRam = usedRam * totalScale;
342 realFreeRam = freeRam * totalScale;
344 Log.i(TAG, "Scaled Used RAM: " + Formatter.formatShortFileSize(context,
345 (long) realUsedRam));
346 Log.i(TAG, "Scaled Free RAM: " + Formatter.formatShortFileSize(context,
347 (long) realFreeRam));
350 Log.i(TAG, "Adj Scaled Used RAM: " + Formatter.formatShortFileSize(context,
351 (long) realUsedRam));
352 Log.i(TAG, "Adj Scaled Free RAM: " + Formatter.formatShortFileSize(context,
353 (long) realFreeRam));
356 ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
357 ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(
359 if (memInfo.hiddenAppThreshold >= realFreeRam) {
360 realUsedRam = freeRam;
362 baseCacheRam = (long) realFreeRam;
364 realUsedRam += memInfo.hiddenAppThreshold;
365 realFreeRam -= memInfo.hiddenAppThreshold;
366 baseCacheRam = memInfo.hiddenAppThreshold;
370 private void calculateWeightInfo(Context context, TotalMemoryUseCollection totalMem,
372 MemInfoReader memReader = new MemInfoReader();
373 memReader.readMemInfo();
374 realTotalRam = memReader.getTotalSize();
375 freeWeight = totalMem.sysMemFreeWeight + totalMem.sysMemCachedWeight;
376 usedWeight = totalMem.sysMemKernelWeight + totalMem.sysMemNativeWeight
377 + totalMem.sysMemZRamWeight;
378 for (int i = 0; i < ProcessStats.STATE_COUNT; i++) {
379 if (i == ProcessStats.STATE_SERVICE_RESTARTING) {
380 // These don't really run.
381 mMemStateWeights[i] = 0;
383 mMemStateWeights[i] = totalMem.processStateWeight[i];
384 if (i >= ProcessStats.STATE_HOME) {
385 freeWeight += totalMem.processStateWeight[i];
387 usedWeight += totalMem.processStateWeight[i];
392 Log.i(TAG, "Used RAM: " + Formatter.formatShortFileSize(context,
393 (long) ((usedWeight * 1024) / memTotalTime)));
394 Log.i(TAG, "Free RAM: " + Formatter.formatShortFileSize(context,
395 (long) ((freeWeight * 1024) / memTotalTime)));
396 Log.i(TAG, "Total RAM: " + Formatter.formatShortFileSize(context,
397 (long) (((freeWeight + usedWeight) * 1024) / memTotalTime)));
402 final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
404 public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
405 if (lhs.mRunWeight < rhs.mRunWeight) {
407 } else if (lhs.mRunWeight > rhs.mRunWeight) {
409 } else if (lhs.mRunDuration < rhs.mRunDuration) {
411 } else if (lhs.mRunDuration > rhs.mRunDuration) {