Merge change 24553 into eclair
* changes: Make running services show dependent processes.
This commit is contained in:
@@ -15,7 +15,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="0px"
|
||||||
|
android:layout_weight="1">
|
||||||
<ListView android:id="@android:id/list"
|
<ListView android:id="@android:id/list"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
@@ -27,4 +34,27 @@
|
|||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/no_running_services"
|
android:text="@string/no_running_services"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
</merge>
|
</FrameLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:background="?android:attr/colorForeground"
|
||||||
|
android:padding="4dp">
|
||||||
|
<TextView android:id="@+id/backgroundText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmallInverse"
|
||||||
|
android:color="?android:attr/textColorPrimaryInverse"
|
||||||
|
android:singleLine="true" />
|
||||||
|
<TextView android:id="@+id/foregroundText"
|
||||||
|
android:layout_gravity="center_vertical|right"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmallInverse"
|
||||||
|
android:color="?android:attr/textColorPrimaryInverse"
|
||||||
|
android:singleLine="true" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
@@ -50,10 +50,10 @@
|
|||||||
|
|
||||||
<!-- Display settings. The type of animations to show. -->
|
<!-- Display settings. The type of animations to show. -->
|
||||||
<string-array name="animations_entries">
|
<string-array name="animations_entries">
|
||||||
<item>Off</item>
|
<item>No animations</item>
|
||||||
<item>Some</item>
|
<item>Some animations</item>
|
||||||
<item>All</item>
|
<item>All animations</item>
|
||||||
<item>Slow</item>
|
<item>Slower all animations</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<!-- Display settings. Summary for each type of animation. -->
|
<!-- Display settings. Summary for each type of animation. -->
|
||||||
|
@@ -1422,9 +1422,13 @@ found in the list of installed applications.</string>
|
|||||||
<!-- Running services, button to cancel stopping of a service -->
|
<!-- Running services, button to cancel stopping of a service -->
|
||||||
<string name="confirm_stop_cancel">Cancel</string>
|
<string name="confirm_stop_cancel">Cancel</string>
|
||||||
<!-- Running services, description for a service in the started state -->
|
<!-- Running services, description for a service in the started state -->
|
||||||
<string name="service_started_by_app">Started by application</string>
|
<string name="service_started_by_app">Started by application: select to stop</string>
|
||||||
<!-- Running services, description for a service in the started state -->
|
<!-- Running services, description for a service in the started state -->
|
||||||
<string name="service_client_name"><xliff:g id="client_name">%1$s</xliff:g>: select to manage</string>
|
<string name="service_client_name"><xliff:g id="client_name">%1$s</xliff:g>: select to manage</string>
|
||||||
|
<!-- Running services, summary of background processes -->
|
||||||
|
<string name="service_background_processes">Background procs: <xliff:g id="client_name">%1$d</xliff:g></string>
|
||||||
|
<!-- Running services, summary of foreground processes -->
|
||||||
|
<string name="service_foreground_processes">Foreground procs: <xliff:g id="client_name">%1$d</xliff:g></string>
|
||||||
|
|
||||||
<!-- Language Settings --> <skip />
|
<!-- Language Settings --> <skip />
|
||||||
<!-- Title of setting on main settings screen. This item will take the user to the screen to tweak settings realted to locale and text -->
|
<!-- Title of setting on main settings screen. This item will take the user to the screen to tweak settings realted to locale and text -->
|
||||||
|
@@ -23,28 +23,17 @@ import android.app.AlertDialog;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ListActivity;
|
import android.app.ListActivity;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.ProgressDialog;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.IPackageStatsObserver;
|
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageItemInfo;
|
import android.content.pm.PackageItemInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageStats;
|
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -54,24 +43,16 @@ import android.os.SystemClock;
|
|||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Config;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.Window;
|
|
||||||
import android.widget.AbsListView;
|
import android.widget.AbsListView;
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.Filter;
|
|
||||||
import android.widget.Filterable;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.AdapterView.OnItemClickListener;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -104,6 +85,12 @@ public class RunningServices extends ListActivity
|
|||||||
|
|
||||||
int mProcessBgColor;
|
int mProcessBgColor;
|
||||||
|
|
||||||
|
TextView mBackgroundProcessText;
|
||||||
|
TextView mForegroundProcessText;
|
||||||
|
|
||||||
|
int mLastNumBackgroundProcesses = -1;
|
||||||
|
int mLastNumForegroundProcesses = -1;
|
||||||
|
|
||||||
Dialog mCurDialog;
|
Dialog mCurDialog;
|
||||||
|
|
||||||
class ActiveItem {
|
class ActiveItem {
|
||||||
@@ -114,6 +101,13 @@ public class RunningServices extends ListActivity
|
|||||||
long mFirstRunTime;
|
long mFirstRunTime;
|
||||||
|
|
||||||
void updateTime(Context context) {
|
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) {
|
if (mItem.mActiveSince >= 0) {
|
||||||
mHolder.size.setText(DateUtils.formatElapsedTime(mBuilder,
|
mHolder.size.setText(DateUtils.formatElapsedTime(mBuilder,
|
||||||
(SystemClock.uptimeMillis()-mFirstRunTime)/1000));
|
(SystemClock.uptimeMillis()-mFirstRunTime)/1000));
|
||||||
@@ -123,9 +117,11 @@ public class RunningServices extends ListActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class BaseItem {
|
static class BaseItem {
|
||||||
boolean mIsProcess;
|
final boolean mIsProcess;
|
||||||
|
|
||||||
PackageItemInfo mPackageInfo;
|
PackageItemInfo mPackageInfo;
|
||||||
CharSequence mDisplayLabel;
|
CharSequence mDisplayLabel;
|
||||||
String mLabel;
|
String mLabel;
|
||||||
@@ -136,21 +132,119 @@ public class RunningServices extends ListActivity
|
|||||||
long mActiveSince;
|
long mActiveSince;
|
||||||
long mSize;
|
long mSize;
|
||||||
String mSizeStr;
|
String mSizeStr;
|
||||||
|
String mCurSizeStr;
|
||||||
boolean mNeedDivider;
|
boolean mNeedDivider;
|
||||||
|
|
||||||
|
public BaseItem(boolean isProcess) {
|
||||||
|
mIsProcess = isProcess;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ServiceItem extends BaseItem {
|
static class ServiceItem extends BaseItem {
|
||||||
ActivityManager.RunningServiceInfo mRunningService;
|
ActivityManager.RunningServiceInfo mRunningService;
|
||||||
ServiceInfo mServiceInfo;
|
ServiceInfo mServiceInfo;
|
||||||
boolean mShownAsStarted;
|
boolean mShownAsStarted;
|
||||||
|
|
||||||
|
public ServiceItem() {
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ProcessItem extends BaseItem {
|
static class ProcessItem extends BaseItem {
|
||||||
final HashMap<ComponentName, ServiceItem> mServices
|
final HashMap<ComponentName, ServiceItem> mServices
|
||||||
= new HashMap<ComponentName, ServiceItem>();
|
= new HashMap<ComponentName, ServiceItem>();
|
||||||
int mUid;
|
final SparseArray<ProcessItem> mDependentProcesses
|
||||||
|
= new SparseArray<ProcessItem>();
|
||||||
|
|
||||||
|
final int mUid;
|
||||||
|
final String mProcessName;
|
||||||
int mPid;
|
int mPid;
|
||||||
|
|
||||||
|
ProcessItem mClient;
|
||||||
|
int mLastNumDependentProcesses;
|
||||||
|
|
||||||
|
int mRunningSeq;
|
||||||
|
ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
|
||||||
|
|
||||||
|
public ProcessItem(int uid, String processName) {
|
||||||
|
super(true);
|
||||||
|
mDescription = 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,
|
boolean updateService(Context context,
|
||||||
ActivityManager.RunningServiceInfo service) {
|
ActivityManager.RunningServiceInfo service) {
|
||||||
final PackageManager pm = context.getPackageManager();
|
final PackageManager pm = context.getPackageManager();
|
||||||
@@ -211,16 +305,89 @@ public class RunningServices extends ListActivity
|
|||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean updateSize(Context context) {
|
||||||
|
boolean changed = false;
|
||||||
|
|
||||||
|
if (mPid != 0 && mSize == 0) {
|
||||||
|
final int NP = mDependentProcesses.size();
|
||||||
|
for (int i=0; i<NP; i++) {
|
||||||
|
ProcessItem proc = mDependentProcesses.valueAt(i);
|
||||||
|
changed |= proc.updateSize(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.MemoryInfo mi = new Debug.MemoryInfo();
|
||||||
|
// XXX This is a hack... I really don't want to be
|
||||||
|
// doing a synchronous call into the app, but can't
|
||||||
|
// figure out any other way to get the pss.
|
||||||
|
try {
|
||||||
|
ActivityManagerNative.getDefault().getProcessMemoryInfo(
|
||||||
|
mPid, mi);
|
||||||
|
mSize = (mi.dalvikPss + mi.nativePss
|
||||||
|
+ mi.otherPss) * 1024;
|
||||||
|
String sizeStr = Formatter.formatFileSize(
|
||||||
|
context, mSize);
|
||||||
|
if (!sizeStr.equals(mSizeStr)){
|
||||||
|
//changed = true;
|
||||||
|
mSizeStr = sizeStr;
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.updateSize(context);
|
||||||
|
changed |= proc.buildDependencyChain(context, pm, curSeq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mLastNumDependentProcesses != mDependentProcesses.size()) {
|
||||||
|
changed = true;
|
||||||
|
mLastNumDependentProcesses = mDependentProcesses.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addDependentProcesses(ArrayList<BaseItem> dest) {
|
||||||
|
final int NP = mDependentProcesses.size();
|
||||||
|
for (int i=0; i<NP; i++) {
|
||||||
|
ProcessItem proc = mDependentProcesses.valueAt(i);
|
||||||
|
proc.addDependentProcesses(dest);
|
||||||
|
dest.add(proc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class State {
|
static class State {
|
||||||
final SparseArray<HashMap<String, ProcessItem>> mProcesses
|
final SparseArray<HashMap<String, ProcessItem>> mProcesses
|
||||||
= new SparseArray<HashMap<String, ProcessItem>>();
|
= new SparseArray<HashMap<String, ProcessItem>>();
|
||||||
|
final SparseArray<ProcessItem> mActiveProcesses
|
||||||
|
= new SparseArray<ProcessItem>();
|
||||||
|
|
||||||
|
// Temporary for finding process dependencies.
|
||||||
|
final SparseArray<ProcessItem> mRunningProcesses
|
||||||
|
= new SparseArray<ProcessItem>();
|
||||||
|
|
||||||
final ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
|
final ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
|
||||||
|
|
||||||
int mSequence = 0;
|
int mSequence = 0;
|
||||||
|
|
||||||
|
int mNumBackgroundProcesses;
|
||||||
|
int mNumForegroundProcesses;
|
||||||
|
|
||||||
boolean update(Context context, ActivityManager am) {
|
boolean update(Context context, ActivityManager am) {
|
||||||
final PackageManager pm = context.getPackageManager();
|
final PackageManager pm = context.getPackageManager();
|
||||||
|
|
||||||
@@ -230,10 +397,7 @@ public class RunningServices extends ListActivity
|
|||||||
|
|
||||||
List<ActivityManager.RunningServiceInfo> services
|
List<ActivityManager.RunningServiceInfo> services
|
||||||
= am.getRunningServices(MAX_SERVICES);
|
= am.getRunningServices(MAX_SERVICES);
|
||||||
if (services == null) {
|
final int NS = services != null ? services.size() : 0;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final int NS = services.size();
|
|
||||||
for (int i=0; i<NS; i++) {
|
for (int i=0; i<NS; i++) {
|
||||||
ActivityManager.RunningServiceInfo si = services.get(i);
|
ActivityManager.RunningServiceInfo si = services.get(i);
|
||||||
// We are not interested in services that have not been started
|
// We are not interested in services that have not been started
|
||||||
@@ -257,19 +421,7 @@ public class RunningServices extends ListActivity
|
|||||||
ProcessItem proc = procs.get(si.process);
|
ProcessItem proc = procs.get(si.process);
|
||||||
if (proc == null) {
|
if (proc == null) {
|
||||||
changed = true;
|
changed = true;
|
||||||
proc = new ProcessItem();
|
proc = new ProcessItem(si.uid, si.process);
|
||||||
proc.mIsProcess = true;
|
|
||||||
proc.mDescription = si.process;
|
|
||||||
proc.mUid = si.uid;
|
|
||||||
try {
|
|
||||||
ApplicationInfo ai = pm.getApplicationInfo(si.process, 0);
|
|
||||||
if (ai.uid == si.uid) {
|
|
||||||
proc.mDisplayLabel = ai.loadLabel(context.getPackageManager());
|
|
||||||
proc.mLabel = proc.mDisplayLabel.toString();
|
|
||||||
proc.mPackageInfo = ai;
|
|
||||||
}
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
}
|
|
||||||
procs.put(si.process, proc);
|
procs.put(si.process, proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,76 +429,127 @@ public class RunningServices extends ListActivity
|
|||||||
int pid = si.restarting == 0 ? si.pid : 0;
|
int pid = si.restarting == 0 ? si.pid : 0;
|
||||||
if (pid != proc.mPid) {
|
if (pid != proc.mPid) {
|
||||||
changed = true;
|
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.mPid = pid;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
proc.mSize = 0;
|
proc.mSize = 0;
|
||||||
if (proc.mPid != 0) {
|
proc.mDependentProcesses.clear();
|
||||||
Debug.MemoryInfo mi = new Debug.MemoryInfo();
|
|
||||||
// XXX This is a hack... I really don't want to be
|
|
||||||
// doing a synchronous call into the app, but can't
|
|
||||||
// figure out any other way to get the pss.
|
|
||||||
try {
|
|
||||||
ActivityManagerNative.getDefault().getProcessMemoryInfo(
|
|
||||||
proc.mPid, mi);
|
|
||||||
proc.mSize = (mi.dalvikPss + mi.nativePss
|
|
||||||
+ mi.otherPss) * 1024;
|
|
||||||
String sizeStr = Formatter.formatFileSize(
|
|
||||||
context, proc.mSize);
|
|
||||||
if (!sizeStr.equals(proc.mSizeStr)){
|
|
||||||
changed = true;
|
|
||||||
proc.mSizeStr = sizeStr;
|
|
||||||
}
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
proc.mCurSeq = mSequence;
|
proc.mCurSeq = mSequence;
|
||||||
}
|
}
|
||||||
changed |= proc.updateService(context, si);
|
changed |= proc.updateService(context, si);
|
||||||
|
}
|
||||||
|
|
||||||
if (proc.mLabel == null) {
|
// Now update the map of other processes that are running (but
|
||||||
// If we couldn't get information about the overall
|
// don't have services actively running inside them).
|
||||||
// process, try to find something about the uid.
|
List<ActivityManager.RunningAppProcessInfo> processes
|
||||||
String[] pkgs = pm.getPackagesForUid(proc.mUid);
|
= am.getRunningAppProcesses();
|
||||||
for (String name : pkgs) {
|
final int NP = processes != null ? processes.size() : 0;
|
||||||
try {
|
for (int i=0; i<NP; i++) {
|
||||||
PackageInfo pi = pm.getPackageInfo(name, 0);
|
ActivityManager.RunningAppProcessInfo pi = processes.get(i);
|
||||||
if (pi.sharedUserLabel != 0) {
|
ProcessItem proc = mActiveProcesses.get(pi.pid);
|
||||||
CharSequence nm = pm.getText(name,
|
if (proc == null) {
|
||||||
pi.sharedUserLabel, pi.applicationInfo);
|
// This process is not one that is a direct container
|
||||||
if (nm != null) {
|
// of a service, so look for it in the secondary
|
||||||
proc.mDisplayLabel = nm;
|
// running list.
|
||||||
proc.mLabel = nm.toString();
|
proc = mRunningProcesses.get(pi.pid);
|
||||||
proc.mPackageInfo = pi.applicationInfo;
|
if (proc == null) {
|
||||||
break;
|
proc = new ProcessItem(pi.uid, pi.processName);
|
||||||
|
proc.mPid = pi.pid;
|
||||||
|
mRunningProcesses.put(pi.pid, proc);
|
||||||
}
|
}
|
||||||
|
proc.mDependentProcesses.clear();
|
||||||
|
proc.mSize = 0;
|
||||||
}
|
}
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If still don't have anything to display, just use the
|
// Follow the tree from all primary service processes to all
|
||||||
// service info.
|
// processes they are dependent on, marking these processes as
|
||||||
if (proc.mLabel == null) {
|
// still being active and determining if anything has changed.
|
||||||
proc.mPackageInfo = proc.mServices.get(si.service)
|
final int NAP = mActiveProcesses.size();
|
||||||
.mServiceInfo.applicationInfo;
|
for (int i=0; i<NAP; i++) {
|
||||||
proc.mDisplayLabel = proc.mPackageInfo.loadLabel(pm);
|
ProcessItem proc = mActiveProcesses.valueAt(i);
|
||||||
proc.mLabel = proc.mDisplayLabel.toString();
|
if (proc.mCurSeq == mSequence) {
|
||||||
|
changed |= proc.buildDependencyChain(context, pm, mSequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count number of interesting other (non-active) processes.
|
||||||
|
mNumBackgroundProcesses = 0;
|
||||||
|
mNumForegroundProcesses = 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) {
|
||||||
|
mNumBackgroundProcesses++;
|
||||||
|
} else if (proc.mRunningProcessInfo.importance <=
|
||||||
|
ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
|
||||||
|
mNumForegroundProcesses++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for anything that no longer exists...
|
// Look for services and their primary processes that no longer exist...
|
||||||
for (int i=0; i<mProcesses.size(); i++) {
|
for (int i=0; i<mProcesses.size(); i++) {
|
||||||
HashMap<String, ProcessItem> procs = mProcesses.valueAt(i);
|
HashMap<String, ProcessItem> procs = mProcesses.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();
|
||||||
if (pi.mCurSeq != mSequence) {
|
if (pi.mCurSeq == mSequence) {
|
||||||
|
pi.ensureLabel(pm);
|
||||||
|
changed |= pi.updateSize(context);
|
||||||
|
if (pi.mPid == 0) {
|
||||||
|
// Sanity: a non-process can't be dependent on
|
||||||
|
// anything.
|
||||||
|
pi.mDependentProcesses.clear();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
changed = true;
|
changed = true;
|
||||||
pit.remove();
|
pit.remove();
|
||||||
if (procs.size() == 0) {
|
if (procs.size() == 0) {
|
||||||
mProcesses.remove(mProcesses.keyAt(i));
|
mProcesses.remove(mProcesses.keyAt(i));
|
||||||
}
|
}
|
||||||
|
if (pi.mPid != 0) {
|
||||||
|
mActiveProcesses.remove(pi.mPid);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Iterator<ServiceItem> sit = pi.mServices.values().iterator();
|
Iterator<ServiceItem> sit = pi.mServices.values().iterator();
|
||||||
@@ -365,7 +568,11 @@ public class RunningServices extends ListActivity
|
|||||||
for (int i=0; i<mProcesses.size(); i++) {
|
for (int i=0; i<mProcesses.size(); i++) {
|
||||||
for (ProcessItem pi : mProcesses.valueAt(i).values()) {
|
for (ProcessItem pi : mProcesses.valueAt(i).values()) {
|
||||||
pi.mNeedDivider = false;
|
pi.mNeedDivider = false;
|
||||||
|
// First add processes we are dependent on.
|
||||||
|
pi.addDependentProcesses(mItems);
|
||||||
|
// And add the process itself.
|
||||||
mItems.add(pi);
|
mItems.add(pi);
|
||||||
|
// And finally the services running in it.
|
||||||
boolean needDivider = false;
|
boolean needDivider = false;
|
||||||
for (ServiceItem si : pi.mServices.values()) {
|
for (ServiceItem si : pi.mServices.values()) {
|
||||||
si.mNeedDivider = needDivider;
|
si.mNeedDivider = needDivider;
|
||||||
@@ -456,27 +663,27 @@ public class RunningServices extends ListActivity
|
|||||||
vh.name.setText(item.mDisplayLabel);
|
vh.name.setText(item.mDisplayLabel);
|
||||||
vh.separator.setVisibility(item.mNeedDivider
|
vh.separator.setVisibility(item.mNeedDivider
|
||||||
? View.VISIBLE : View.INVISIBLE);
|
? View.VISIBLE : View.INVISIBLE);
|
||||||
if (item.mIsProcess) {
|
|
||||||
view.setBackgroundColor(mProcessBgColor);
|
|
||||||
vh.icon.setImageDrawable(item.mPackageInfo.loadIcon(getPackageManager()));
|
|
||||||
vh.description.setText(item.mDescription);
|
|
||||||
vh.size.setText(item.mSizeStr);
|
|
||||||
mActiveItems.remove(view);
|
|
||||||
} else {
|
|
||||||
view.setBackgroundDrawable(null);
|
|
||||||
vh.icon.setImageDrawable(null);
|
|
||||||
vh.description.setText("");
|
|
||||||
ActiveItem ai = new ActiveItem();
|
ActiveItem ai = new ActiveItem();
|
||||||
ai.mRootView = view;
|
ai.mRootView = view;
|
||||||
ai.mItem = item;
|
ai.mItem = item;
|
||||||
ai.mHolder = vh;
|
ai.mHolder = vh;
|
||||||
ai.mFirstRunTime = item.mActiveSince;
|
ai.mFirstRunTime = item.mActiveSince;
|
||||||
vh.description.setText(item.mDescription);
|
vh.description.setText(item.mDescription);
|
||||||
|
if (item.mIsProcess) {
|
||||||
|
view.setBackgroundColor(mProcessBgColor);
|
||||||
|
vh.icon.setImageDrawable(item.mPackageInfo.loadIcon(getPackageManager()));
|
||||||
|
vh.description.setText(item.mDescription);
|
||||||
|
item.mCurSizeStr = null;
|
||||||
|
} else {
|
||||||
|
view.setBackgroundDrawable(null);
|
||||||
|
vh.icon.setImageDrawable(null);
|
||||||
|
vh.description.setText(item.mDescription);
|
||||||
|
ai.mFirstRunTime = item.mActiveSince;
|
||||||
|
}
|
||||||
ai.updateTime(RunningServices.this);
|
ai.updateTime(RunningServices.this);
|
||||||
mActiveItems.put(view, ai);
|
mActiveItems.put(view, ai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
final Handler mHandler = new Handler() {
|
final Handler mHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
@@ -516,14 +723,27 @@ public class RunningServices extends ListActivity
|
|||||||
mState = new State();
|
mState = new State();
|
||||||
}
|
}
|
||||||
mProcessBgColor = 0xff505050;
|
mProcessBgColor = 0xff505050;
|
||||||
|
setContentView(R.layout.running_services);
|
||||||
getListView().setDivider(null);
|
getListView().setDivider(null);
|
||||||
getListView().setAdapter(new ServiceListAdapter(mState));
|
getListView().setAdapter(new ServiceListAdapter(mState));
|
||||||
|
mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
|
||||||
|
mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateList() {
|
void updateList() {
|
||||||
if (mState.update(this, mAm)) {
|
if (mState.update(this, mAm)) {
|
||||||
((ServiceListAdapter)(getListView().getAdapter())).notifyDataSetChanged();
|
((ServiceListAdapter)(getListView().getAdapter())).notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
if (mLastNumBackgroundProcesses != mState.mNumBackgroundProcesses) {
|
||||||
|
mLastNumBackgroundProcesses = mState.mNumBackgroundProcesses;
|
||||||
|
mBackgroundProcessText.setText(getResources().getString(
|
||||||
|
R.string.service_background_processes, mLastNumBackgroundProcesses));
|
||||||
|
}
|
||||||
|
if (mLastNumForegroundProcesses != mState.mNumForegroundProcesses) {
|
||||||
|
mLastNumForegroundProcesses = mState.mNumForegroundProcesses;
|
||||||
|
mForegroundProcessText.setText(getResources().getString(
|
||||||
|
R.string.service_foreground_processes, mLastNumForegroundProcesses));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -537,9 +757,16 @@ public class RunningServices extends ListActivity
|
|||||||
si.mRunningService.service);
|
si.mRunningService.service);
|
||||||
if (pi != null) {
|
if (pi != null) {
|
||||||
try {
|
try {
|
||||||
pi.send();
|
this.startActivity(pi, null,
|
||||||
|
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
| Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,
|
||||||
|
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||||
} catch (PendingIntent.CanceledException e) {
|
} catch (PendingIntent.CanceledException e) {
|
||||||
// whatever.
|
Log.w(TAG, e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Reference in New Issue
Block a user