1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17package com.android.settings.applications; 18 19import android.content.Context; 20import android.content.pm.ApplicationInfo; 21import android.content.pm.PackageManager; 22import android.os.Parcel; 23import android.os.Parcelable; 24 25import com.android.settings.R; 26import com.android.settings.Utils; 27 28import java.util.ArrayList; 29 30public class ProcStatsPackageEntry implements Parcelable { 31 private static final String TAG = "ProcStatsEntry"; 32 private static boolean DEBUG = ProcessStatsUi.DEBUG; 33 34 private static final float ALWAYS_THRESHOLD = .95f; 35 private static final float SOMETIMES_THRESHOLD = .25f; 36 37 final String mPackage; 38 final ArrayList<ProcStatsEntry> mEntries = new ArrayList<ProcStatsEntry>(); 39 40 long mBgDuration; 41 long mAvgBgMem; 42 long mMaxBgMem; 43 double mBgWeight; 44 long mRunDuration; 45 long mAvgRunMem; 46 long mMaxRunMem; 47 double mRunWeight; 48 49 public ApplicationInfo mUiTargetApp; 50 public String mUiLabel; 51 private long mWindowLength; 52 53 public ProcStatsPackageEntry(String pkg, long windowLength) { 54 mPackage = pkg; 55 mWindowLength = windowLength; 56 } 57 58 public ProcStatsPackageEntry(Parcel in) { 59 mPackage = in.readString(); 60 in.readTypedList(mEntries, ProcStatsEntry.CREATOR); 61 mBgDuration = in.readLong(); 62 mAvgBgMem = in.readLong(); 63 mMaxBgMem = in.readLong(); 64 mBgWeight = in.readDouble(); 65 mRunDuration = in.readLong(); 66 mAvgRunMem = in.readLong(); 67 mMaxRunMem = in.readLong(); 68 mRunWeight = in.readDouble(); 69 } 70 71 public CharSequence getRunningFrequency(Context context) { 72 float amountRunning = mRunDuration / (float) mWindowLength; 73 return getFrequency(amountRunning, context); 74 } 75 76 public CharSequence getBackgroundFrequency(Context context) { 77 float amountRunning = mBgDuration / (float) mWindowLength; 78 return getFrequency(amountRunning, context); 79 } 80 81 public void addEntry(ProcStatsEntry entry) { 82 mEntries.add(entry); 83 } 84 85 public void updateMetrics() { 86 mBgDuration = mAvgBgMem = mMaxBgMem = 0; 87 mBgWeight = 0; 88 mRunDuration = mAvgRunMem = mMaxRunMem = 0; 89 mRunWeight = 0; 90 final int N = mEntries.size(); 91 for (int i=0; i < N; i++) { 92 ProcStatsEntry entry = mEntries.get(i); 93 mBgDuration = Math.max(entry.mBgDuration, mBgDuration); 94 mAvgBgMem += entry.mAvgBgMem; 95 mBgWeight += entry.mBgWeight; 96 mRunDuration = Math.max(entry.mRunDuration, mRunDuration); 97 mAvgRunMem += entry.mAvgRunMem; 98 mRunWeight += entry.mRunWeight; 99 100 // Each entry is generally a process or something similar. Since it is extremely 101 // unlikely that any apps are going to avoid running processes at the same time 102 // to avoid memory usage, we will sum the maximum memory usage to create a 103 // hypothetical worst case scenario of memory. 104 mMaxBgMem += entry.mMaxBgMem; 105 mMaxRunMem += entry.mMaxRunMem; 106 } 107 mAvgBgMem /= N; 108 mAvgRunMem /= N; 109 } 110 111 public void retrieveUiData(Context context, PackageManager pm) { 112 mUiTargetApp = null; 113 mUiLabel = mPackage; 114 // Only one app associated with this process. 115 try { 116 if ("os".equals(mPackage)) { 117 mUiTargetApp = pm.getApplicationInfo("android", 118 PackageManager.GET_DISABLED_COMPONENTS | 119 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | 120 PackageManager.GET_UNINSTALLED_PACKAGES); 121 mUiLabel = context.getString(R.string.process_stats_os_label); 122 } else { 123 mUiTargetApp = pm.getApplicationInfo(mPackage, 124 PackageManager.GET_DISABLED_COMPONENTS | 125 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | 126 PackageManager.GET_UNINSTALLED_PACKAGES); 127 mUiLabel = mUiTargetApp.loadLabel(pm).toString(); 128 } 129 } catch (PackageManager.NameNotFoundException e) { 130 } 131 } 132 133 @Override 134 public int describeContents() { 135 return 0; 136 } 137 138 @Override 139 public void writeToParcel(Parcel dest, int flags) { 140 dest.writeString(mPackage); 141 dest.writeTypedList(mEntries); 142 dest.writeLong(mBgDuration); 143 dest.writeLong(mAvgBgMem); 144 dest.writeLong(mMaxBgMem); 145 dest.writeDouble(mBgWeight); 146 dest.writeLong(mRunDuration); 147 dest.writeLong(mAvgRunMem); 148 dest.writeLong(mMaxRunMem); 149 dest.writeDouble(mRunWeight); 150 } 151 152 public static final Parcelable.Creator<ProcStatsPackageEntry> CREATOR 153 = new Parcelable.Creator<ProcStatsPackageEntry>() { 154 public ProcStatsPackageEntry createFromParcel(Parcel in) { 155 return new ProcStatsPackageEntry(in); 156 } 157 158 public ProcStatsPackageEntry[] newArray(int size) { 159 return new ProcStatsPackageEntry[size]; 160 } 161 }; 162 163 // TODO: Find better place for this. 164 public static CharSequence getFrequency(float amount, Context context) { 165 if (amount > ALWAYS_THRESHOLD) { 166 return context.getString(R.string.always_running, 167 Utils.formatPercentage((int) (amount * 100))); 168 } else if (amount > SOMETIMES_THRESHOLD) { 169 return context.getString(R.string.sometimes_running, 170 Utils.formatPercentage((int) (amount * 100))); 171 } else { 172 return context.getString(R.string.rarely_running, 173 Utils.formatPercentage((int) (amount * 100))); 174 } 175 } 176} 177