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