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