Home | History | Annotate | Download | only in applications
      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 
     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 
     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 
     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 
    116     public void addPackage(String packageName) {
    117         mPackages.add(packageName);
    118     }
    119 
    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 
    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
    267     public int describeContents() {
    268         return 0;
    269     }
    270 
    271     @Override
    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 
    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 
    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
    327         public int describeContents() {
    328             return 0;
    329         }
    330 
    331         @Override
    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