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 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 
     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 
     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 
     98     public void addPackage(String packageName) {
     99         mPackages.add(packageName);
    100     }
    101 
    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 
    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 
    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
    276     public int describeContents() {
    277         return 0;
    278     }
    279 
    280     @Override
    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 
    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 
    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
    335         public int describeContents() {
    336             return 0;
    337         }
    338 
    339         @Override
    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