Allow user to see and stop heavy-weight processes.
Change-Id: If5caed3972ab03a54fbf8c459cdfc136e4bdc020
This commit is contained in:
@@ -1788,6 +1788,9 @@ found in the list of installed applications.</string>
|
|||||||
<!-- Running service details, default description for services that are started. -->
|
<!-- Running service details, default description for services that are started. -->
|
||||||
<string name="service_stop_description">This service was started by its
|
<string name="service_stop_description">This service was started by its
|
||||||
application. Stopping it may cause the application to fail.</string>
|
application. Stopping it may cause the application to fail.</string>
|
||||||
|
<!-- Running service details, description for running heavy-weight process. -->
|
||||||
|
<string name="heavy_weight_stop_description">This application can not safely
|
||||||
|
be stopped. Doing so may lose some of your current work.</string>
|
||||||
<!-- Running service details, default description for services that are managed. -->
|
<!-- Running service details, default description for services that are managed. -->
|
||||||
<string name="service_manage_description"><xliff:g id="client_name">%1$s</xliff:g>:
|
<string name="service_manage_description"><xliff:g id="client_name">%1$s</xliff:g>:
|
||||||
currently in use. Touch Settings to control it.</string>
|
currently in use. Touch Settings to control it.</string>
|
||||||
|
@@ -130,8 +130,16 @@ public class RunningProcessesView extends FrameLayout
|
|||||||
uptimeView.setText(DateUtils.formatElapsedTime(builder,
|
uptimeView.setText(DateUtils.formatElapsedTime(builder,
|
||||||
(SystemClock.uptimeMillis()-mFirstRunTime)/1000));
|
(SystemClock.uptimeMillis()-mFirstRunTime)/1000));
|
||||||
} else {
|
} else {
|
||||||
uptimeView.setText(context.getResources().getText(
|
boolean isService = false;
|
||||||
R.string.service_restarting));
|
if (mItem instanceof RunningState.MergedItem) {
|
||||||
|
isService = ((RunningState.MergedItem)mItem).mServices.size() > 0;
|
||||||
|
}
|
||||||
|
if (isService) {
|
||||||
|
uptimeView.setText(context.getResources().getText(
|
||||||
|
R.string.service_restarting));
|
||||||
|
} else {
|
||||||
|
uptimeView.setText("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,8 @@ public class RunningServiceDetails extends Activity {
|
|||||||
RunningProcessesView.ActiveItem mSnippetActiveItem;
|
RunningProcessesView.ActiveItem mSnippetActiveItem;
|
||||||
RunningProcessesView.ViewHolder mSnippetViewHolder;
|
RunningProcessesView.ViewHolder mSnippetViewHolder;
|
||||||
|
|
||||||
|
int mNumServices, mNumProcesses;
|
||||||
|
|
||||||
TextView mServicesHeader;
|
TextView mServicesHeader;
|
||||||
TextView mProcessesHeader;
|
TextView mProcessesHeader;
|
||||||
final ArrayList<ActiveDetail> mActiveDetails = new ArrayList<ActiveDetail>();
|
final ArrayList<ActiveDetail> mActiveDetails = new ArrayList<ActiveDetail>();
|
||||||
@@ -79,7 +81,7 @@ public class RunningServiceDetails extends Activity {
|
|||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (mActiveItem.mItem instanceof RunningState.ServiceItem) {
|
||||||
RunningState.ServiceItem si = (RunningState.ServiceItem)mActiveItem.mItem;
|
RunningState.ServiceItem si = (RunningState.ServiceItem)mActiveItem.mItem;
|
||||||
stopService(new Intent().setComponent(si.mRunningService.service));
|
stopService(new Intent().setComponent(si.mRunningService.service));
|
||||||
if (mMergedItem == null || mMergedItem.mServices.size() <= 1) {
|
if (mMergedItem == null || mMergedItem.mServices.size() <= 1) {
|
||||||
@@ -91,6 +93,10 @@ public class RunningServiceDetails extends Activity {
|
|||||||
mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS);
|
mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Heavy-weight process. We'll do a force-stop on it.
|
||||||
|
mAm.forceStopPackage(mActiveItem.mItem.mPackageInfo.packageName);
|
||||||
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,6 +169,129 @@ public class RunningServiceDetails extends Activity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addServiceDetailsView(RunningState.ServiceItem si, RunningState.MergedItem mi) {
|
||||||
|
if (mNumServices == 0) {
|
||||||
|
mServicesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
|
||||||
|
mAllDetails, false);
|
||||||
|
mServicesHeader.setText(R.string.runningservicedetails_services_title);
|
||||||
|
mAllDetails.addView(mServicesHeader);
|
||||||
|
}
|
||||||
|
mNumServices++;
|
||||||
|
|
||||||
|
RunningState.BaseItem bi = si != null ? si : mi;
|
||||||
|
|
||||||
|
ActiveDetail detail = new ActiveDetail();
|
||||||
|
View root = mInflater.inflate(R.layout.running_service_details_service,
|
||||||
|
mAllDetails, false);
|
||||||
|
mAllDetails.addView(root);
|
||||||
|
detail.mRootView = root;
|
||||||
|
detail.mViewHolder = new RunningProcessesView.ViewHolder(root);
|
||||||
|
detail.mActiveItem = detail.mViewHolder.bind(mState, bi, mBuilder);
|
||||||
|
|
||||||
|
if (si != null && si.mRunningService.clientLabel != 0) {
|
||||||
|
detail.mManageIntent = mAm.getRunningServiceControlPanel(
|
||||||
|
si.mRunningService.service);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView description = (TextView)root.findViewById(R.id.comp_description);
|
||||||
|
if (si != null && si.mServiceInfo.descriptionRes != 0) {
|
||||||
|
description.setText(getPackageManager().getText(
|
||||||
|
si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes,
|
||||||
|
si.mServiceInfo.applicationInfo));
|
||||||
|
} else {
|
||||||
|
if (detail.mManageIntent != null) {
|
||||||
|
try {
|
||||||
|
Resources clientr = getPackageManager().getResourcesForApplication(
|
||||||
|
si.mRunningService.clientPackage);
|
||||||
|
String label = clientr.getString(si.mRunningService.clientLabel);
|
||||||
|
description.setText(getString(R.string.service_manage_description,
|
||||||
|
label));
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
description.setText(getText(si != null
|
||||||
|
? R.string.service_stop_description
|
||||||
|
: R.string.heavy_weight_stop_description));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
View button = root.findViewById(R.id.right_button);
|
||||||
|
button.setOnClickListener(detail);
|
||||||
|
((TextView)button).setText(getText(detail.mManageIntent != null
|
||||||
|
? R.string.service_manage : R.string.service_stop));
|
||||||
|
root.findViewById(R.id.left_button).setVisibility(View.INVISIBLE);
|
||||||
|
|
||||||
|
mActiveDetails.add(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addProcessDetailsView(RunningState.ProcessItem pi, boolean isMain) {
|
||||||
|
if (mNumProcesses == 0) {
|
||||||
|
mProcessesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
|
||||||
|
mAllDetails, false);
|
||||||
|
mProcessesHeader.setText(R.string.runningservicedetails_processes_title);
|
||||||
|
mAllDetails.addView(mProcessesHeader);
|
||||||
|
}
|
||||||
|
mNumProcesses++;
|
||||||
|
|
||||||
|
ActiveDetail detail = new ActiveDetail();
|
||||||
|
View root = mInflater.inflate(R.layout.running_service_details_process,
|
||||||
|
mAllDetails, false);
|
||||||
|
mAllDetails.addView(root);
|
||||||
|
detail.mRootView = root;
|
||||||
|
detail.mViewHolder = new RunningProcessesView.ViewHolder(root);
|
||||||
|
detail.mActiveItem = detail.mViewHolder.bind(mState, pi, mBuilder);
|
||||||
|
|
||||||
|
TextView description = (TextView)root.findViewById(R.id.comp_description);
|
||||||
|
if (isMain) {
|
||||||
|
description.setText(R.string.main_running_process_description);
|
||||||
|
} else {
|
||||||
|
int textid = 0;
|
||||||
|
CharSequence label = null;
|
||||||
|
ActivityManager.RunningAppProcessInfo rpi = pi.mRunningProcessInfo;
|
||||||
|
final ComponentName comp = rpi.importanceReasonComponent;
|
||||||
|
//Log.i(TAG, "Secondary proc: code=" + rpi.importanceReasonCode
|
||||||
|
// + " pid=" + rpi.importanceReasonPid + " comp=" + comp);
|
||||||
|
switch (rpi.importanceReasonCode) {
|
||||||
|
case ActivityManager.RunningAppProcessInfo.REASON_PROVIDER_IN_USE:
|
||||||
|
textid = R.string.process_provider_in_use_description;
|
||||||
|
List<ProviderInfo> providers = null;
|
||||||
|
if (comp != null) {
|
||||||
|
providers = getPackageManager()
|
||||||
|
.queryContentProviders(comp.getPackageName(),
|
||||||
|
rpi.uid, 0);
|
||||||
|
}
|
||||||
|
if (providers != null) {
|
||||||
|
for (int j=0; j<providers.size(); j++) {
|
||||||
|
ProviderInfo prov = providers.get(j);
|
||||||
|
if (comp.getClassName().equals(prov.name)) {
|
||||||
|
label = RunningState.makeLabel(getPackageManager(),
|
||||||
|
prov.name, prov);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE:
|
||||||
|
textid = R.string.process_service_in_use_description;
|
||||||
|
if (rpi.importanceReasonComponent != null) {
|
||||||
|
try {
|
||||||
|
ServiceInfo serv = getPackageManager().getServiceInfo(
|
||||||
|
rpi.importanceReasonComponent, 0);
|
||||||
|
label = RunningState.makeLabel(getPackageManager(),
|
||||||
|
serv.name, serv);
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (textid != 0 && label != null) {
|
||||||
|
description.setText(getString(textid, label));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mActiveDetails.add(detail);
|
||||||
|
}
|
||||||
|
|
||||||
void addDetailViews() {
|
void addDetailViews() {
|
||||||
for (int i=mActiveDetails.size()-1; i>=0; i--) {
|
for (int i=mActiveDetails.size()-1; i>=0; i--) {
|
||||||
mAllDetails.removeView(mActiveDetails.get(i).mRootView);
|
mAllDetails.removeView(mActiveDetails.get(i).mRootView);
|
||||||
@@ -179,58 +308,20 @@ public class RunningServiceDetails extends Activity {
|
|||||||
mProcessesHeader = null;
|
mProcessesHeader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mNumServices = mNumProcesses = 0;
|
||||||
|
|
||||||
if (mMergedItem != null) {
|
if (mMergedItem != null) {
|
||||||
for (int i=0; i<mMergedItem.mServices.size(); i++) {
|
for (int i=0; i<mMergedItem.mServices.size(); i++) {
|
||||||
if (i == 0) {
|
addServiceDetailsView(mMergedItem.mServices.get(i), mMergedItem);
|
||||||
mServicesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
|
}
|
||||||
mAllDetails, false);
|
|
||||||
mServicesHeader.setText(R.string.runningservicedetails_services_title);
|
if (mMergedItem.mServices.size() <= 0) {
|
||||||
mAllDetails.addView(mServicesHeader);
|
// This item does not have any services, so it must be
|
||||||
}
|
// a heavy-weight process... we will put a fake service
|
||||||
RunningState.ServiceItem si = mMergedItem.mServices.get(i);
|
// entry for it, to allow the user to "stop" it.
|
||||||
ActiveDetail detail = new ActiveDetail();
|
addServiceDetailsView(null, mMergedItem);
|
||||||
View root = mInflater.inflate(R.layout.running_service_details_service,
|
|
||||||
mAllDetails, false);
|
|
||||||
mAllDetails.addView(root);
|
|
||||||
detail.mRootView = root;
|
|
||||||
detail.mViewHolder = new RunningProcessesView.ViewHolder(root);
|
|
||||||
detail.mActiveItem = detail.mViewHolder.bind(mState, si, mBuilder);
|
|
||||||
|
|
||||||
if (si.mRunningService.clientLabel != 0) {
|
|
||||||
detail.mManageIntent = mAm.getRunningServiceControlPanel(
|
|
||||||
si.mRunningService.service);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextView description = (TextView)root.findViewById(R.id.comp_description);
|
|
||||||
if (si.mServiceInfo.descriptionRes != 0) {
|
|
||||||
description.setText(getPackageManager().getText(
|
|
||||||
si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes,
|
|
||||||
si.mServiceInfo.applicationInfo));
|
|
||||||
} else {
|
|
||||||
if (detail.mManageIntent != null) {
|
|
||||||
try {
|
|
||||||
Resources clientr = getPackageManager().getResourcesForApplication(
|
|
||||||
si.mRunningService.clientPackage);
|
|
||||||
String label = clientr.getString(si.mRunningService.clientLabel);
|
|
||||||
description.setText(getString(R.string.service_manage_description,
|
|
||||||
label));
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
description.setText(getText(R.string.service_stop_description));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
View button = root.findViewById(R.id.right_button);
|
|
||||||
button.setOnClickListener(detail);
|
|
||||||
((TextView)button).setText(getText(detail.mManageIntent != null
|
|
||||||
? R.string.service_manage : R.string.service_stop));
|
|
||||||
root.findViewById(R.id.left_button).setVisibility(View.INVISIBLE);
|
|
||||||
|
|
||||||
mActiveDetails.add(detail);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean didProcess = false;
|
|
||||||
for (int i=-1; i<mMergedItem.mOtherProcesses.size(); i++) {
|
for (int i=-1; i<mMergedItem.mOtherProcesses.size(); i++) {
|
||||||
RunningState.ProcessItem pi = i < 0 ? mMergedItem.mProcess
|
RunningState.ProcessItem pi = i < 0 ? mMergedItem.mProcess
|
||||||
: mMergedItem.mOtherProcesses.get(i);
|
: mMergedItem.mOtherProcesses.get(i);
|
||||||
@@ -238,70 +329,7 @@ public class RunningServiceDetails extends Activity {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!didProcess) {
|
addProcessDetailsView(pi, i < 0);
|
||||||
mProcessesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
|
|
||||||
mAllDetails, false);
|
|
||||||
mProcessesHeader.setText(R.string.runningservicedetails_processes_title);
|
|
||||||
mAllDetails.addView(mProcessesHeader);
|
|
||||||
didProcess = true;
|
|
||||||
}
|
|
||||||
ActiveDetail detail = new ActiveDetail();
|
|
||||||
View root = mInflater.inflate(R.layout.running_service_details_process,
|
|
||||||
mAllDetails, false);
|
|
||||||
mAllDetails.addView(root);
|
|
||||||
detail.mRootView = root;
|
|
||||||
detail.mViewHolder = new RunningProcessesView.ViewHolder(root);
|
|
||||||
detail.mActiveItem = detail.mViewHolder.bind(mState, pi, mBuilder);
|
|
||||||
|
|
||||||
TextView description = (TextView)root.findViewById(R.id.comp_description);
|
|
||||||
if (i < 0) {
|
|
||||||
description.setText(R.string.main_running_process_description);
|
|
||||||
} else {
|
|
||||||
int textid = 0;
|
|
||||||
CharSequence label = null;
|
|
||||||
ActivityManager.RunningAppProcessInfo rpi = pi.mRunningProcessInfo;
|
|
||||||
final ComponentName comp = rpi.importanceReasonComponent;
|
|
||||||
//Log.i(TAG, "Secondary proc: code=" + rpi.importanceReasonCode
|
|
||||||
// + " pid=" + rpi.importanceReasonPid + " comp=" + comp);
|
|
||||||
switch (rpi.importanceReasonCode) {
|
|
||||||
case ActivityManager.RunningAppProcessInfo.REASON_PROVIDER_IN_USE:
|
|
||||||
textid = R.string.process_provider_in_use_description;
|
|
||||||
List<ProviderInfo> providers = null;
|
|
||||||
if (comp != null) {
|
|
||||||
providers = getPackageManager()
|
|
||||||
.queryContentProviders(comp.getPackageName(),
|
|
||||||
rpi.uid, 0);
|
|
||||||
}
|
|
||||||
if (providers != null) {
|
|
||||||
for (int j=0; j<providers.size(); j++) {
|
|
||||||
ProviderInfo prov = providers.get(i);
|
|
||||||
if (comp.getClassName().equals(prov.name)) {
|
|
||||||
label = RunningState.makeLabel(getPackageManager(),
|
|
||||||
prov.name, prov);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE:
|
|
||||||
textid = R.string.process_service_in_use_description;
|
|
||||||
if (rpi.importanceReasonComponent != null) {
|
|
||||||
try {
|
|
||||||
ServiceInfo serv = getPackageManager().getServiceInfo(
|
|
||||||
rpi.importanceReasonComponent, 0);
|
|
||||||
label = RunningState.makeLabel(getPackageManager(),
|
|
||||||
serv.name, serv);
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (textid != 0 && label != null) {
|
|
||||||
description.setText(getString(textid, label));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mActiveDetails.add(detail);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -47,18 +47,34 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class RunningState {
|
public class RunningState {
|
||||||
|
|
||||||
final SparseArray<HashMap<String, ProcessItem>> mProcesses
|
// Processes that are hosting a service we are interested in, organized
|
||||||
|
// by uid and name. Note that this mapping does not change even across
|
||||||
|
// service restarts, and during a restart there will still be a process
|
||||||
|
// entry.
|
||||||
|
final SparseArray<HashMap<String, ProcessItem>> mServiceProcessesByName
|
||||||
= new SparseArray<HashMap<String, ProcessItem>>();
|
= new SparseArray<HashMap<String, ProcessItem>>();
|
||||||
final SparseArray<ProcessItem> mActiveProcesses
|
|
||||||
|
// Processes that are hosting a service we are interested in, organized
|
||||||
|
// by their pid. These disappear and re-appear as services are restarted.
|
||||||
|
final SparseArray<ProcessItem> mServiceProcessesByPid
|
||||||
= new SparseArray<ProcessItem>();
|
= new SparseArray<ProcessItem>();
|
||||||
|
|
||||||
|
// Used to sort the interesting processes.
|
||||||
final ServiceProcessComparator mServiceProcessComparator
|
final ServiceProcessComparator mServiceProcessComparator
|
||||||
= new ServiceProcessComparator();
|
= new ServiceProcessComparator();
|
||||||
|
|
||||||
// Temporary for finding process dependencies.
|
// Additional heavy-weight processes to be shown to the user, even if
|
||||||
|
// there is no service running in them.
|
||||||
|
final ArrayList<ProcessItem> mHeavyProcesses = new ArrayList<ProcessItem>();
|
||||||
|
|
||||||
|
// All currently running processes, for finding dependencies etc.
|
||||||
final SparseArray<ProcessItem> mRunningProcesses
|
final SparseArray<ProcessItem> mRunningProcesses
|
||||||
= new SparseArray<ProcessItem>();
|
= new SparseArray<ProcessItem>();
|
||||||
|
|
||||||
|
// The processes associated with services, in sorted order.
|
||||||
final ArrayList<ProcessItem> mProcessItems = new ArrayList<ProcessItem>();
|
final ArrayList<ProcessItem> mProcessItems = new ArrayList<ProcessItem>();
|
||||||
|
|
||||||
|
// All processes, used for retrieving memory information.
|
||||||
final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>();
|
final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>();
|
||||||
|
|
||||||
int mSequence = 0;
|
int mSequence = 0;
|
||||||
@@ -128,6 +144,8 @@ public class RunningState {
|
|||||||
int mRunningSeq;
|
int mRunningSeq;
|
||||||
ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
|
ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
|
||||||
|
|
||||||
|
MergedItem mMergedItem;
|
||||||
|
|
||||||
// Purely for sorting.
|
// Purely for sorting.
|
||||||
boolean mIsSystem;
|
boolean mIsSystem;
|
||||||
boolean mIsStarted;
|
boolean mIsStarted;
|
||||||
@@ -435,10 +453,10 @@ public class RunningState {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMap<String, ProcessItem> procs = mProcesses.get(si.uid);
|
HashMap<String, ProcessItem> procs = mServiceProcessesByName.get(si.uid);
|
||||||
if (procs == null) {
|
if (procs == null) {
|
||||||
procs = new HashMap<String, ProcessItem>();
|
procs = new HashMap<String, ProcessItem>();
|
||||||
mProcesses.put(si.uid, procs);
|
mServiceProcessesByName.put(si.uid, procs);
|
||||||
}
|
}
|
||||||
ProcessItem proc = procs.get(si.process);
|
ProcessItem proc = procs.get(si.process);
|
||||||
if (proc == null) {
|
if (proc == null) {
|
||||||
@@ -453,10 +471,10 @@ public class RunningState {
|
|||||||
changed = true;
|
changed = true;
|
||||||
if (proc.mPid != pid) {
|
if (proc.mPid != pid) {
|
||||||
if (proc.mPid != 0) {
|
if (proc.mPid != 0) {
|
||||||
mActiveProcesses.remove(proc.mPid);
|
mServiceProcessesByPid.remove(proc.mPid);
|
||||||
}
|
}
|
||||||
if (pid != 0) {
|
if (pid != 0) {
|
||||||
mActiveProcesses.put(pid, proc);
|
mServiceProcessesByPid.put(pid, proc);
|
||||||
}
|
}
|
||||||
proc.mPid = pid;
|
proc.mPid = pid;
|
||||||
}
|
}
|
||||||
@@ -474,19 +492,30 @@ public class RunningState {
|
|||||||
final int NP = processes != null ? processes.size() : 0;
|
final int NP = processes != null ? processes.size() : 0;
|
||||||
for (int i=0; i<NP; i++) {
|
for (int i=0; i<NP; i++) {
|
||||||
ActivityManager.RunningAppProcessInfo pi = processes.get(i);
|
ActivityManager.RunningAppProcessInfo pi = processes.get(i);
|
||||||
ProcessItem proc = mActiveProcesses.get(pi.pid);
|
ProcessItem proc = mServiceProcessesByPid.get(pi.pid);
|
||||||
if (proc == null) {
|
if (proc == null) {
|
||||||
// This process is not one that is a direct container
|
// This process is not one that is a direct container
|
||||||
// of a service, so look for it in the secondary
|
// of a service, so look for it in the secondary
|
||||||
// running list.
|
// running list.
|
||||||
proc = mRunningProcesses.get(pi.pid);
|
proc = mRunningProcesses.get(pi.pid);
|
||||||
if (proc == null) {
|
if (proc == null) {
|
||||||
|
changed = true;
|
||||||
proc = new ProcessItem(context, pi.uid, pi.processName);
|
proc = new ProcessItem(context, pi.uid, pi.processName);
|
||||||
proc.mPid = pi.pid;
|
proc.mPid = pi.pid;
|
||||||
mRunningProcesses.put(pi.pid, proc);
|
mRunningProcesses.put(pi.pid, proc);
|
||||||
}
|
}
|
||||||
proc.mDependentProcesses.clear();
|
proc.mDependentProcesses.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_HEAVY_WEIGHT) != 0) {
|
||||||
|
if (!mHeavyProcesses.contains(proc)) {
|
||||||
|
changed = true;
|
||||||
|
mHeavyProcesses.add(proc);
|
||||||
|
}
|
||||||
|
proc.mCurSeq = mSequence;
|
||||||
|
proc.ensureLabel(pm);
|
||||||
|
}
|
||||||
|
|
||||||
proc.mRunningSeq = mSequence;
|
proc.mRunningSeq = mSequence;
|
||||||
proc.mRunningProcessInfo = pi;
|
proc.mRunningProcessInfo = pi;
|
||||||
}
|
}
|
||||||
@@ -499,7 +528,7 @@ public class RunningState {
|
|||||||
if (proc.mRunningSeq == mSequence) {
|
if (proc.mRunningSeq == mSequence) {
|
||||||
int clientPid = proc.mRunningProcessInfo.importanceReasonPid;
|
int clientPid = proc.mRunningProcessInfo.importanceReasonPid;
|
||||||
if (clientPid != 0) {
|
if (clientPid != 0) {
|
||||||
ProcessItem client = mActiveProcesses.get(clientPid);
|
ProcessItem client = mServiceProcessesByPid.get(clientPid);
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
client = mRunningProcesses.get(clientPid);
|
client = mRunningProcesses.get(clientPid);
|
||||||
}
|
}
|
||||||
@@ -508,29 +537,42 @@ public class RunningState {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// In this pass the process doesn't have a client.
|
// In this pass the process doesn't have a client.
|
||||||
// Clear to make sure if it later gets the same one
|
// Clear to make sure that, if it later gets the same one,
|
||||||
// that we will detect the change.
|
// we will detect the change.
|
||||||
proc.mClient = null;
|
proc.mClient = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
changed = true;
|
||||||
mRunningProcesses.remove(mRunningProcesses.keyAt(i));
|
mRunningProcesses.remove(mRunningProcesses.keyAt(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove any old heavy processes.
|
||||||
|
int NHP = mHeavyProcesses.size();
|
||||||
|
for (int i=0; i<NHP; i++) {
|
||||||
|
ProcessItem proc = mHeavyProcesses.get(i);
|
||||||
|
if (mRunningProcesses.get(proc.mPid) == null) {
|
||||||
|
changed = true;
|
||||||
|
mHeavyProcesses.remove(i);
|
||||||
|
i--;
|
||||||
|
NHP--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Follow the tree from all primary service processes to all
|
// Follow the tree from all primary service processes to all
|
||||||
// processes they are dependent on, marking these processes as
|
// processes they are dependent on, marking these processes as
|
||||||
// still being active and determining if anything has changed.
|
// still being active and determining if anything has changed.
|
||||||
final int NAP = mActiveProcesses.size();
|
final int NAP = mServiceProcessesByPid.size();
|
||||||
for (int i=0; i<NAP; i++) {
|
for (int i=0; i<NAP; i++) {
|
||||||
ProcessItem proc = mActiveProcesses.valueAt(i);
|
ProcessItem proc = mServiceProcessesByPid.valueAt(i);
|
||||||
if (proc.mCurSeq == mSequence) {
|
if (proc.mCurSeq == mSequence) {
|
||||||
changed |= proc.buildDependencyChain(context, pm, mSequence);
|
changed |= proc.buildDependencyChain(context, pm, mSequence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for services and their primary processes that no longer exist...
|
// Look for services and their primary processes that no longer exist...
|
||||||
for (int i=0; i<mProcesses.size(); i++) {
|
for (int i=0; i<mServiceProcessesByName.size(); i++) {
|
||||||
HashMap<String, ProcessItem> procs = mProcesses.valueAt(i);
|
HashMap<String, ProcessItem> procs = mServiceProcessesByName.valueAt(i);
|
||||||
Iterator<ProcessItem> pit = procs.values().iterator();
|
Iterator<ProcessItem> pit = procs.values().iterator();
|
||||||
while (pit.hasNext()) {
|
while (pit.hasNext()) {
|
||||||
ProcessItem pi = pit.next();
|
ProcessItem pi = pit.next();
|
||||||
@@ -545,10 +587,10 @@ public class RunningState {
|
|||||||
changed = true;
|
changed = true;
|
||||||
pit.remove();
|
pit.remove();
|
||||||
if (procs.size() == 0) {
|
if (procs.size() == 0) {
|
||||||
mProcesses.remove(mProcesses.keyAt(i));
|
mServiceProcessesByName.remove(mServiceProcessesByName.keyAt(i));
|
||||||
}
|
}
|
||||||
if (pi.mPid != 0) {
|
if (pi.mPid != 0) {
|
||||||
mActiveProcesses.remove(pi.mPid);
|
mServiceProcessesByPid.remove(pi.mPid);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -566,8 +608,8 @@ public class RunningState {
|
|||||||
if (changed) {
|
if (changed) {
|
||||||
// First determine an order for the services.
|
// First determine an order for the services.
|
||||||
ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
|
ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
|
||||||
for (int i=0; i<mProcesses.size(); i++) {
|
for (int i=0; i<mServiceProcessesByName.size(); i++) {
|
||||||
for (ProcessItem pi : mProcesses.valueAt(i).values()) {
|
for (ProcessItem pi : mServiceProcessesByName.valueAt(i).values()) {
|
||||||
pi.mIsSystem = false;
|
pi.mIsSystem = false;
|
||||||
pi.mIsStarted = true;
|
pi.mIsStarted = true;
|
||||||
pi.mActiveSince = Long.MAX_VALUE;
|
pi.mActiveSince = Long.MAX_VALUE;
|
||||||
@@ -643,6 +685,23 @@ public class RunningState {
|
|||||||
mergedItem.update(context);
|
mergedItem.update(context);
|
||||||
newMergedItems.add(mergedItem);
|
newMergedItems.add(mergedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finally, heavy-weight processes need to be shown and will
|
||||||
|
// go at the top.
|
||||||
|
NHP = mHeavyProcesses.size();
|
||||||
|
for (int i=0; i<NHP; i++) {
|
||||||
|
ProcessItem proc = mHeavyProcesses.get(i);
|
||||||
|
if (proc.mClient == null && proc.mServices.size() <= 0) {
|
||||||
|
if (proc.mMergedItem == null) {
|
||||||
|
proc.mMergedItem = new MergedItem();
|
||||||
|
proc.mMergedItem.mProcess = proc;
|
||||||
|
}
|
||||||
|
proc.mMergedItem.update(context);
|
||||||
|
newMergedItems.add(0, proc.mMergedItem);
|
||||||
|
mProcessItems.add(proc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mItems = newItems;
|
mItems = newItems;
|
||||||
mMergedItems = newMergedItems;
|
mMergedItems = newMergedItems;
|
||||||
|
@@ -288,9 +288,9 @@ public class BatteryHistoryChart extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void finishPaths(int w, int h, int levelh, int startX, int y, Path curLevelPath,
|
void finishPaths(int w, int h, int levelh, int startX, int y, Path curLevelPath,
|
||||||
int lastBatX, boolean lastCharging, boolean lastScreenOn, Path lastPath) {
|
int lastX, boolean lastCharging, boolean lastScreenOn, Path lastPath) {
|
||||||
if (curLevelPath != null) {
|
if (curLevelPath != null) {
|
||||||
if (lastBatX >= 0) {
|
if (lastX >= 0 && lastX < w) {
|
||||||
if (lastPath != null) {
|
if (lastPath != null) {
|
||||||
lastPath.lineTo(w, y);
|
lastPath.lineTo(w, y);
|
||||||
}
|
}
|
||||||
@@ -301,10 +301,10 @@ public class BatteryHistoryChart extends View {
|
|||||||
curLevelPath.close();
|
curLevelPath.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastCharging) {
|
if (lastCharging && lastX < w) {
|
||||||
mChargingPath.lineTo(w, h-mChargingOffset);
|
mChargingPath.lineTo(w, h-mChargingOffset);
|
||||||
}
|
}
|
||||||
if (lastScreenOn) {
|
if (lastScreenOn && lastX < w) {
|
||||||
mScreenOnPath.lineTo(w, h-mScreenOnOffset);
|
mScreenOnPath.lineTo(w, h-mScreenOnOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ public class BatteryHistoryChart extends View {
|
|||||||
final int levelh = h - mLevelOffset;
|
final int levelh = h - mLevelOffset;
|
||||||
|
|
||||||
BatteryStats.HistoryItem rec = mHistFirst;
|
BatteryStats.HistoryItem rec = mHistFirst;
|
||||||
int x = 0, y = 0, startX = 0, lastX = -1, lastY = -1, lastBatX = -1;
|
int x = 0, y = 0, startX = 0, lastX = -1, lastY = -1;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
Path curLevelPath = null;
|
Path curLevelPath = null;
|
||||||
Path lastLinePath = null;
|
Path lastLinePath = null;
|
||||||
@@ -342,11 +342,8 @@ public class BatteryHistoryChart extends View {
|
|||||||
|
|
||||||
if (lastX != x) {
|
if (lastX != x) {
|
||||||
// We have moved by at least a pixel.
|
// We have moved by at least a pixel.
|
||||||
if (lastY == y) {
|
if (lastY != y) {
|
||||||
// Battery level is still the same; don't plot,
|
// Don't plot changes within a pixel.
|
||||||
// but remember it.
|
|
||||||
lastBatX = x;
|
|
||||||
} else {
|
|
||||||
Path path;
|
Path path;
|
||||||
byte value = rec.batteryLevel;
|
byte value = rec.batteryLevel;
|
||||||
if (value <= BATTERY_CRITICAL) path = mBatCriticalPath;
|
if (value <= BATTERY_CRITICAL) path = mBatCriticalPath;
|
||||||
@@ -372,7 +369,6 @@ public class BatteryHistoryChart extends View {
|
|||||||
}
|
}
|
||||||
lastX = x;
|
lastX = x;
|
||||||
lastY = y;
|
lastY = y;
|
||||||
lastBatX = -1;
|
|
||||||
|
|
||||||
final boolean charging =
|
final boolean charging =
|
||||||
(rec.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0;
|
(rec.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0;
|
||||||
@@ -399,9 +395,9 @@ public class BatteryHistoryChart extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (curLevelPath != null) {
|
} else if (curLevelPath != null) {
|
||||||
finishPaths(x+1, h, levelh, startX, lastY, curLevelPath, lastBatX,
|
finishPaths(x+1, h, levelh, startX, lastY, curLevelPath, lastX,
|
||||||
lastCharging, lastScreenOn, lastLinePath);
|
lastCharging, lastScreenOn, lastLinePath);
|
||||||
lastX = lastY = lastBatX = -1;
|
lastX = lastY = -1;
|
||||||
curLevelPath = null;
|
curLevelPath = null;
|
||||||
lastLinePath = null;
|
lastLinePath = null;
|
||||||
lastCharging = lastScreenOn = false;
|
lastCharging = lastScreenOn = false;
|
||||||
@@ -411,7 +407,7 @@ public class BatteryHistoryChart extends View {
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
finishPaths(w, h, levelh, startX, lastY, curLevelPath, lastBatX,
|
finishPaths(w, h, levelh, startX, lastY, curLevelPath, lastX,
|
||||||
lastCharging, lastScreenOn, lastLinePath);
|
lastCharging, lastScreenOn, lastLinePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user