diff options
Diffstat (limited to 'src/com/android/settings/RunningServices.java')
-rw-r--r-- | src/com/android/settings/RunningServices.java | 1172 |
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(); - } - } -} |