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