From dd9b82c283815747b75fe4434c65e4b6c9c9b54f Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 3 Sep 2009 00:18:47 -0700 Subject: [PATCH] Add better service reporting. This will be used elsewhere. Change-Id: Id561fa7fed5eb65446312cb697813483903d33a6 --- api/current.xml | 109 ++++++++++++++++++ core/java/android/app/ActivityManager.java | 82 +++++++++++++ .../android/app/ActivityManagerNative.java | 24 ++++ core/java/android/app/IActivityManager.java | 12 +- core/java/android/content/Intent.java | 18 +++ core/java/android/content/SyncManager.java | 4 + core/java/android/provider/Settings.java | 14 +++ core/res/res/values/strings.xml | 41 ++++--- .../server/AccessibilityManagerService.java | 5 + .../server/InputMethodManagerService.java | 5 + .../server/WallpaperManagerService.java | 6 + .../server/am/ActivityManagerService.java | 63 +++++++++- .../android/server/am/ConnectionRecord.java | 8 +- .../com/android/server/am/ProcessRecord.java | 1 + 14 files changed, 369 insertions(+), 23 deletions(-) diff --git a/api/current.xml b/api/current.xml index b052a61718ee3..7bb99e482bd94 100644 --- a/api/current.xml +++ b/api/current.xml @@ -17373,6 +17373,21 @@ visibility="public" > + + + + + + + + + + + + + + + + + + + + + + + + CREATOR = new Creator() { @@ -438,6 +455,22 @@ public class ActivityManager { } } + /** + * Returns a PendingIntent you can start to show a control panel for the + * given running service. If the service does not have a control panel, + * null is returned. + */ + public PendingIntent getRunningServiceControlPanel(ComponentName service) + throws SecurityException { + try { + return ActivityManagerNative.getDefault() + .getRunningServiceControlPanel(service); + } catch (RemoteException e) { + // System dead, we will be dead too soon! + return null; + } + } + /** * Information you can retrieve about the available memory through * {@link ActivityManager#getMemoryInfo}. @@ -704,8 +737,51 @@ public class ActivityManager { */ public int lru; + /** + * Constant for {@link #importanceReasonCode}: nothing special has + * been specified for the reason for this level. + */ + public static final int REASON_UNKNOWN = 0; + + /** + * Constant for {@link #importanceReasonCode}: one of the application's + * content providers is being used by another process. The pid of + * the client process is in {@link #importanceReasonPid} and the + * target provider in this process is in + * {@link #importanceReasonComponent}. + */ + public static final int REASON_PROVIDER_IN_USE = 1; + + /** + * Constant for {@link #importanceReasonCode}: one of the application's + * content providers is being used by another process. The pid of + * the client process is in {@link #importanceReasonPid} and the + * target provider in this process is in + * {@link #importanceReasonComponent}. + */ + public static final int REASON_SERVICE_IN_USE = 2; + + /** + * The reason for {@link #importance}, if any. + */ + public int importanceReasonCode; + + /** + * For the specified values of {@link #importanceReasonCode}, this + * is the process ID of the other process that is a client of this + * process. This will be 0 if no other process is using this one. + */ + public int importanceReasonPid; + + /** + * For the specified values of {@link #importanceReasonCode}, this + * is the name of the component that is being used in this process. + */ + public ComponentName importanceReasonComponent; + public RunningAppProcessInfo() { importance = IMPORTANCE_FOREGROUND; + importanceReasonCode = REASON_UNKNOWN; } public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) { @@ -724,6 +800,9 @@ public class ActivityManager { dest.writeStringArray(pkgList); dest.writeInt(importance); dest.writeInt(lru); + dest.writeInt(importanceReasonCode); + dest.writeInt(importanceReasonPid); + ComponentName.writeToParcel(importanceReasonComponent, dest); } public void readFromParcel(Parcel source) { @@ -732,6 +811,9 @@ public class ActivityManager { pkgList = source.readStringArray(); importance = source.readInt(); lru = source.readInt(); + importanceReasonCode = source.readInt(); + importanceReasonPid = source.readInt(); + importanceReasonComponent = ComponentName.readFromParcel(source); } public static final Creator CREATOR = diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 213f26e72d857..4ed152e34631e 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -510,6 +510,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + ComponentName comp = ComponentName.CREATOR.createFromParcel(data); + PendingIntent pi = getRunningServiceControlPanel(comp); + reply.writeNoException(); + PendingIntent.writePendingIntentOrNullToParcel(pi, reply); + return true; + } + case START_SERVICE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); @@ -1634,6 +1643,21 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + public PendingIntent getRunningServiceControlPanel(ComponentName service) + throws RemoteException + { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + service.writeToParcel(data, 0); + mRemote.transact(GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION, data, reply, 0); + reply.readException(); + PendingIntent res = PendingIntent.readPendingIntentOrNullFromParcel(reply); + data.recycle(); + reply.recycle(); + return res; + } + public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType) throws RemoteException { diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index a7bef545f65c2..a937c11f789cd 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -126,13 +126,15 @@ public interface IActivityManager extends IInterface { public void finishOtherInstances(IBinder token, ComponentName className) throws RemoteException; /* oneway */ public void reportThumbnail(IBinder token, - Bitmap thumbnail, CharSequence description) throws RemoteException; + Bitmap thumbnail, CharSequence description) throws RemoteException; public ContentProviderHolder getContentProvider(IApplicationThread caller, - String name) throws RemoteException; + String name) throws RemoteException; public void removeContentProvider(IApplicationThread caller, - String name) throws RemoteException; + String name) throws RemoteException; public void publishContentProviders(IApplicationThread caller, - List providers) throws RemoteException; + List providers) throws RemoteException; + public PendingIntent getRunningServiceControlPanel(ComponentName service) + throws RemoteException; public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType) throws RemoteException; public int stopService(IApplicationThread caller, Intent service, @@ -367,7 +369,7 @@ public interface IActivityManager extends IInterface { int PUBLISH_CONTENT_PROVIDERS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29; int SET_PERSISTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30; int FINISH_SUB_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31; - + int GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32; int START_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33; int STOP_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+34; int BIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 87a8f391bb371..1d1161eab4cc0 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2044,6 +2044,24 @@ public class Intent implements Parcelable { public static final String EXTRA_CHANGED_COMPONENT_NAME = "android.intent.extra.changed_component_name"; + /** + * @hide + * Magic extra system code can use when binding, to give a label for + * who it is that has bound to a service. This is an integer giving + * a framework string resource that can be displayed to the user. + */ + public static final String EXTRA_CLIENT_LABEL = + "android.intent.extra.client_label"; + + /** + * @hide + * Magic extra system code can use when binding, to give a PendingIntent object + * that can be launched for the user to disable the system's use of this + * service. + */ + public static final String EXTRA_CLIENT_INTENT = + "android.intent.extra.client_intent"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Intent flags (see mFlags variable). diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 5ffe9629786c2..6d27bc78bbd2e 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -1064,6 +1064,10 @@ class SyncManager implements OnAccountsUpdatedListener { Intent intent = new Intent(); intent.setAction("android.content.SyncAdapter"); intent.setComponent(info.componentName); + intent.putExtra(Intent.EXTRA_CLIENT_LABEL, + com.android.internal.R.string.sync_binding_label); + intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( + mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0)); return mContext.bindService(intent, this, Context.BIND_AUTO_CREATE); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 125ed0b5f8ad8..64e47eb94b680 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -118,6 +118,20 @@ public final class Settings { public static final String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS"; + /** + * Activity Action: Show settings for accessibility modules. + *

+ * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

+ * Input: Nothing. + *

+ * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_ACCESSIBILITY_SETTINGS = + "android.settings.ACCESSIBILITY_SETTINGS"; + /** * Activity Action: Show settings to allow configuration of security and * location privacy. diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 70c9385e7752c..3333915ecdd7a 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1943,25 +1943,34 @@ - - checked + + checked - - not checked + + not checked - The - listed applications are requesting permission to access the login credentials for account %1$s from - %2$s. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted - again. + The + listed applications are requesting permission to access the login credentials for account %1$s from + %2$s. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted + again. - The - listed applications are requesting permission to access the %1$s login credentials for account %2$s from - %3$s. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted - again. + The + listed applications are requesting permission to access the %1$s login credentials for account %2$s from + %3$s. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted + again. - Allow - Deny - Permission Requested - for account %s + Allow + Deny + Permission Requested + for account %s + + Input method + + Sync + + Accessibility + + Wallpaper + diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java index 55007ba701751..f67a7aec48ccf 100644 --- a/services/java/com/android/server/AccessibilityManagerService.java +++ b/services/java/com/android/server/AccessibilityManagerService.java @@ -25,6 +25,7 @@ import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceConnection; import android.accessibilityservice.IEventListener; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -615,6 +616,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mId = sIdCounter++; mComponentName = componentName; mIntent = new Intent().setComponent(mComponentName); + mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, + com.android.internal.R.string.accessibility_binding_label); + mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( + mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0)); } /** diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 558a024b0c7c8..1da2b47d14465 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -32,6 +32,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.app.ActivityManagerNative; import android.app.AlertDialog; +import android.app.PendingIntent; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -765,6 +766,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE); mCurIntent.setComponent(info.getComponent()); + mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, + com.android.internal.R.string.input_method_binding_label); + mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( + mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0)); if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) { mLastBindTime = SystemClock.uptimeMillis(); mHaveConnection = true; diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index c101463b2a301..cc977b09808e6 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -21,6 +21,7 @@ import static android.os.ParcelFileDescriptor.*; import android.app.IWallpaperManager; import android.app.IWallpaperManagerCallback; +import android.app.PendingIntent; import android.backup.BackupManager; import android.content.ComponentName; import android.content.Context; @@ -40,6 +41,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; import android.os.ServiceManager; import android.os.SystemClock; +import android.provider.Settings; import android.service.wallpaper.IWallpaperConnection; import android.service.wallpaper.IWallpaperEngine; import android.service.wallpaper.IWallpaperService; @@ -376,6 +378,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub { // Bind the service! WallpaperConnection newConn = new WallpaperConnection(); intent.setComponent(realName); + intent.putExtra(Intent.EXTRA_CLIENT_LABEL, + com.android.internal.R.string.wallpaper_binding_label); + intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( + mContext, 0, new Intent(Intent.ACTION_SET_WALLPAPER), 0)); if (!mContext.bindService(intent, newConn, Context.BIND_AUTO_CREATE)) { throw new IllegalArgumentException("Unable to bind service: " diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 03ebf0c9c2a3d..9554a22a2ae87 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -8866,6 +8866,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } else { currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; } + currApp.importanceReasonCode = app.adjTypeCode; + if (app.adjSource instanceof ProcessRecord) { + currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid; + } else if (app.adjSource instanceof HistoryRecord) { + HistoryRecord r = (HistoryRecord)app.adjSource; + if (r.app != null) currApp.importanceReasonPid = r.app.pid; + } + if (app.adjTarget instanceof ComponentName) { + currApp.importanceReasonComponent = (ComponentName)app.adjTarget; + } //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance // + " lru=" + currApp.lru); if (runList == null) { @@ -9888,6 +9898,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (r.app != null && r.app.persistent) { info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS; } + for (ConnectionRecord conn : r.connections.values()) { + if (conn.clientLabel != 0) { + info.clientPackage = conn.binding.client.info.packageName; + info.clientLabel = conn.clientLabel; + break; + } + } return info; } @@ -9916,6 +9933,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + public PendingIntent getRunningServiceControlPanel(ComponentName name) { + synchronized (this) { + ServiceRecord r = mServices.get(name); + if (r != null) { + for (ConnectionRecord conn : r.connections.values()) { + if (conn.clientIntent != null) { + return conn.clientIntent; + } + } + } + } + return null; + } + private final ServiceRecord findServiceLocked(ComponentName name, IBinder token) { ServiceRecord r = mServices.get(name); @@ -10783,6 +10814,29 @@ public final class ActivityManagerService extends ActivityManagerNative implemen activity = (HistoryRecord)mHistory.get(aindex); } + int clientLabel = 0; + PendingIntent clientIntent = null; + + if (callerApp.info.uid == Process.SYSTEM_UID) { + // Hacky kind of thing -- allow system stuff to tell us + // what they are, so we can report this elsewhere for + // others to know why certain services are running. + try { + clientIntent = (PendingIntent)service.getParcelableExtra( + Intent.EXTRA_CLIENT_INTENT); + } catch (RuntimeException e) { + } + if (clientIntent != null) { + clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0); + if (clientLabel != 0) { + // There are no useful extras in the intent, trash them. + // System code calling with this stuff just needs to know + // this will happen. + service = service.cloneFilter(); + } + } + } + ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, Binder.getCallingPid(), Binder.getCallingUid()); @@ -10803,7 +10857,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); ConnectionRecord c = new ConnectionRecord(b, activity, - connection, flags); + connection, flags, clientLabel, clientIntent); IBinder binder = connection.asBinder(); s.connections.put(binder, c); @@ -12776,6 +12830,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return (app.curAdj=app.maxAdj); } + app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN; app.adjSource = null; app.adjTarget = null; @@ -12909,6 +12964,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen adj = clientAdj > VISIBLE_APP_ADJ ? clientAdj : VISIBLE_APP_ADJ; app.adjType = "service"; + app.adjTypeCode = ActivityManager.RunningAppProcessInfo + .REASON_SERVICE_IN_USE; app.adjSource = cr.binding.client; app.adjTarget = s.serviceInfo.name; } @@ -12922,6 +12979,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen || a.state == ActivityState.PAUSING)) { adj = FOREGROUND_APP_ADJ; app.adjType = "service"; + app.adjTypeCode = ActivityManager.RunningAppProcessInfo + .REASON_SERVICE_IN_USE; app.adjSource = a; app.adjTarget = s.serviceInfo.name; } @@ -12964,6 +13023,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen adj = clientAdj > FOREGROUND_APP_ADJ ? clientAdj : FOREGROUND_APP_ADJ; app.adjType = "provider"; + app.adjTypeCode = ActivityManager.RunningAppProcessInfo + .REASON_PROVIDER_IN_USE; app.adjSource = client; app.adjTarget = cpr.info.name; } diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java index b3343dd51eb25..f613b001e9150 100644 --- a/services/java/com/android/server/am/ConnectionRecord.java +++ b/services/java/com/android/server/am/ConnectionRecord.java @@ -17,6 +17,7 @@ package com.android.server.am; import android.app.IServiceConnection; +import android.app.PendingIntent; import java.io.PrintWriter; @@ -28,6 +29,8 @@ class ConnectionRecord { final HistoryRecord activity; // If non-null, the owning activity. final IServiceConnection conn; // The client connection. final int flags; // Binding options. + final int clientLabel; // String resource labeling this client. + final PendingIntent clientIntent; // How to launch the client. String stringName; // Caching of toString. void dump(PrintWriter pw, String prefix) { @@ -40,11 +43,14 @@ class ConnectionRecord { } ConnectionRecord(AppBindRecord _binding, HistoryRecord _activity, - IServiceConnection _conn, int _flags) { + IServiceConnection _conn, int _flags, + int _clientLabel, PendingIntent _clientIntent) { binding = _binding; activity = _activity; conn = _conn; flags = _flags; + clientLabel = _clientLabel; + clientIntent = _clientIntent; } public String toString() { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 76fdf09baec00..d05b44ba76e5c 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -75,6 +75,7 @@ class ProcessRecord implements Watchdog.PssRequestor { boolean reportLowMemory; // Set to true when waiting to report low mem int lastPss; // Last pss size reported by app. String adjType; // Debugging: primary thing impacting oom_adj. + int adjTypeCode; // Debugging: adj code to report to app. Object adjSource; // Debugging: option dependent object. Object adjTarget; // Debugging: target component impacting oom_adj.