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