Merge "Fix issue #10948509: Crash in procstats when there is no data" into klp-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
768dc8f729
@@ -801,7 +801,8 @@
|
|||||||
<activity android:name="Settings$AppOpsSummaryActivity"
|
<activity android:name="Settings$AppOpsSummaryActivity"
|
||||||
android:label="@string/app_ops_settings"
|
android:label="@string/app_ops_settings"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
android:excludeFromRecents="true">
|
android:excludeFromRecents="true"
|
||||||
|
android:enabled="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<action android:name="android.settings.APP_OPS_SETTINGS" />
|
<action android:name="android.settings.APP_OPS_SETTINGS" />
|
||||||
|
@@ -21,8 +21,8 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
|
||||||
import com.android.internal.app.ProcessStats;
|
import com.android.internal.app.ProcessStats;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -31,11 +31,12 @@ import java.util.Comparator;
|
|||||||
|
|
||||||
public final class ProcStatsEntry implements Parcelable {
|
public final class ProcStatsEntry implements Parcelable {
|
||||||
private static final String TAG = "ProcStatsEntry";
|
private static final String TAG = "ProcStatsEntry";
|
||||||
|
private static boolean DEBUG = ProcessStatsUi.DEBUG;
|
||||||
|
|
||||||
final String mPackage;
|
final String mPackage;
|
||||||
final int mUid;
|
final int mUid;
|
||||||
final String mName;
|
final String mName;
|
||||||
final boolean mUnique;
|
final ArrayList<String> mPackages = new ArrayList<String>();
|
||||||
final long mDuration;
|
final long mDuration;
|
||||||
final long mAvgPss;
|
final long mAvgPss;
|
||||||
final long mMaxPss;
|
final long mMaxPss;
|
||||||
@@ -45,33 +46,35 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
|
|
||||||
String mBestTargetPackage;
|
String mBestTargetPackage;
|
||||||
|
|
||||||
ArrayList<Service> mServices = new ArrayList<Service>(2);
|
ArrayMap<String, ArrayList<Service>> mServices = new ArrayMap<String, ArrayList<Service>>(1);
|
||||||
|
|
||||||
public ApplicationInfo mUiTargetApp;
|
public ApplicationInfo mUiTargetApp;
|
||||||
public String mUiLabel;
|
public String mUiLabel;
|
||||||
public String mUiBaseLabel;
|
public String mUiBaseLabel;
|
||||||
public String mUiPackage;
|
public String mUiPackage;
|
||||||
|
|
||||||
public ProcStatsEntry(ProcessStats.ProcessState proc,
|
public ProcStatsEntry(ProcessStats.ProcessState proc, String packageName,
|
||||||
ProcessStats.ProcessDataCollection tmpTotals, boolean useUss, boolean weightWithTime) {
|
ProcessStats.ProcessDataCollection tmpTotals, boolean useUss, boolean weightWithTime) {
|
||||||
ProcessStats.computeProcessData(proc, tmpTotals, 0);
|
ProcessStats.computeProcessData(proc, tmpTotals, 0);
|
||||||
mPackage = proc.mPackage;
|
mPackage = proc.mPackage;
|
||||||
mUid = proc.mUid;
|
mUid = proc.mUid;
|
||||||
mName = proc.mName;
|
mName = proc.mName;
|
||||||
mUnique = proc.mCommonProcess == proc;
|
mPackages.add(packageName);
|
||||||
mDuration = tmpTotals.totalTime;
|
mDuration = tmpTotals.totalTime;
|
||||||
mAvgPss = tmpTotals.avgPss;
|
mAvgPss = tmpTotals.avgPss;
|
||||||
mMaxPss = tmpTotals.maxPss;
|
mMaxPss = tmpTotals.maxPss;
|
||||||
mAvgUss = tmpTotals.avgUss;
|
mAvgUss = tmpTotals.avgUss;
|
||||||
mMaxUss = tmpTotals.maxUss;
|
mMaxUss = tmpTotals.maxUss;
|
||||||
mWeight = (weightWithTime ? mDuration : 1) * (useUss ? mAvgUss : mAvgPss);
|
mWeight = (weightWithTime ? mDuration : 1) * (useUss ? mAvgUss : mAvgPss);
|
||||||
|
if (DEBUG) Log.d(TAG, "New proc entry " + proc.mName + ": dur=" + mDuration
|
||||||
|
+ " avgpss=" + mAvgPss + " weight=" + mWeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProcStatsEntry(Parcel in) {
|
public ProcStatsEntry(Parcel in) {
|
||||||
mPackage = in.readString();
|
mPackage = in.readString();
|
||||||
mUid = in.readInt();
|
mUid = in.readInt();
|
||||||
mName = in.readString();
|
mName = in.readString();
|
||||||
mUnique = in.readInt() != 0;
|
in.readStringList(mPackages);
|
||||||
mDuration = in.readLong();
|
mDuration = in.readLong();
|
||||||
mAvgPss = in.readLong();
|
mAvgPss = in.readLong();
|
||||||
mMaxPss = in.readLong();
|
mMaxPss = in.readLong();
|
||||||
@@ -79,40 +82,118 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
mMaxUss = in.readLong();
|
mMaxUss = in.readLong();
|
||||||
mWeight = in.readLong();
|
mWeight = in.readLong();
|
||||||
mBestTargetPackage = in.readString();
|
mBestTargetPackage = in.readString();
|
||||||
in.readTypedList(mServices, Service.CREATOR);
|
final int N = in.readInt();
|
||||||
|
if (N > 0) {
|
||||||
|
mServices.ensureCapacity(N);
|
||||||
|
for (int i=0; i<N; i++) {
|
||||||
|
String key = in.readString();
|
||||||
|
ArrayList<Service> value = new ArrayList<Service>();
|
||||||
|
in.readTypedList(value, Service.CREATOR);
|
||||||
|
mServices.append(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void evaluateTargetPackage(ProcessStats stats, ProcessStats.ProcessDataCollection totals,
|
public void addPackage(String packageName) {
|
||||||
Comparator<ProcStatsEntry> compare, boolean useUss, boolean weightWithTime) {
|
mPackages.add(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evaluateTargetPackage(PackageManager pm, ProcessStats stats,
|
||||||
|
ProcessStats.ProcessDataCollection totals, Comparator<ProcStatsEntry> compare,
|
||||||
|
boolean useUss, boolean weightWithTime) {
|
||||||
mBestTargetPackage = null;
|
mBestTargetPackage = null;
|
||||||
if (mUnique) {
|
if (mPackages.size() == 1) {
|
||||||
mBestTargetPackage = mPackage;
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": single pkg " + mPackages.get(0));
|
||||||
|
mBestTargetPackage = mPackages.get(0);
|
||||||
} else {
|
} else {
|
||||||
// See if there is one significant package that was running here.
|
// See if there is one significant package that was running here.
|
||||||
ArrayList<ProcStatsEntry> subProcs = new ArrayList<ProcStatsEntry>();
|
ArrayList<ProcStatsEntry> subProcs = new ArrayList<ProcStatsEntry>();
|
||||||
for (int ipkg=0, NPKG=stats.mPackages.getMap().size(); ipkg<NPKG; ipkg++) {
|
for (int ipkg=0; ipkg<mPackages.size(); ipkg++) {
|
||||||
SparseArray<ProcessStats.PackageState> uids
|
ProcessStats.PackageState pkgState = stats.mPackages.get(mPackages.get(ipkg), mUid);
|
||||||
= stats.mPackages.getMap().valueAt(ipkg);
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ", pkg "
|
||||||
for (int iu=0, NU=uids.size(); iu<NU; iu++) {
|
+ mPackages.get(ipkg) + ":");
|
||||||
if (uids.keyAt(iu) != mUid) {
|
if (pkgState == null) {
|
||||||
continue;
|
Log.w(TAG, "No package state found for " + mPackages.get(ipkg) + "/"
|
||||||
}
|
+ mUid + " in process " + mName);
|
||||||
ProcessStats.PackageState pkgState = uids.valueAt(iu);
|
continue;
|
||||||
for (int iproc=0, NPROC=pkgState.mProcesses.size(); iproc<NPROC; iproc++) {
|
|
||||||
ProcessStats.ProcessState subProc =
|
|
||||||
pkgState.mProcesses.valueAt(iproc);
|
|
||||||
if (subProc.mName.equals(mName)) {
|
|
||||||
subProcs.add(new ProcStatsEntry(subProc, totals, useUss,
|
|
||||||
weightWithTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ProcessStats.ProcessState pkgProc = pkgState.mProcesses.get(mName);
|
||||||
|
if (pkgProc == null) {
|
||||||
|
Log.w(TAG, "No process " + mName + " found in package state "
|
||||||
|
+ mPackages.get(ipkg) + "/" + mUid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
subProcs.add(new ProcStatsEntry(pkgProc, pkgState.mPackageName, totals, useUss,
|
||||||
|
weightWithTime));
|
||||||
}
|
}
|
||||||
if (subProcs.size() > 1) {
|
if (subProcs.size() > 1) {
|
||||||
Collections.sort(subProcs, compare);
|
Collections.sort(subProcs, compare);
|
||||||
if (subProcs.get(0).mWeight > (subProcs.get(1).mWeight*3)) {
|
if (subProcs.get(0).mWeight > (subProcs.get(1).mWeight*3)) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": best pkg "
|
||||||
|
+ subProcs.get(0).mPackage + " weight " + subProcs.get(0).mWeight
|
||||||
|
+ " better than " + subProcs.get(1).mPackage
|
||||||
|
+ " weight " + subProcs.get(1).mWeight);
|
||||||
mBestTargetPackage = subProcs.get(0).mPackage;
|
mBestTargetPackage = subProcs.get(0).mPackage;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// Couldn't find one that is best by weight, let's decide on best another
|
||||||
|
// way: the one that has the longest running service, accounts for at least
|
||||||
|
// half of the maximum weight, and has specified an explicit app icon.
|
||||||
|
long maxWeight = subProcs.get(0).mWeight;
|
||||||
|
long bestRunTime = -1;
|
||||||
|
for (int i=0; i<subProcs.size(); i++) {
|
||||||
|
if (subProcs.get(i).mWeight < (maxWeight/2)) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
|
+ subProcs.get(i).mPackage + " weight " + subProcs.get(i).mWeight
|
||||||
|
+ " too small");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ApplicationInfo ai = pm.getApplicationInfo(subProcs.get(i).mPackage, 0);
|
||||||
|
if (ai.icon == 0) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
|
+ subProcs.get(i).mPackage + " has no icon");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
|
+ subProcs.get(i).mPackage + " failed finding app info");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ArrayList<Service> subProcServices = null;
|
||||||
|
for (int isp=0, NSP=mServices.size(); isp<NSP; isp++) {
|
||||||
|
ArrayList<Service> subServices = mServices.valueAt(isp);
|
||||||
|
if (subServices.get(0).mPackage.equals(subProcs.get(i).mPackage)) {
|
||||||
|
subProcServices = subServices;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long thisRunTime = 0;
|
||||||
|
if (subProcServices != null) {
|
||||||
|
for (int iss=0, NSS=subProcServices.size(); iss<NSS; iss++) {
|
||||||
|
Service service = subProcServices.get(iss);
|
||||||
|
if (service.mDuration > thisRunTime) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
|
+ subProcs.get(i).mPackage + " service " + service.mName
|
||||||
|
+ " run time is " + service.mDuration);
|
||||||
|
thisRunTime = service.mDuration;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (thisRunTime > bestRunTime) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
|
+ subProcs.get(i).mPackage + " new best run time " + thisRunTime);
|
||||||
|
mBestTargetPackage = subProcs.get(i).mPackage;
|
||||||
|
bestRunTime = thisRunTime;
|
||||||
|
} else {
|
||||||
|
if (DEBUG) Log.d(TAG, "Eval pkg of " + mName + ": pkg "
|
||||||
|
+ subProcs.get(i).mPackage + " run time " + thisRunTime
|
||||||
|
+ " not as good as last " + bestRunTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (subProcs.size() == 1) {
|
||||||
|
mBestTargetPackage = subProcs.get(0).mPackage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +259,12 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addService(ProcessStats.ServiceState svc) {
|
public void addService(ProcessStats.ServiceState svc) {
|
||||||
mServices.add(new Service(svc));
|
ArrayList<Service> services = mServices.get(svc.mPackage);
|
||||||
|
if (services == null) {
|
||||||
|
services = new ArrayList<Service>();
|
||||||
|
mServices.put(svc.mPackage, services);
|
||||||
|
}
|
||||||
|
services.add(new Service(svc));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -191,7 +277,7 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
dest.writeString(mPackage);
|
dest.writeString(mPackage);
|
||||||
dest.writeInt(mUid);
|
dest.writeInt(mUid);
|
||||||
dest.writeString(mName);
|
dest.writeString(mName);
|
||||||
dest.writeInt(mUnique ? 1 : 0);
|
dest.writeStringList(mPackages);
|
||||||
dest.writeLong(mDuration);
|
dest.writeLong(mDuration);
|
||||||
dest.writeLong(mAvgPss);
|
dest.writeLong(mAvgPss);
|
||||||
dest.writeLong(mMaxPss);
|
dest.writeLong(mMaxPss);
|
||||||
@@ -199,7 +285,12 @@ public final class ProcStatsEntry implements Parcelable {
|
|||||||
dest.writeLong(mMaxUss);
|
dest.writeLong(mMaxUss);
|
||||||
dest.writeLong(mWeight);
|
dest.writeLong(mWeight);
|
||||||
dest.writeString(mBestTargetPackage);
|
dest.writeString(mBestTargetPackage);
|
||||||
dest.writeTypedList(mServices);
|
final int N = mServices.size();
|
||||||
|
dest.writeInt(N);
|
||||||
|
for (int i=0; i<N; i++) {
|
||||||
|
dest.writeString(mServices.keyAt(i));
|
||||||
|
dest.writeTypedList(mServices.valueAt(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<ProcStatsEntry> CREATOR
|
public static final Parcelable.Creator<ProcStatsEntry> CREATOR
|
||||||
|
@@ -168,6 +168,23 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addPackageHeaderItem(ViewGroup parent, String packageName) {
|
||||||
|
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||||
|
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.running_processes_item,
|
||||||
|
null);
|
||||||
|
parent.addView(item);
|
||||||
|
final ImageView icon = (ImageView) item.findViewById(R.id.icon);
|
||||||
|
TextView nameView = (TextView) item.findViewById(R.id.name);
|
||||||
|
TextView descriptionView = (TextView) item.findViewById(R.id.description);
|
||||||
|
try {
|
||||||
|
ApplicationInfo ai = mPm.getApplicationInfo(packageName, 0);
|
||||||
|
icon.setImageDrawable(ai.loadIcon(mPm));
|
||||||
|
nameView.setText(ai.loadLabel(mPm));
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
}
|
||||||
|
descriptionView.setText(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
private void addDetailsItem(ViewGroup parent, CharSequence label, CharSequence value) {
|
private void addDetailsItem(ViewGroup parent, CharSequence label, CharSequence value) {
|
||||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||||
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text,
|
ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text,
|
||||||
@@ -204,22 +221,31 @@ public class ProcessStatsDetail extends Fragment implements Button.OnClickListen
|
|||||||
};
|
};
|
||||||
|
|
||||||
private void fillServicesSection() {
|
private void fillServicesSection() {
|
||||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
|
||||||
if (mEntry.mServices.size() > 0) {
|
if (mEntry.mServices.size() > 0) {
|
||||||
ArrayList<ProcStatsEntry.Service> services =
|
boolean addPackageSections = false;
|
||||||
(ArrayList<ProcStatsEntry.Service>)mEntry.mServices.clone();
|
if (mEntry.mServices.size() > 1
|
||||||
Collections.sort(services, sServiceCompare);
|
|| !mEntry.mServices.valueAt(0).get(0).mPackage.equals(mEntry.mPackage)) {
|
||||||
for (int i=0; i<services.size(); i++) {
|
addPackageSections = true;
|
||||||
ProcStatsEntry.Service service = services.get(i);
|
}
|
||||||
String label = service.mName;
|
for (int ip=0; ip<mEntry.mServices.size(); ip++) {
|
||||||
int tail = label.lastIndexOf('.');
|
ArrayList<ProcStatsEntry.Service> services =
|
||||||
if (tail >= 0 && tail < (label.length()-1)) {
|
(ArrayList<ProcStatsEntry.Service>)mEntry.mServices.valueAt(ip).clone();
|
||||||
label = label.substring(tail+1);
|
Collections.sort(services, sServiceCompare);
|
||||||
|
if (addPackageSections) {
|
||||||
|
addPackageHeaderItem(mServicesParent, services.get(0).mPackage);
|
||||||
|
}
|
||||||
|
for (int is=0; is<services.size(); is++) {
|
||||||
|
ProcStatsEntry.Service service = services.get(is);
|
||||||
|
String label = service.mName;
|
||||||
|
int tail = label.lastIndexOf('.');
|
||||||
|
if (tail >= 0 && tail < (label.length()-1)) {
|
||||||
|
label = label.substring(tail+1);
|
||||||
|
}
|
||||||
|
long duration = service.mDuration;
|
||||||
|
final double percentOfTime = (((double)duration) / mTotalTime) * 100;
|
||||||
|
addDetailsItem(mServicesParent, label, getActivity().getResources().getString(
|
||||||
|
R.string.percentage, (int) Math.ceil(percentOfTime)));
|
||||||
}
|
}
|
||||||
long duration = service.mDuration;
|
|
||||||
final double percentOfTime = (((double)duration) / mTotalTime) * 100;
|
|
||||||
addDetailsItem(mServicesParent, label, getActivity().getResources().getString(
|
|
||||||
R.string.percentage, (int) Math.ceil(percentOfTime)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -45,7 +45,7 @@ public class ProcessStatsPreference extends Preference {
|
|||||||
public void setPercent(double percentOfWeight, double percentOfTime) {
|
public void setPercent(double percentOfWeight, double percentOfTime) {
|
||||||
mProgress = (int) Math.ceil(percentOfWeight);
|
mProgress = (int) Math.ceil(percentOfWeight);
|
||||||
mProgressText = getContext().getResources().getString(
|
mProgressText = getContext().getResources().getString(
|
||||||
R.string.percentage, (int) Math.ceil(percentOfTime));
|
R.string.percentage, (int) Math.round(percentOfTime));
|
||||||
notifyChanged();
|
notifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,7 +19,6 @@ package com.android.settings.applications;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
@@ -30,7 +29,6 @@ import android.preference.PreferenceActivity;
|
|||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.PreferenceGroup;
|
import android.preference.PreferenceGroup;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.util.ArrayMap;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.TimeUtils;
|
import android.util.TimeUtils;
|
||||||
@@ -39,6 +37,7 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.SubMenu;
|
import android.view.SubMenu;
|
||||||
import com.android.internal.app.IProcessStats;
|
import com.android.internal.app.IProcessStats;
|
||||||
|
import com.android.internal.app.ProcessMap;
|
||||||
import com.android.internal.app.ProcessStats;
|
import com.android.internal.app.ProcessStats;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.fuelgauge.Utils;
|
import com.android.settings.fuelgauge.Utils;
|
||||||
@@ -50,8 +49,8 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
public class ProcessStatsUi extends PreferenceFragment {
|
public class ProcessStatsUi extends PreferenceFragment {
|
||||||
private static final String TAG = "ProcessStatsUi";
|
static final String TAG = "ProcessStatsUi";
|
||||||
private static final boolean DEBUG = false;
|
static final boolean DEBUG = false;
|
||||||
|
|
||||||
private static final String KEY_APP_LIST = "app_list";
|
private static final String KEY_APP_LIST = "app_list";
|
||||||
private static final String KEY_MEM_STATUS = "mem_status";
|
private static final String KEY_MEM_STATUS = "mem_status";
|
||||||
@@ -76,6 +75,10 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
return 1;
|
return 1;
|
||||||
} else if (lhs.mWeight > rhs.mWeight) {
|
} else if (lhs.mWeight > rhs.mWeight) {
|
||||||
return -1;
|
return -1;
|
||||||
|
} else if (lhs.mDuration < rhs.mDuration) {
|
||||||
|
return 1;
|
||||||
|
} else if (lhs.mDuration > rhs.mDuration) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -112,7 +115,7 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
// batches of 3 hours so we want to allow the time we use to be slightly
|
// batches of 3 hours so we want to allow the time we use to be slightly
|
||||||
// smaller than the actual time selected instead of bumping up to 3 hours
|
// smaller than the actual time selected instead of bumping up to 3 hours
|
||||||
// beyond it.
|
// beyond it.
|
||||||
private static final long DURATION_QUANTUM = 3*60*60*1000;
|
private static final long DURATION_QUANTUM = ProcessStats.COMMIT_PERIOD;
|
||||||
private static long[] sDurations = new long[] {
|
private static long[] sDurations = new long[] {
|
||||||
3*60*60*1000 - DURATION_QUANTUM/2, 6*60*60*1000 - DURATION_QUANTUM/2,
|
3*60*60*1000 - DURATION_QUANTUM/2, 6*60*60*1000 - DURATION_QUANTUM/2,
|
||||||
12*60*60*1000 - DURATION_QUANTUM/2, 24*60*60*1000 - DURATION_QUANTUM/2
|
12*60*60*1000 - DURATION_QUANTUM/2, 24*60*60*1000 - DURATION_QUANTUM/2
|
||||||
@@ -319,6 +322,12 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
ProcessStats.STATE_CACHED_EMPTY
|
ProcessStats.STATE_CACHED_EMPTY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private String makeDuration(long time) {
|
||||||
|
StringBuilder sb = new StringBuilder(32);
|
||||||
|
TimeUtils.formatDuration(time, sb);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private void refreshStats() {
|
private void refreshStats() {
|
||||||
updateMenus();
|
updateMenus();
|
||||||
|
|
||||||
@@ -378,6 +387,7 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
|
|
||||||
mTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations,
|
mTotalTime = ProcessStats.dumpSingleTime(null, null, mStats.mMemFactorDurations,
|
||||||
mStats.mMemFactor, mStats.mStartTime, now);
|
mStats.mMemFactor, mStats.mStartTime, now);
|
||||||
|
if (DEBUG) Log.d(TAG, "Total time of stats: " + makeDuration(mTotalTime));
|
||||||
|
|
||||||
LinearColorPreference colors = new LinearColorPreference(getActivity());
|
LinearColorPreference colors = new LinearColorPreference(getActivity());
|
||||||
colors.setOrder(-1);
|
colors.setOrder(-1);
|
||||||
@@ -396,7 +406,7 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
+ memTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]) / (float)mTotalTime,
|
+ memTimes[ProcessStats.ADJ_MEM_FACTOR_MODERATE]) / (float)mTotalTime,
|
||||||
memTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL] / (float)mTotalTime);
|
memTimes[ProcessStats.ADJ_MEM_FACTOR_NORMAL] / (float)mTotalTime);
|
||||||
|
|
||||||
ArrayList<ProcStatsEntry> procs = new ArrayList<ProcStatsEntry>();
|
ArrayList<ProcStatsEntry> entries = new ArrayList<ProcStatsEntry>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked(
|
ArrayList<ProcessStats.ProcessState> rawProcs = mStats.collectProcessesLocked(
|
||||||
@@ -407,50 +417,43 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ArrayMap<String, ProcStatsEntry> processes = new ArrayMap<String, ProcStatsEntry>(
|
if (DEBUG) Log.d(TAG, "-------------------- PULLING PROCESSES");
|
||||||
mStats.mProcesses.getMap().size());
|
|
||||||
for (int ip=0, N=mStats.mProcesses.getMap().size(); ip<N; ip++) {
|
final ProcessMap<ProcStatsEntry> entriesMap = new ProcessMap<ProcStatsEntry>();
|
||||||
SparseArray<ProcessStats.ProcessState> uids = mStats.mProcesses.getMap().valueAt(ip);
|
for (int ipkg=0, N=mStats.mPackages.getMap().size(); ipkg<N; ipkg++) {
|
||||||
for (int iu=0; iu<uids.size(); iu++) {
|
final SparseArray<ProcessStats.PackageState> pkgUids
|
||||||
ProcStatsEntry ent = new ProcStatsEntry(uids.valueAt(iu), totals, mUseUss,
|
= mStats.mPackages.getMap().valueAt(ipkg);
|
||||||
mStatsType == MENU_TYPE_BACKGROUND);
|
for (int iu=0; iu<pkgUids.size(); iu++) {
|
||||||
procs.add(ent);
|
final ProcessStats.PackageState st = pkgUids.valueAt(iu);
|
||||||
processes.put(ent.mName, ent);
|
for (int iproc=0; iproc<st.mProcesses.size(); iproc++) {
|
||||||
|
final ProcessStats.ProcessState pkgProc = st.mProcesses.valueAt(iproc);
|
||||||
|
final ProcessStats.ProcessState proc = mStats.mProcesses.get(pkgProc.mName,
|
||||||
|
pkgProc.mUid);
|
||||||
|
if (proc == null) {
|
||||||
|
Log.w(TAG, "No process found for pkg " + st.mPackageName
|
||||||
|
+ "/" + st.mUid + " proc name " + pkgProc.mName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ProcStatsEntry ent = entriesMap.get(proc.mName, proc.mUid);
|
||||||
|
if (ent == null) {
|
||||||
|
ent = new ProcStatsEntry(proc, st.mPackageName, totals, mUseUss,
|
||||||
|
mStatsType == MENU_TYPE_BACKGROUND);
|
||||||
|
if (ent.mDuration > 0) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Adding proc " + proc.mName + "/"
|
||||||
|
+ proc.mUid + ": time=" + makeDuration(ent.mDuration) + " ("
|
||||||
|
+ ((((double)ent.mDuration) / mTotalTime) * 100) + "%)"
|
||||||
|
+ " pss=" + ent.mAvgPss);
|
||||||
|
entriesMap.put(proc.mName, proc.mUid, ent);
|
||||||
|
entries.add(ent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ent.addPackage(st.mPackageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(procs, sEntryCompare);
|
if (DEBUG) Log.d(TAG, "-------------------- MAPPING SERVICES");
|
||||||
while (procs.size() > MAX_ITEMS_TO_LIST) {
|
|
||||||
procs.remove(procs.size()-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
long maxWeight = 0;
|
|
||||||
for (int i=0, N=(procs != null ? procs.size() : 0); i<N; i++) {
|
|
||||||
ProcStatsEntry proc = procs.get(i);
|
|
||||||
if (maxWeight < proc.mWeight) {
|
|
||||||
maxWeight = proc.mWeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mMaxWeight = maxWeight;
|
|
||||||
|
|
||||||
for (int i=0, N=(procs != null ? procs.size() : 0); i<N; i++) {
|
|
||||||
ProcStatsEntry proc = procs.get(i);
|
|
||||||
final double percentOfWeight = (((double)proc.mWeight) / maxWeight) * 100;
|
|
||||||
final double percentOfTime = (((double)proc.mDuration) / mTotalTime) * 100;
|
|
||||||
if (percentOfWeight < 1) break;
|
|
||||||
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null, proc);
|
|
||||||
proc.evaluateTargetPackage(mStats, totals, sEntryCompare, mUseUss,
|
|
||||||
mStatsType == MENU_TYPE_BACKGROUND);
|
|
||||||
proc.retrieveUiData(pm);
|
|
||||||
pref.setTitle(proc.mUiLabel);
|
|
||||||
if (proc.mUiTargetApp != null) {
|
|
||||||
pref.setIcon(proc.mUiTargetApp.loadIcon(pm));
|
|
||||||
}
|
|
||||||
pref.setOrder(i);
|
|
||||||
pref.setPercent(percentOfWeight, percentOfTime);
|
|
||||||
mAppListGroup.addPreference(pref);
|
|
||||||
if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add in service info.
|
// Add in service info.
|
||||||
if (mStatsType == MENU_TYPE_BACKGROUND) {
|
if (mStatsType == MENU_TYPE_BACKGROUND) {
|
||||||
@@ -461,13 +464,85 @@ public class ProcessStatsUi extends PreferenceFragment {
|
|||||||
for (int is=0, NS=ps.mServices.size(); is<NS; is++) {
|
for (int is=0, NS=ps.mServices.size(); is<NS; is++) {
|
||||||
ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
|
ProcessStats.ServiceState ss = ps.mServices.valueAt(is);
|
||||||
if (ss.mProcessName != null) {
|
if (ss.mProcessName != null) {
|
||||||
ProcStatsEntry ent = processes.get(ss.mProcessName);
|
ProcStatsEntry ent = entriesMap.get(ss.mProcessName, uids.keyAt(iu));
|
||||||
ent.addService(ss);
|
if (ent != null) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Adding service " + ps.mPackageName
|
||||||
|
+ "/" + ss.mName + "/" + uids.keyAt(iu) + " to proc "
|
||||||
|
+ ss.mProcessName);
|
||||||
|
ent.addService(ss);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "No process " + ss.mProcessName + "/" + uids.keyAt(iu)
|
||||||
|
+ " for service " + ss.mName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
SparseArray<ArrayMap<String, ProcStatsEntry>> processes
|
||||||
|
= new SparseArray<ArrayMap<String, ProcStatsEntry>>();
|
||||||
|
for (int ip=0, N=mStats.mProcesses.getMap().size(); ip<N; ip++) {
|
||||||
|
SparseArray<ProcessStats.ProcessState> uids = mStats.mProcesses.getMap().valueAt(ip);
|
||||||
|
for (int iu=0; iu<uids.size(); iu++) {
|
||||||
|
ProcessStats.ProcessState st = uids.valueAt(iu);
|
||||||
|
ProcStatsEntry ent = new ProcStatsEntry(st, totals, mUseUss,
|
||||||
|
mStatsType == MENU_TYPE_BACKGROUND);
|
||||||
|
if (ent.mDuration > 0) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Adding proc " + st.mName + "/" + st.mUid + ": time="
|
||||||
|
+ makeDuration(ent.mDuration) + " ("
|
||||||
|
+ ((((double)ent.mDuration) / mTotalTime) * 100) + "%)");
|
||||||
|
procs.add(ent);
|
||||||
|
ArrayMap<String, ProcStatsEntry> uidProcs = processes.get(ent.mUid);
|
||||||
|
if (uidProcs == null) {
|
||||||
|
uidProcs = new ArrayMap<String, ProcStatsEntry>();
|
||||||
|
processes.put(ent.mUid, uidProcs);
|
||||||
|
}
|
||||||
|
uidProcs.put(ent.mName, ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Collections.sort(entries, sEntryCompare);
|
||||||
|
|
||||||
|
long maxWeight = 1;
|
||||||
|
for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) {
|
||||||
|
ProcStatsEntry proc = entries.get(i);
|
||||||
|
if (maxWeight < proc.mWeight) {
|
||||||
|
maxWeight = proc.mWeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mMaxWeight = maxWeight;
|
||||||
|
|
||||||
|
if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI");
|
||||||
|
|
||||||
|
for (int i=0, N=(entries != null ? entries.size() : 0); i<N; i++) {
|
||||||
|
ProcStatsEntry proc = entries.get(i);
|
||||||
|
final double percentOfWeight = (((double)proc.mWeight) / maxWeight) * 100;
|
||||||
|
final double percentOfTime = (((double)proc.mDuration) / mTotalTime) * 100;
|
||||||
|
if (percentOfWeight < 1 && percentOfTime < 33) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Skipping " + proc.mName + " weight=" + percentOfWeight
|
||||||
|
+ " time=" + percentOfTime);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ProcessStatsPreference pref = new ProcessStatsPreference(getActivity(), null, proc);
|
||||||
|
proc.evaluateTargetPackage(pm, mStats, totals, sEntryCompare, mUseUss,
|
||||||
|
mStatsType == MENU_TYPE_BACKGROUND);
|
||||||
|
proc.retrieveUiData(pm);
|
||||||
|
pref.setTitle(proc.mUiLabel);
|
||||||
|
if (proc.mUiTargetApp != null) {
|
||||||
|
pref.setIcon(proc.mUiTargetApp.loadIcon(pm));
|
||||||
|
}
|
||||||
|
pref.setOrder(i);
|
||||||
|
pref.setPercent(percentOfWeight, percentOfTime);
|
||||||
|
mAppListGroup.addPreference(pref);
|
||||||
|
if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST+1)) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Done with UI, hit item limit!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void load() {
|
private void load() {
|
||||||
|
Reference in New Issue
Block a user