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