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