• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.pm.ApplicationInfo;
20 import android.content.pm.PackageManager;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.ArrayMap;
24 import android.util.Log;
25 import android.util.SparseArray;
26 
27 import com.android.internal.app.procstats.ProcessStats;
28 import com.android.internal.app.procstats.ProcessState;
29 import com.android.internal.app.procstats.ServiceState;
30 
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.Comparator;
34 
35 public final class ProcStatsEntry implements Parcelable {
36     private static final String TAG = "ProcStatsEntry";
37     private static boolean DEBUG = ProcessStatsUi.DEBUG;
38 
39     final String mPackage;
40     final int mUid;
41     final String mName;
42     public CharSequence mLabel;
43     final ArrayList<String> mPackages = new ArrayList<String>();
44     final long mBgDuration;
45     final long mAvgBgMem;
46     final long mMaxBgMem;
47     final double mBgWeight;
48     final long mRunDuration;
49     final long mAvgRunMem;
50     final long mMaxRunMem;
51     final double mRunWeight;
52 
53     String mBestTargetPackage;
54 
55     ArrayMap<String, ArrayList<Service>> mServices = new ArrayMap<String, ArrayList<Service>>(1);
56 
ProcStatsEntry(ProcessState proc, String packageName, ProcessStats.ProcessDataCollection tmpBgTotals, ProcessStats.ProcessDataCollection tmpRunTotals, boolean useUss)57     public ProcStatsEntry(ProcessState proc, String packageName,
58             ProcessStats.ProcessDataCollection tmpBgTotals,
59             ProcessStats.ProcessDataCollection tmpRunTotals, boolean useUss) {
60         proc.computeProcessData(tmpBgTotals, 0);
61         proc.computeProcessData(tmpRunTotals, 0);
62         mPackage = proc.getPackage();
63         mUid = proc.getUid();
64         mName = proc.getName();
65         mPackages.add(packageName);
66         mBgDuration = tmpBgTotals.totalTime;
67         mAvgBgMem = useUss ? tmpBgTotals.avgUss : tmpBgTotals.avgPss;
68         mMaxBgMem = useUss ? tmpBgTotals.maxUss : tmpBgTotals.maxPss;
69         mBgWeight = mAvgBgMem * (double) mBgDuration;
70         mRunDuration = tmpRunTotals.totalTime;
71         mAvgRunMem = useUss ? tmpRunTotals.avgUss : tmpRunTotals.avgPss;
72         mMaxRunMem = useUss ? tmpRunTotals.maxUss : tmpRunTotals.maxPss;
73         mRunWeight = mAvgRunMem * (double) mRunDuration;
74         if (DEBUG) Log.d(TAG, "New proc entry " + proc.getName() + ": dur=" + mBgDuration
75                 + " avgpss=" + mAvgBgMem + " weight=" + mBgWeight);
76     }
77 
ProcStatsEntry(String pkgName, int uid, String procName, long duration, long mem, long memDuration)78     public ProcStatsEntry(String pkgName, int uid, String procName, long duration, long mem,
79             long memDuration) {
80         mPackage = pkgName;
81         mUid = uid;
82         mName = procName;
83         mBgDuration = mRunDuration = duration;
84         mAvgBgMem = mMaxBgMem = mAvgRunMem = mMaxRunMem = mem;
85         mBgWeight = mRunWeight = ((double)memDuration) * mem;
86         if (DEBUG) Log.d(TAG, "New proc entry " + procName + ": dur=" + mBgDuration
87                 + " avgpss=" + mAvgBgMem + " weight=" + mBgWeight);
88     }
89 
ProcStatsEntry(Parcel in)90     public ProcStatsEntry(Parcel in) {
91         mPackage = in.readString();
92         mUid = in.readInt();
93         mName = in.readString();
94         in.readStringList(mPackages);
95         mBgDuration = in.readLong();
96         mAvgBgMem = in.readLong();
97         mMaxBgMem = in.readLong();
98         mBgWeight = in.readDouble();
99         mRunDuration = in.readLong();
100         mAvgRunMem = in.readLong();
101         mMaxRunMem = in.readLong();
102         mRunWeight = in.readDouble();
103         mBestTargetPackage = in.readString();
104         final int N = in.readInt();
105         if (N > 0) {
106             mServices.ensureCapacity(N);
107             for (int i=0; i<N; i++) {
108                 String key = in.readString();
109                 ArrayList<Service> value = new ArrayList<Service>();
110                 in.readTypedList(value, Service.CREATOR);
111                 mServices.append(key, value);
112             }
113         }
114     }
115 
addPackage(String packageName)116     public void addPackage(String packageName) {
117         mPackages.add(packageName);
118     }
119 
evaluateTargetPackage(PackageManager pm, ProcessStats stats, ProcessStats.ProcessDataCollection bgTotals, ProcessStats.ProcessDataCollection runTotals, Comparator<ProcStatsEntry> compare, boolean useUss)120     public void evaluateTargetPackage(PackageManager pm, ProcessStats stats,
121             ProcessStats.ProcessDataCollection bgTotals,
122             ProcessStats.ProcessDataCollection runTotals, Comparator<ProcStatsEntry> compare,
123             boolean useUss) {
124         mBestTargetPackage = null;
125         if (mPackages.size() == 1) {
126             if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": single pkg " + mPackages.get(0));
127             mBestTargetPackage = mPackages.get(0);
128             return;
129         }
130 
131         // If one of the packages is the framework itself, that wins.
132         // See if there is one significant package that was running here.
133         for (int ipkg=0; ipkg<mPackages.size(); ipkg++) {
134             if ("android".equals(mPackages.get(ipkg))) {
135                 mBestTargetPackage = mPackages.get(ipkg);
136                 return;
137             }
138         }
139 
140         // Collect information about each package running in the process.
141         ArrayList<ProcStatsEntry> subProcs = new ArrayList<>();
142         for (int ipkg=0; ipkg<mPackages.size(); ipkg++) {
143             SparseArray<ProcessStats.PackageState> vpkgs
144                     = stats.mPackages.get(mPackages.get(ipkg), mUid);
145             for (int ivers=0;  ivers<vpkgs.size(); ivers++) {
146                 ProcessStats.PackageState pkgState = vpkgs.valueAt(ivers);
147                 if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ", pkg "
148                         + pkgState + ":");
149                 if (pkgState == null) {
150                     Log.w(TAG, "No package state found for " + mPackages.get(ipkg) + "/"
151                             + mUid + " in process " + mName);
152                     continue;
153                 }
154                 ProcessState pkgProc = pkgState.mProcesses.get(mName);
155                 if (pkgProc == null) {
156                     Log.w(TAG, "No process " + mName + " found in package state "
157                             + mPackages.get(ipkg) + "/" + mUid);
158                     continue;
159                 }
160                 subProcs.add(new ProcStatsEntry(pkgProc, pkgState.mPackageName, bgTotals,
161                         runTotals, useUss));
162             }
163         }
164 
165         if (subProcs.size() > 1) {
166             Collections.sort(subProcs, compare);
167             if (subProcs.get(0).mRunWeight > (subProcs.get(1).mRunWeight *3)) {
168                 if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": best pkg "
169                         + subProcs.get(0).mPackage + " weight " + subProcs.get(0).mRunWeight
170                         + " better than " + subProcs.get(1).mPackage
171                         + " weight " + subProcs.get(1).mRunWeight);
172                 mBestTargetPackage = subProcs.get(0).mPackage;
173                 return;
174             }
175             // Couldn't find one that is best by weight, let's decide on best another
176             // way: the one that has the longest running service, accounts for at least
177             // half of the maximum weight, and has specified an explicit app icon.
178             double maxWeight = subProcs.get(0).mRunWeight;
179             long bestRunTime = -1;
180             boolean bestPersistent = false;
181             for (int i=0; i<subProcs.size(); i++) {
182                 final ProcStatsEntry subProc = subProcs.get(i);
183                 if (subProc.mRunWeight < (maxWeight/2)) {
184                     if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
185                             + subProc.mPackage + " weight " + subProc.mRunWeight
186                             + " too small");
187                     continue;
188                 }
189                 try {
190                     ApplicationInfo ai = pm.getApplicationInfo(subProc.mPackage, 0);
191                     if (ai.icon == 0) {
192                         if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
193                                 + subProc.mPackage + " has no icon");
194                         continue;
195                     }
196                     if ((ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0) {
197                         long thisRunTime = subProc.mRunDuration;
198                         if (!bestPersistent || thisRunTime > bestRunTime) {
199                             if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
200                                     + subProc.mPackage + " new best pers run time "
201                                     + thisRunTime);
202                             bestRunTime = thisRunTime;
203                             bestPersistent = true;
204                         } else {
205                             if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
206                                     + subProc.mPackage + " pers run time " + thisRunTime
207                                     + " not as good as last " + bestRunTime);
208                         }
209                         continue;
210                     } else if (bestPersistent) {
211                         if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
212                                 + subProc.mPackage + " is not persistent");
213                         continue;
214                     }
215                 } catch (PackageManager.NameNotFoundException e) {
216                     if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
217                             + subProc.mPackage + " failed finding app info");
218                     continue;
219                 }
220                 ArrayList<Service> subProcServices = null;
221                 for (int isp=0, NSP=mServices.size(); isp<NSP; isp++) {
222                     ArrayList<Service> subServices = mServices.valueAt(isp);
223                     if (subServices.get(0).mPackage.equals(subProc.mPackage)) {
224                         subProcServices = subServices;
225                         break;
226                     }
227                 }
228                 long thisRunTime = 0;
229                 if (subProcServices != null) {
230                     for (int iss=0, NSS=subProcServices.size(); iss<NSS; iss++) {
231                         Service service = subProcServices.get(iss);
232                         if (service.mDuration > thisRunTime) {
233                             if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
234                                     + subProc.mPackage + " service " + service.mName
235                                     + " run time is " + service.mDuration);
236                             thisRunTime = service.mDuration;
237                             break;
238                         }
239                     }
240                 }
241                 if (thisRunTime > bestRunTime) {
242                     if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
243                             + subProc.mPackage + " new best run time " + thisRunTime);
244                     mBestTargetPackage = subProc.mPackage;
245                     bestRunTime = thisRunTime;
246                 } else {
247                     if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
248                             + subProc.mPackage + " run time " + thisRunTime
249                             + " not as good as last " + bestRunTime);
250                 }
251             }
252         } else if (subProcs.size() == 1) {
253             mBestTargetPackage = subProcs.get(0).mPackage;
254         }
255     }
256 
addService(ServiceState svc)257     public void addService(ServiceState svc) {
258         ArrayList<Service> services = mServices.get(svc.getPackage());
259         if (services == null) {
260             services = new ArrayList<Service>();
261             mServices.put(svc.getPackage(), services);
262         }
263         services.add(new Service(svc));
264     }
265 
266     @Override
describeContents()267     public int describeContents() {
268         return 0;
269     }
270 
271     @Override
writeToParcel(Parcel dest, int flags)272     public void writeToParcel(Parcel dest, int flags) {
273         dest.writeString(mPackage);
274         dest.writeInt(mUid);
275         dest.writeString(mName);
276         dest.writeStringList(mPackages);
277         dest.writeLong(mBgDuration);
278         dest.writeLong(mAvgBgMem);
279         dest.writeLong(mMaxBgMem);
280         dest.writeDouble(mBgWeight);
281         dest.writeLong(mRunDuration);
282         dest.writeLong(mAvgRunMem);
283         dest.writeLong(mMaxRunMem);
284         dest.writeDouble(mRunWeight);
285         dest.writeString(mBestTargetPackage);
286         final int N = mServices.size();
287         dest.writeInt(N);
288         for (int i=0; i<N; i++) {
289             dest.writeString(mServices.keyAt(i));
290             dest.writeTypedList(mServices.valueAt(i));
291         }
292     }
293 
294     public static final Parcelable.Creator<ProcStatsEntry> CREATOR
295             = new Parcelable.Creator<ProcStatsEntry>() {
296         public ProcStatsEntry createFromParcel(Parcel in) {
297             return new ProcStatsEntry(in);
298         }
299 
300         public ProcStatsEntry[] newArray(int size) {
301             return new ProcStatsEntry[size];
302         }
303     };
304 
305     public static final class Service implements Parcelable {
306         final String mPackage;
307         final String mName;
308         final String mProcess;
309         final long mDuration;
310 
Service(ServiceState service)311         public Service(ServiceState service) {
312             mPackage = service.getPackage();
313             mName = service.getName();
314             mProcess = service.getProcessName();
315             mDuration = service.dumpTime(null, null,
316                     ServiceState.SERVICE_RUN, ProcessStats.STATE_NOTHING, 0, 0);
317         }
318 
Service(Parcel in)319         public Service(Parcel in) {
320             mPackage = in.readString();
321             mName = in.readString();
322             mProcess = in.readString();
323             mDuration = in.readLong();
324         }
325 
326         @Override
describeContents()327         public int describeContents() {
328             return 0;
329         }
330 
331         @Override
writeToParcel(Parcel dest, int flags)332         public void writeToParcel(Parcel dest, int flags) {
333             dest.writeString(mPackage);
334             dest.writeString(mName);
335             dest.writeString(mProcess);
336             dest.writeLong(mDuration);
337         }
338 
339         public static final Parcelable.Creator<Service> CREATOR
340                 = new Parcelable.Creator<Service>() {
341             public Service createFromParcel(Parcel in) {
342                 return new Service(in);
343             }
344 
345             public Service[] newArray(int size) {
346                 return new Service[size];
347             }
348         };
349     }
350 }
351