summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/RunningServices.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/settings/RunningServices.java')
-rw-r--r--src/com/android/settings/RunningServices.java1172
1 files changed, 0 insertions, 1172 deletions
diff --git a/src/com/android/settings/RunningServices.java b/src/com/android/settings/RunningServices.java
deleted file mode 100644
index e67adf0..0000000
--- a/src/com/android/settings/RunningServices.java
+++ /dev/null
@@ -1,1172 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import com.android.settings.R;
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ListActivity;
-import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageItemInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import java.io.FileInputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-public class RunningServices extends ListActivity
- implements AbsListView.RecyclerListener,
- DialogInterface.OnClickListener {
- static final String TAG = "RunningServices";
-
- /** Maximum number of services to retrieve */
- static final int MAX_SERVICES = 100;
-
- static final int MSG_UPDATE_TIMES = 1;
- static final int MSG_UPDATE_CONTENTS = 2;
- static final int MSG_REFRESH_UI = 3;
-
- static final long TIME_UPDATE_DELAY = 1000;
- static final long CONTENTS_UPDATE_DELAY = 2000;
-
- // Memory pages are 4K.
- static final long PAGE_SIZE = 4*1024;
-
- long SECONDARY_SERVER_MEM;
-
- final HashMap<View, ActiveItem> mActiveItems = new HashMap<View, ActiveItem>();
-
- ActivityManager mAm;
-
- State mState;
-
- StringBuilder mBuilder = new StringBuilder(128);
-
- BaseItem mCurSelected;
-
- int mProcessBgColor;
-
- LinearColorBar mColorBar;
- TextView mBackgroundProcessText;
- TextView mForegroundProcessText;
-
- int mLastNumBackgroundProcesses = -1;
- int mLastNumForegroundProcesses = -1;
- int mLastNumServiceProcesses = -1;
- long mLastBackgroundProcessMemory = -1;
- long mLastForegroundProcessMemory = -1;
- long mLastServiceProcessMemory = -1;
- long mLastAvailMemory = -1;
-
- Dialog mCurDialog;
-
- byte[] mBuffer = new byte[1024];
-
- class ActiveItem {
- View mRootView;
- BaseItem mItem;
- ActivityManager.RunningServiceInfo mService;
- ViewHolder mHolder;
- long mFirstRunTime;
-
- void updateTime(Context context) {
- if (mItem.mIsProcess) {
- String size = mItem.mSizeStr != null ? mItem.mSizeStr : "";
- if (!size.equals(mItem.mCurSizeStr)) {
- mItem.mCurSizeStr = size;
- mHolder.size.setText(size);
- }
- } else {
- if (mItem.mActiveSince >= 0) {
- mHolder.size.setText(DateUtils.formatElapsedTime(mBuilder,
- (SystemClock.uptimeMillis()-mFirstRunTime)/1000));
- } else {
- mHolder.size.setText(context.getResources().getText(
- R.string.service_restarting));
- }
- }
- }
- }
-
- static class BaseItem {
- final boolean mIsProcess;
-
- PackageItemInfo mPackageInfo;
- CharSequence mDisplayLabel;
- String mLabel;
- String mDescription;
-
- int mCurSeq;
-
- long mActiveSince;
- long mSize;
- String mSizeStr;
- String mCurSizeStr;
- boolean mNeedDivider;
-
- public BaseItem(boolean isProcess) {
- mIsProcess = isProcess;
- }
- }
-
- static class ServiceItem extends BaseItem {
- ActivityManager.RunningServiceInfo mRunningService;
- ServiceInfo mServiceInfo;
- boolean mShownAsStarted;
-
- public ServiceItem() {
- super(false);
- }
- }
-
- static class ProcessItem extends BaseItem {
- final HashMap<ComponentName, ServiceItem> mServices
- = new HashMap<ComponentName, ServiceItem>();
- final SparseArray<ProcessItem> mDependentProcesses
- = new SparseArray<ProcessItem>();
-
- final int mUid;
- final String mProcessName;
- int mPid;
-
- ProcessItem mClient;
- int mLastNumDependentProcesses;
-
- int mRunningSeq;
- ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
-
- // Purely for sorting.
- boolean mIsSystem;
- boolean mIsStarted;
- long mActiveSince;
-
- public ProcessItem(Context context, int uid, String processName) {
- super(true);
- mDescription = context.getResources().getString(
- R.string.service_process_name, processName);
- mUid = uid;
- mProcessName = processName;
- }
-
- void ensureLabel(PackageManager pm) {
- if (mLabel != null) {
- return;
- }
-
- try {
- ApplicationInfo ai = pm.getApplicationInfo(mProcessName, 0);
- if (ai.uid == mUid) {
- mDisplayLabel = ai.loadLabel(pm);
- mLabel = mDisplayLabel.toString();
- mPackageInfo = ai;
- return;
- }
- } catch (PackageManager.NameNotFoundException e) {
- }
-
- // If we couldn't get information about the overall
- // process, try to find something about the uid.
- String[] pkgs = pm.getPackagesForUid(mUid);
-
- // If there is one package with this uid, that is what we want.
- if (pkgs.length == 1) {
- try {
- ApplicationInfo ai = pm.getApplicationInfo(pkgs[0], 0);
- mDisplayLabel = ai.loadLabel(pm);
- mLabel = mDisplayLabel.toString();
- mPackageInfo = ai;
- return;
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
-
- // If there are multiple, see if one gives us the official name
- // for this uid.
- for (String name : pkgs) {
- try {
- PackageInfo pi = pm.getPackageInfo(name, 0);
- if (pi.sharedUserLabel != 0) {
- CharSequence nm = pm.getText(name,
- pi.sharedUserLabel, pi.applicationInfo);
- if (nm != null) {
- mDisplayLabel = nm;
- mLabel = nm.toString();
- mPackageInfo = pi.applicationInfo;
- return;
- }
- }
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
-
- // If still don't have anything to display, just use the
- // service info.
- if (mServices.size() > 0) {
- mPackageInfo = mServices.values().iterator().next()
- .mServiceInfo.applicationInfo;
- mDisplayLabel = mPackageInfo.loadLabel(pm);
- mLabel = mDisplayLabel.toString();
- return;
- }
-
- // Finally... whatever, just pick the first package's name.
- try {
- ApplicationInfo ai = pm.getApplicationInfo(pkgs[0], 0);
- mDisplayLabel = ai.loadLabel(pm);
- mLabel = mDisplayLabel.toString();
- mPackageInfo = ai;
- return;
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
-
- boolean updateService(Context context,
- ActivityManager.RunningServiceInfo service) {
- final PackageManager pm = context.getPackageManager();
-
- boolean changed = false;
- ServiceItem si = mServices.get(service.service);
- if (si == null) {
- changed = true;
- si = new ServiceItem();
- si.mRunningService = service;
- try {
- si.mServiceInfo = pm.getServiceInfo(service.service, 0);
- } catch (PackageManager.NameNotFoundException e) {
- }
- if (si.mServiceInfo != null && (si.mServiceInfo.labelRes != 0
- || si.mServiceInfo.nonLocalizedLabel != null)) {
- si.mDisplayLabel = si.mServiceInfo.loadLabel(pm);
- si.mLabel = si.mDisplayLabel.toString();
- } else {
- si.mLabel = si.mRunningService.service.getClassName();
- int tail = si.mLabel.lastIndexOf('.');
- if (tail >= 0) {
- si.mLabel = si.mLabel.substring(tail+1, si.mLabel.length());
- }
- si.mDisplayLabel = si.mLabel;
- }
- si.mPackageInfo = si.mServiceInfo.applicationInfo;
- mServices.put(service.service, si);
- }
- si.mCurSeq = mCurSeq;
- si.mRunningService = service;
- long activeSince = service.restarting == 0 ? service.activeSince : -1;
- if (si.mActiveSince != activeSince) {
- si.mActiveSince = activeSince;
- changed = true;
- }
- if (service.clientPackage != null && service.clientLabel != 0) {
- if (si.mShownAsStarted) {
- si.mShownAsStarted = false;
- changed = true;
- }
- try {
- Resources clientr = pm.getResourcesForApplication(service.clientPackage);
- String label = clientr.getString(service.clientLabel);
- si.mDescription = context.getResources().getString(
- R.string.service_client_name, label);
- } catch (PackageManager.NameNotFoundException e) {
- si.mDescription = null;
- }
- } else {
- if (!si.mShownAsStarted) {
- si.mShownAsStarted = true;
- changed = true;
- }
- si.mDescription = context.getResources().getString(
- R.string.service_started_by_app);
- }
-
- return changed;
- }
-
- boolean updateSize(Context context, Debug.MemoryInfo mem, int curSeq) {
- mSize = ((long)mem.getTotalPss()) * 1024;
- if (mCurSeq == curSeq) {
- String sizeStr = Formatter.formatShortFileSize(
- context, mSize);
- if (!sizeStr.equals(mSizeStr)){
- mSizeStr = sizeStr;
- // We update this on the second tick where we update just
- // the text in the current items, so no need to say we
- // changed here.
- return false;
- }
- }
- return false;
- }
-
- boolean buildDependencyChain(Context context, PackageManager pm, int curSeq) {
- final int NP = mDependentProcesses.size();
- boolean changed = false;
- for (int i=0; i<NP; i++) {
- ProcessItem proc = mDependentProcesses.valueAt(i);
- if (proc.mClient != this) {
- changed = true;
- proc.mClient = this;
- }
- proc.mCurSeq = curSeq;
- proc.ensureLabel(pm);
- changed |= proc.buildDependencyChain(context, pm, curSeq);
- }
-
- if (mLastNumDependentProcesses != mDependentProcesses.size()) {
- changed = true;
- mLastNumDependentProcesses = mDependentProcesses.size();
- }
-
- return changed;
- }
-
- void addDependentProcesses(ArrayList<BaseItem> dest,
- ArrayList<ProcessItem> destProc) {
- final int NP = mDependentProcesses.size();
- for (int i=0; i<NP; i++) {
- ProcessItem proc = mDependentProcesses.valueAt(i);
- proc.addDependentProcesses(dest, destProc);
- dest.add(proc);
- if (proc.mPid > 0) {
- destProc.add(proc);
- }
- }
- }
- }
-
- static class ServiceProcessComparator implements Comparator<ProcessItem> {
- public int compare(ProcessItem object1, ProcessItem object2) {
- if (object1.mIsStarted != object2.mIsStarted) {
- // Non-started processes go last.
- return object1.mIsStarted ? -1 : 1;
- }
- if (object1.mIsSystem != object2.mIsSystem) {
- // System processes go below non-system.
- return object1.mIsSystem ? 1 : -1;
- }
- if (object1.mActiveSince != object2.mActiveSince) {
- // Remaining ones are sorted with the longest running
- // services last.
- return (object1.mActiveSince > object2.mActiveSince) ? -1 : 1;
- }
- return 0;
- }
- }
-
- static class State {
- final SparseArray<HashMap<String, ProcessItem>> mProcesses
- = new SparseArray<HashMap<String, ProcessItem>>();
- final SparseArray<ProcessItem> mActiveProcesses
- = new SparseArray<ProcessItem>();
- final ServiceProcessComparator mServiceProcessComparator
- = new ServiceProcessComparator();
-
- // Temporary for finding process dependencies.
- final SparseArray<ProcessItem> mRunningProcesses
- = new SparseArray<ProcessItem>();
-
- final ArrayList<ProcessItem> mProcessItems = new ArrayList<ProcessItem>();
- final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>();
-
- int mSequence = 0;
-
- // ----- following protected by mLock -----
-
- // Lock for protecting the state that will be shared between the
- // background update thread and the UI thread.
- final Object mLock = new Object();
-
- ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
-
- int mNumBackgroundProcesses;
- long mBackgroundProcessMemory;
- int mNumForegroundProcesses;
- long mForegroundProcessMemory;
- int mNumServiceProcesses;
- long mServiceProcessMemory;
-
- boolean update(Context context, ActivityManager am) {
- final PackageManager pm = context.getPackageManager();
-
- mSequence++;
-
- boolean changed = false;
-
- List<ActivityManager.RunningServiceInfo> services
- = am.getRunningServices(MAX_SERVICES);
- final int NS = services != null ? services.size() : 0;
- for (int i=0; i<NS; i++) {
- ActivityManager.RunningServiceInfo si = services.get(i);
- // We are not interested in services that have not been started
- // and don't have a known client, because
- // there is nothing the user can do about them.
- if (!si.started && si.clientLabel == 0) {
- continue;
- }
- // We likewise don't care about services running in a
- // persistent process like the system or phone.
- if ((si.flags&ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS)
- != 0) {
- continue;
- }
-
- HashMap<String, ProcessItem> procs = mProcesses.get(si.uid);
- if (procs == null) {
- procs = new HashMap<String, ProcessItem>();
- mProcesses.put(si.uid, procs);
- }
- ProcessItem proc = procs.get(si.process);
- if (proc == null) {
- changed = true;
- proc = new ProcessItem(context, si.uid, si.process);
- procs.put(si.process, proc);
- }
-
- if (proc.mCurSeq != mSequence) {
- int pid = si.restarting == 0 ? si.pid : 0;
- if (pid != proc.mPid) {
- changed = true;
- if (proc.mPid != pid) {
- if (proc.mPid != 0) {
- mActiveProcesses.remove(proc.mPid);
- }
- if (pid != 0) {
- mActiveProcesses.put(pid, proc);
- }
- proc.mPid = pid;
- }
- }
- proc.mDependentProcesses.clear();
- proc.mCurSeq = mSequence;
- }
- changed |= proc.updateService(context, si);
- }
-
- // Now update the map of other processes that are running (but
- // don't have services actively running inside them).
- List<ActivityManager.RunningAppProcessInfo> processes
- = am.getRunningAppProcesses();
- final int NP = processes != null ? processes.size() : 0;
- for (int i=0; i<NP; i++) {
- ActivityManager.RunningAppProcessInfo pi = processes.get(i);
- ProcessItem proc = mActiveProcesses.get(pi.pid);
- if (proc == null) {
- // This process is not one that is a direct container
- // of a service, so look for it in the secondary
- // running list.
- proc = mRunningProcesses.get(pi.pid);
- if (proc == null) {
- proc = new ProcessItem(context, pi.uid, pi.processName);
- proc.mPid = pi.pid;
- mRunningProcesses.put(pi.pid, proc);
- }
- proc.mDependentProcesses.clear();
- }
- proc.mRunningSeq = mSequence;
- proc.mRunningProcessInfo = pi;
- }
-
- // Build the chains from client processes to the process they are
- // dependent on; also remove any old running processes.
- int NRP = mRunningProcesses.size();
- for (int i=0; i<NRP; i++) {
- ProcessItem proc = mRunningProcesses.valueAt(i);
- if (proc.mRunningSeq == mSequence) {
- int clientPid = proc.mRunningProcessInfo.importanceReasonPid;
- if (clientPid != 0) {
- ProcessItem client = mActiveProcesses.get(clientPid);
- if (client == null) {
- client = mRunningProcesses.get(clientPid);
- }
- if (client != null) {
- client.mDependentProcesses.put(proc.mPid, proc);
- }
- } else {
- // In this pass the process doesn't have a client.
- // Clear to make sure if it later gets the same one
- // that we will detect the change.
- proc.mClient = null;
- }
- } else {
- mRunningProcesses.remove(mRunningProcesses.keyAt(i));
- }
- }
-
- // Follow the tree from all primary service processes to all
- // processes they are dependent on, marking these processes as
- // still being active and determining if anything has changed.
- final int NAP = mActiveProcesses.size();
- for (int i=0; i<NAP; i++) {
- ProcessItem proc = mActiveProcesses.valueAt(i);
- if (proc.mCurSeq == mSequence) {
- changed |= proc.buildDependencyChain(context, pm, mSequence);
- }
- }
-
- // Look for services and their primary processes that no longer exist...
- for (int i=0; i<mProcesses.size(); i++) {
- HashMap<String, ProcessItem> procs = mProcesses.valueAt(i);
- Iterator<ProcessItem> pit = procs.values().iterator();
- while (pit.hasNext()) {
- ProcessItem pi = pit.next();
- if (pi.mCurSeq == mSequence) {
- pi.ensureLabel(pm);
- if (pi.mPid == 0) {
- // Sanity: a non-process can't be dependent on
- // anything.
- pi.mDependentProcesses.clear();
- }
- } else {
- changed = true;
- pit.remove();
- if (procs.size() == 0) {
- mProcesses.remove(mProcesses.keyAt(i));
- }
- if (pi.mPid != 0) {
- mActiveProcesses.remove(pi.mPid);
- }
- continue;
- }
- Iterator<ServiceItem> sit = pi.mServices.values().iterator();
- while (sit.hasNext()) {
- ServiceItem si = sit.next();
- if (si.mCurSeq != mSequence) {
- changed = true;
- sit.remove();
- }
- }
- }
- }
-
- if (changed) {
- // First determine an order for the services.
- ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
- for (int i=0; i<mProcesses.size(); i++) {
- for (ProcessItem pi : mProcesses.valueAt(i).values()) {
- pi.mIsSystem = false;
- pi.mIsStarted = true;
- pi.mActiveSince = Long.MAX_VALUE;
- for (ServiceItem si : pi.mServices.values()) {
- if (si.mServiceInfo != null
- && (si.mServiceInfo.applicationInfo.flags
- & ApplicationInfo.FLAG_SYSTEM) != 0) {
- pi.mIsSystem = true;
- }
- if (si.mRunningService != null
- && si.mRunningService.clientLabel != 0) {
- pi.mIsStarted = false;
- if (pi.mActiveSince > si.mRunningService.activeSince) {
- pi.mActiveSince = si.mRunningService.activeSince;
- }
- }
- }
- sortedProcesses.add(pi);
- }
- }
-
- Collections.sort(sortedProcesses, mServiceProcessComparator);
-
- ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
- mProcessItems.clear();
- for (int i=0; i<sortedProcesses.size(); i++) {
- ProcessItem pi = sortedProcesses.get(i);
- pi.mNeedDivider = false;
- // First add processes we are dependent on.
- pi.addDependentProcesses(newItems, mProcessItems);
- // And add the process itself.
- newItems.add(pi);
- if (pi.mPid > 0) {
- mProcessItems.add(pi);
- }
- // And finally the services running in it.
- boolean needDivider = false;
- for (ServiceItem si : pi.mServices.values()) {
- si.mNeedDivider = needDivider;
- needDivider = true;
- newItems.add(si);
- }
- }
- synchronized (mLock) {
- mItems = newItems;
- }
- }
-
- // Count number of interesting other (non-active) processes, and
- // build a list of all processes we will retrieve memory for.
- mAllProcessItems.clear();
- mAllProcessItems.addAll(mProcessItems);
- int numBackgroundProcesses = 0;
- int numForegroundProcesses = 0;
- int numServiceProcesses = 0;
- NRP = mRunningProcesses.size();
- for (int i=0; i<NRP; i++) {
- ProcessItem proc = mRunningProcesses.valueAt(i);
- if (proc.mCurSeq != mSequence) {
- // We didn't hit this process as a dependency on one
- // of our active ones, so add it up if needed.
- if (proc.mRunningProcessInfo.importance >=
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
- numBackgroundProcesses++;
- mAllProcessItems.add(proc);
- } else if (proc.mRunningProcessInfo.importance <=
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
- numForegroundProcesses++;
- mAllProcessItems.add(proc);
- } else {
- Log.i(TAG, "Unknown non-service process: "
- + proc.mProcessName + " #" + proc.mPid);
- }
- } else {
- numServiceProcesses++;
- }
- }
-
- long backgroundProcessMemory = 0;
- long foregroundProcessMemory = 0;
- long serviceProcessMemory = 0;
- try {
- final int numProc = mAllProcessItems.size();
- int[] pids = new int[numProc];
- for (int i=0; i<numProc; i++) {
- pids[i] = mAllProcessItems.get(i).mPid;
- }
- Debug.MemoryInfo[] mem = ActivityManagerNative.getDefault()
- .getProcessMemoryInfo(pids);
- for (int i=pids.length-1; i>=0; i--) {
- ProcessItem proc = mAllProcessItems.get(i);
- changed |= proc.updateSize(context, mem[i], mSequence);
- if (proc.mCurSeq == mSequence) {
- serviceProcessMemory += proc.mSize;
- } else if (proc.mRunningProcessInfo.importance >=
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
- backgroundProcessMemory += proc.mSize;
- } else if (proc.mRunningProcessInfo.importance <=
- ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
- foregroundProcessMemory += proc.mSize;
- }
- }
- } catch (RemoteException e) {
- }
-
- synchronized (mLock) {
- mNumBackgroundProcesses = numBackgroundProcesses;
- mNumForegroundProcesses = numForegroundProcesses;
- mNumServiceProcesses = numServiceProcesses;
- mBackgroundProcessMemory = backgroundProcessMemory;
- mForegroundProcessMemory = foregroundProcessMemory;
- mServiceProcessMemory = serviceProcessMemory;
- }
-
- return changed;
- }
-
- ArrayList<BaseItem> getCurrentItems() {
- synchronized (mLock) {
- return mItems;
- }
- }
- }
-
- static class TimeTicker extends TextView {
- public TimeTicker(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- }
-
- static class ViewHolder {
- ImageView separator;
- ImageView icon;
- TextView name;
- TextView description;
- TextView size;
- }
-
- class ServiceListAdapter extends BaseAdapter {
- final State mState;
- final LayoutInflater mInflater;
- ArrayList<BaseItem> mItems;
-
- ServiceListAdapter(State state) {
- mState = state;
- mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- refreshItems();
- }
-
- void refreshItems() {
- ArrayList<BaseItem> newItems = mState.getCurrentItems();
- if (mItems != newItems) {
- mItems = newItems;
- }
- if (mItems == null) {
- mItems = new ArrayList<BaseItem>();
- }
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- public int getCount() {
- return mItems.size();
- }
-
- public Object getItem(int position) {
- return mItems.get(position);
- }
-
- public long getItemId(int position) {
- return mItems.get(position).hashCode();
- }
-
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- public boolean isEnabled(int position) {
- return !mItems.get(position).mIsProcess;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View v;
- if (convertView == null) {
- v = newView(parent);
- } else {
- v = convertView;
- }
- bindView(v, position);
- return v;
- }
-
- public View newView(ViewGroup parent) {
- View v = mInflater.inflate(R.layout.running_services_item, parent, false);
- ViewHolder h = new ViewHolder();
- h.separator = (ImageView)v.findViewById(R.id.separator);
- h.icon = (ImageView)v.findViewById(R.id.icon);
- h.name = (TextView)v.findViewById(R.id.name);
- h.description = (TextView)v.findViewById(R.id.description);
- h.size = (TextView)v.findViewById(R.id.size);
- v.setTag(h);
- return v;
- }
-
- public void bindView(View view, int position) {
- synchronized (mState.mLock) {
- ViewHolder vh = (ViewHolder) view.getTag();
- if (position >= mItems.size()) {
- // List must have changed since we last reported its
- // size... ignore here, we will be doing a data changed
- // to refresh the entire list.
- return;
- }
- BaseItem item = mItems.get(position);
- vh.name.setText(item.mDisplayLabel);
- vh.separator.setVisibility(item.mNeedDivider
- ? View.VISIBLE : View.INVISIBLE);
- ActiveItem ai = new ActiveItem();
- ai.mRootView = view;
- ai.mItem = item;
- ai.mHolder = vh;
- ai.mFirstRunTime = item.mActiveSince;
- vh.description.setText(item.mDescription);
- if (item.mIsProcess) {
- view.setBackgroundColor(mProcessBgColor);
- vh.icon.setImageDrawable(null);
- vh.icon.setVisibility(View.GONE);
- vh.description.setText(item.mDescription);
- item.mCurSizeStr = null;
- } else {
- view.setBackgroundDrawable(null);
- vh.icon.setImageDrawable(item.mPackageInfo.loadIcon(getPackageManager()));
- vh.icon.setVisibility(View.VISIBLE);
- vh.description.setText(item.mDescription);
- ai.mFirstRunTime = item.mActiveSince;
- }
- ai.updateTime(RunningServices.this);
- mActiveItems.put(view, ai);
- }
- }
- }
-
- public static class LinearColorBar extends LinearLayout {
- private float mRedRatio;
- private float mYellowRatio;
- private float mGreenRatio;
-
- final Rect mRect = new Rect();
- final Paint mPaint = new Paint();
-
- public LinearColorBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- setWillNotDraw(false);
- mPaint.setStyle(Paint.Style.FILL);
- }
-
- public void setRatios(float red, float yellow, float green) {
- mRedRatio = red;
- mYellowRatio = yellow;
- mGreenRatio = green;
- invalidate();
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- int width = getWidth();
- mRect.top = 0;
- mRect.bottom = getHeight();
-
- int left = 0;
-
- int right = left + (int)(width*mRedRatio);
- if (left < right) {
- mRect.left = left;
- mRect.right = right;
- mPaint.setColor(0xffff8080);
- canvas.drawRect(mRect, mPaint);
- width -= (right-left);
- left = right;
- }
-
- right = left + (int)(width*mYellowRatio);
- if (left < right) {
- mRect.left = left;
- mRect.right = right;
- mPaint.setColor(0xffffff00);
- canvas.drawRect(mRect, mPaint);
- width -= (right-left);
- left = right;
- }
-
- right = left + width;
- if (left < right) {
- mRect.left = left;
- mRect.right = right;
- mPaint.setColor(0xff80ff80);
- canvas.drawRect(mRect, mPaint);
- }
- }
- }
-
- HandlerThread mBackgroundThread;
- final class BackgroundHandler extends Handler {
- public BackgroundHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UPDATE_CONTENTS:
- Message cmd = mHandler.obtainMessage(MSG_REFRESH_UI);
- cmd.arg1 = mState.update(RunningServices.this, mAm) ? 1 : 0;
- mHandler.sendMessage(cmd);
- removeMessages(MSG_UPDATE_CONTENTS);
- msg = obtainMessage(MSG_UPDATE_CONTENTS);
- sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
- break;
- }
- }
- };
- BackgroundHandler mBackgroundHandler;
-
- final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UPDATE_TIMES:
- Iterator<ActiveItem> it = mActiveItems.values().iterator();
- while (it.hasNext()) {
- ActiveItem ai = it.next();
- if (ai.mRootView.getWindowToken() == null) {
- // Clean out any dead views, just in case.
- it.remove();
- continue;
- }
- ai.updateTime(RunningServices.this);
- }
- removeMessages(MSG_UPDATE_TIMES);
- msg = obtainMessage(MSG_UPDATE_TIMES);
- sendMessageDelayed(msg, TIME_UPDATE_DELAY);
- break;
- case MSG_REFRESH_UI:
- refreshUi(msg.arg1 != 0);
- break;
- }
- }
- };
-
- private boolean matchText(byte[] buffer, int index, String text) {
- int N = text.length();
- if ((index+N) >= buffer.length) {
- return false;
- }
- for (int i=0; i<N; i++) {
- if (buffer[index+i] != text.charAt(i)) {
- return false;
- }
- }
- return true;
- }
-
- private long extractMemValue(byte[] buffer, int index) {
- while (index < buffer.length && buffer[index] != '\n') {
- if (buffer[index] >= '0' && buffer[index] <= '9') {
- int start = index;
- index++;
- while (index < buffer.length && buffer[index] >= '0'
- && buffer[index] <= '9') {
- index++;
- }
- String str = new String(buffer, 0, start, index-start);
- return ((long)Integer.parseInt(str)) * 1024;
- }
- index++;
- }
- return 0;
- }
-
- private long readAvailMem() {
- try {
- long memFree = 0;
- long memCached = 0;
- FileInputStream is = new FileInputStream("/proc/meminfo");
- int len = is.read(mBuffer);
- is.close();
- final int BUFLEN = mBuffer.length;
- for (int i=0; i<len && (memFree == 0 || memCached == 0); i++) {
- if (matchText(mBuffer, i, "MemFree")) {
- i += 7;
- memFree = extractMemValue(mBuffer, i);
- } else if (matchText(mBuffer, i, "Cached")) {
- i += 6;
- memCached = extractMemValue(mBuffer, i);
- }
- while (i < BUFLEN && mBuffer[i] != '\n') {
- i++;
- }
- }
- return memFree + memCached;
- } catch (java.io.FileNotFoundException e) {
- } catch (java.io.IOException e) {
- }
- return 0;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mAm = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
- mState = (State)getLastNonConfigurationInstance();
- if (mState == null) {
- mState = new State();
- }
- mProcessBgColor = 0xff505050;
- setContentView(R.layout.running_services);
- getListView().setDivider(null);
- getListView().setAdapter(new ServiceListAdapter(mState));
- mColorBar = (LinearColorBar)findViewById(R.id.color_bar);
- mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
- mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
-
- // Magic! Implementation detail! Don't count on this!
- SECONDARY_SERVER_MEM =
- Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
- }
-
- void refreshUi(boolean dataChanged) {
- if (dataChanged) {
- ServiceListAdapter adapter = (ServiceListAdapter)(getListView().getAdapter());
- adapter.refreshItems();
- adapter.notifyDataSetChanged();
- }
-
- // This is the amount of available memory until we start killing
- // background services.
- long availMem = readAvailMem() - SECONDARY_SERVER_MEM;
- if (availMem < 0) {
- availMem = 0;
- }
-
- synchronized (mState.mLock) {
- if (mLastNumBackgroundProcesses != mState.mNumBackgroundProcesses
- || mLastBackgroundProcessMemory != mState.mBackgroundProcessMemory
- || mLastAvailMemory != availMem) {
- mLastNumBackgroundProcesses = mState.mNumBackgroundProcesses;
- mLastBackgroundProcessMemory = mState.mBackgroundProcessMemory;
- mLastAvailMemory = availMem;
- String availStr = availMem != 0
- ? Formatter.formatShortFileSize(this, availMem) : "0";
- String sizeStr = Formatter.formatShortFileSize(this, mLastBackgroundProcessMemory);
- mBackgroundProcessText.setText(getResources().getString(
- R.string.service_background_processes,
- mLastNumBackgroundProcesses, availStr, sizeStr));
- }
- if (mLastNumForegroundProcesses != mState.mNumForegroundProcesses
- || mLastForegroundProcessMemory != mState.mForegroundProcessMemory) {
- mLastNumForegroundProcesses = mState.mNumForegroundProcesses;
- mLastForegroundProcessMemory = mState.mForegroundProcessMemory;
- String sizeStr = Formatter.formatShortFileSize(this, mLastForegroundProcessMemory);
- mForegroundProcessText.setText(getResources().getString(
- R.string.service_foreground_processes, mLastNumForegroundProcesses, sizeStr));
- }
- mLastNumServiceProcesses = mState.mNumServiceProcesses;
- mLastServiceProcessMemory = mState.mServiceProcessMemory;
-
- float totalMem = availMem + mLastBackgroundProcessMemory
- + mLastForegroundProcessMemory + mLastServiceProcessMemory;
- mColorBar.setRatios(mLastForegroundProcessMemory/totalMem,
- mLastServiceProcessMemory/totalMem,
- (availMem+mLastBackgroundProcessMemory)/totalMem);
- }
- }
-
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- BaseItem bi = (BaseItem)l.getAdapter().getItem(position);
- if (!bi.mIsProcess) {
- ServiceItem si = (ServiceItem)bi;
- if (si.mRunningService.clientLabel != 0) {
- mCurSelected = null;
- PendingIntent pi = mAm.getRunningServiceControlPanel(
- si.mRunningService.service);
- if (pi != null) {
- try {
- this.startIntentSender(pi.getIntentSender(), null,
- Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,
- Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, 0);
- } catch (IntentSender.SendIntentException e) {
- Log.w(TAG, e);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, e);
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, e);
- }
- }
- } else {
- mCurSelected = bi;
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.confirm_stop_service);
- String msg = getResources().getString(
- R.string.confirm_stop_service_msg,
- si.mPackageInfo.loadLabel(getPackageManager()));
- builder.setMessage(msg);
- builder.setPositiveButton(R.string.confirm_stop_stop, this);
- builder.setNegativeButton(R.string.confirm_stop_cancel, null);
- builder.setCancelable(true);
- mCurDialog = builder.show();
- }
- } else {
- mCurSelected = null;
- }
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if (mCurSelected != null) {
- stopService(new Intent().setComponent(
- ((ServiceItem)mCurSelected).mRunningService.service));
- if (mBackgroundHandler != null) {
- mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS);
- }
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mHandler.removeMessages(MSG_UPDATE_TIMES);
- if (mBackgroundThread != null) {
- mBackgroundThread.quit();
- mBackgroundThread = null;
- mBackgroundHandler = null;
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- refreshUi(mState.update(this, mAm));
- mBackgroundThread = new HandlerThread("RunningServices");
- mBackgroundThread.start();
- mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper());
- mHandler.removeMessages(MSG_UPDATE_TIMES);
- Message msg = mHandler.obtainMessage(MSG_UPDATE_TIMES);
- mHandler.sendMessageDelayed(msg, TIME_UPDATE_DELAY);
- mBackgroundHandler.removeMessages(MSG_UPDATE_CONTENTS);
- msg = mBackgroundHandler.obtainMessage(MSG_UPDATE_CONTENTS);
- mBackgroundHandler.sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
- }
-
- @Override
- public Object onRetainNonConfigurationInstance() {
- return mState;
- }
-
- public void onMovedToScrapHeap(View view) {
- mActiveItems.remove(view);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (mCurDialog != null) {
- mCurDialog.dismiss();
- }
- }
-}