diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index f523b55404ad8..62ed697997e01 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -16,6 +16,7 @@ package android.app; +import android.os.BatteryStats; import android.os.IBinder; import com.android.internal.app.IUsageStats; import com.android.internal.os.PkgUsageStats; @@ -2210,7 +2211,7 @@ public class ActivityManager { pw.println(); dumpService(pw, fd, "package", new String[] { packageName}); pw.println(); - dumpService(pw, fd, "batteryinfo", new String[] { packageName}); + dumpService(pw, fd, BatteryStats.SERVICE_NAME, new String[] { packageName}); pw.flush(); } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index fef18182ce85e..7c09e89c01537 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -41,7 +41,10 @@ import android.util.TimeUtils; public abstract class BatteryStats implements Parcelable { private static final boolean LOCAL_LOGV = false; - + + /** @hide */ + public static final String SERVICE_NAME = "batterystats"; + /** * A constant indicating a partial wake lock timer. */ diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index ce952d1dabd58..6f740cd036d3d 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -43,6 +43,7 @@ import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.KeyMgmt; +import android.os.BatteryStats; import android.os.Binder; import android.os.Handler; import android.os.INetworkManagementService; @@ -347,7 +348,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub if (mBandwidthControlEnabled) { try { - IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")) + IBatteryStats.Stub.asInterface(ServiceManager.getService(BatteryStats.SERVICE_NAME)) .noteNetworkStatsEnabled(); } catch (RemoteException e) { } diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java index 21d31111c38df..9b5f8f65cb489 100644 --- a/services/java/com/android/server/VibratorService.java +++ b/services/java/com/android/server/VibratorService.java @@ -24,6 +24,7 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.database.ContentObserver; import android.hardware.input.InputManager; +import android.os.BatteryStats; import android.os.Handler; import android.os.IVibratorService; import android.os.PowerManager; @@ -143,7 +144,8 @@ public class VibratorService extends IVibratorService.Stub mWakeLock.setReferenceCounted(true); mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE)); - mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); + mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService( + BatteryStats.SERVICE_NAME)); mVibrations = new LinkedList(); diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index 912c465b5c162..c558fbdca2f15 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -241,11 +241,14 @@ public final class ActiveServices { if (unscheduleServiceRestartLocked(r)) { if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r); } + r.lastActivity = SystemClock.uptimeMillis(); r.startRequested = true; + if (r.tracker != null) { + r.tracker.setStarted(true, mAm.mProcessTracker.getMemFactor(), r.lastActivity); + } r.callStart = false; r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), service, neededGrants)); - r.lastActivity = SystemClock.uptimeMillis(); synchronized (r.stats.getBatteryStats()) { r.stats.startRunningLocked(); } @@ -261,8 +264,12 @@ public final class ActiveServices { service.stats.stopRunningLocked(); } service.startRequested = false; + if (service.tracker != null) { + service.tracker.setStarted(false, mAm.mProcessTracker.getMemFactor(), + SystemClock.uptimeMillis()); + } service.callStart = false; - bringDownServiceLocked(service, false); + bringDownServiceIfNeededLocked(service, false, false); } int stopServiceLocked(IApplicationThread caller, Intent service, @@ -355,11 +362,15 @@ public final class ActiveServices { synchronized (r.stats.getBatteryStats()) { r.stats.stopRunningLocked(); - r.startRequested = false; - r.callStart = false; } + r.startRequested = false; + if (r.tracker != null) { + r.tracker.setStarted(false, mAm.mProcessTracker.getMemFactor(), + SystemClock.uptimeMillis()); + } + r.callStart = false; final long origId = Binder.clearCallingIdentity(); - bringDownServiceLocked(r, false); + bringDownServiceIfNeededLocked(r, false, false); Binder.restoreCallingIdentity(origId); return true; } @@ -489,6 +500,17 @@ public final class ActiveServices { + s); } + if ((flags&Context.BIND_AUTO_CREATE) != 0) { + s.lastActivity = SystemClock.uptimeMillis(); + if (!s.hasAutoCreateConnections()) { + // This is the first binding, let the tracker know. + if (s.tracker != null) { + s.tracker.setBound(true, mAm.mProcessTracker.getMemFactor(), + s.lastActivity); + } + } + } + AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent); @@ -748,7 +770,12 @@ public final class ActiveServices { sInfo.applicationInfo.uid, sInfo.packageName, sInfo.name); } - r = new ServiceRecord(mAm, ss, name, filter, sInfo, res); + ProcessTracker.ServiceState tracker = null; + if ((sInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) { + tracker = mAm.mProcessTracker.getServiceStateLocked(sInfo.packageName, + sInfo.applicationInfo.uid, sInfo.name); + } + r = new ServiceRecord(mAm, ss, name, filter, sInfo, res, tracker); res.setService(r); mServiceMap.putServiceByName(name, UserHandle.getUserId(r.appInfo.uid), r); mServiceMap.putServiceByIntent(filter, UserHandle.getUserId(r.appInfo.uid), r); @@ -798,14 +825,19 @@ public final class ActiveServices { else if (DEBUG_SERVICE_EXECUTING) Log.v(TAG, ">>> EXECUTING " + why + " of " + r.shortName); long now = SystemClock.uptimeMillis(); - if (r.executeNesting == 0 && r.app != null) { - if (r.app.executingServices.size() == 0) { - Message msg = mAm.mHandler.obtainMessage( - ActivityManagerService.SERVICE_TIMEOUT_MSG); - msg.obj = r.app; - mAm.mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT); + if (r.executeNesting == 0) { + if (r.tracker != null) { + r.tracker.setExecuting(true, mAm.mProcessTracker.getMemFactor(), now); + } + if (r.app != null) { + if (r.app.executingServices.size() == 0) { + Message msg = mAm.mHandler.obtainMessage( + ActivityManagerService.SERVICE_TIMEOUT_MSG); + msg.obj = r.app; + mAm.mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT); + } + r.app.executingServices.add(r); } - r.app.executingServices.add(r); } r.executeNesting++; r.executingStart = now; @@ -991,7 +1023,7 @@ public final class ActiveServices { + r.appInfo.uid + " for service " + r.intent.getIntent() + ": user " + r.userId + " is stopped"; Slog.w(TAG, msg); - bringDownServiceLocked(r, true); + bringDownServiceLocked(r); return msg; } @@ -1045,7 +1077,7 @@ public final class ActiveServices { + r.appInfo.uid + " for service " + r.intent.getIntent() + ": process is bad"; Slog.w(TAG, msg); - bringDownServiceLocked(r, true); + bringDownServiceLocked(r); return msg; } if (isolated) { @@ -1167,26 +1199,29 @@ public final class ActiveServices { } } - private final void bringDownServiceLocked(ServiceRecord r, boolean force) { + private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, + boolean hasConn) { //Slog.i(TAG, "Bring down service:"); //r.dump(" "); // Does it still need to run? - if (!force && r.startRequested) { + if (r.startRequested) { return; } - if (!force) { - // XXX should probably keep a count of the number of auto-create - // connections directly in the service. - for (int conni=r.connections.size()-1; conni>=0; conni--) { - ArrayList cr = r.connections.valueAt(conni); - for (int i=0; i 0) { + if (sr.tracker != null) { + sr.tracker.setStarted(false, mAm.mProcessTracker.getMemFactor(), + SystemClock.uptimeMillis()); + } + if (!sr.hasAutoCreateConnections()) { // Whoops, no reason to restart! - bringDownServiceLocked(sr, true); + bringDownServiceLocked(sr); } } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 2124095502f3f..21c752b6e59fe 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -7292,7 +7292,6 @@ public final class ActivityManagerService extends ActivityManagerNative if (isolated) { int userId = UserHandle.getUserId(uid); int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1; - uid = 0; while (true) { if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) { @@ -7314,7 +7313,7 @@ public final class ActivityManagerService extends ActivityManagerNative ps = stats.getProcessStatsLocked(info.uid, proc); } return new ProcessRecord(ps, thread, info, proc, uid, - mProcessTracker.getProcessStateLocked(info.packageName, uid, proc)); + mProcessTracker.getProcessStateLocked(info.packageName, info.uid, proc)); } final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) { @@ -14193,7 +14192,7 @@ public final class ActivityManagerService extends ActivityManagerNative // are managing to keep around is less than half the maximum we desire; // if we are keeping a good number around, we'll let them use whatever // memory they want. - int memFactor = ProcessTracker.STATE_MEM_FACTOR_NORMAL_ADJ; + int memFactor = ProcessTracker.ADJ_MEM_FACTOR_NORMAL; if (numCached <= ProcessList.TRIM_CACHED_APPS && numEmpty <= ProcessList.TRIM_EMPTY_APPS) { final int numCachedAndEmpty = numCached + numEmpty; @@ -14207,13 +14206,13 @@ public final class ActivityManagerService extends ActivityManagerNative int fgTrimLevel; if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; - memFactor = ProcessTracker.STATE_MEM_FACTOR_CRITIAL_ADJ; + memFactor = ProcessTracker.ADJ_MEM_FACTOR_CRITICAL; } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; - memFactor = ProcessTracker.STATE_MEM_FACTOR_LOW_ADJ; + memFactor = ProcessTracker.ADJ_MEM_FACTOR_LOW; } else { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; - memFactor = ProcessTracker.STATE_MEM_FACTOR_MODERATE_ADJ; + memFactor = ProcessTracker.ADJ_MEM_FACTOR_MODERATE; } int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; for (i=0; i]"); pw.println(" --checkin: format output for a checkin report."); pw.println(" --unplugged: only output data since last unplugged."); diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java index fb8d09c6f1870..ec8a0b24b3791 100644 --- a/services/java/com/android/server/am/ProcessTracker.java +++ b/services/java/com/android/server/am/ProcessTracker.java @@ -17,6 +17,7 @@ package com.android.server.am; import android.os.SystemClock; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.SparseArray; import android.util.TimeUtils; @@ -24,6 +25,9 @@ import com.android.server.ProcessMap; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; public final class ProcessTracker { public static final int STATE_NOTHING = -1; @@ -36,16 +40,18 @@ public final class ProcessTracker { public static final int STATE_HOME = 6; public static final int STATE_PREVIOUS = 7; public static final int STATE_CACHED = 8; - public static final int STATE_MEM_FACTOR_MOD = STATE_CACHED+1; - public static final int STATE_MEM_FACTOR_NORMAL_ADJ = 0; - public static final int STATE_MEM_FACTOR_MODERATE_ADJ = STATE_MEM_FACTOR_MOD; - public static final int STATE_MEM_FACTOR_LOW_ADJ = STATE_MEM_FACTOR_MOD*2; - public static final int STATE_MEM_FACTOR_CRITIAL_ADJ = STATE_MEM_FACTOR_MOD*3; - public static final int STATE_MEM_FACTOR_COUNT = STATE_MEM_FACTOR_MOD*4; - public static final int STATE_SCREEN_ON_MOD = STATE_MEM_FACTOR_COUNT; - public static final int STATE_SCREEN_OFF_ADJ = 0; - public static final int STATE_SCREEN_ON_ADJ = STATE_SCREEN_ON_MOD; - public static final int STATE_COUNT = STATE_SCREEN_ON_MOD*2; + public static final int STATE_COUNT = STATE_CACHED+1; + + public static final int ADJ_NOTHING = -1; + public static final int ADJ_MEM_FACTOR_NORMAL = 0; + public static final int ADJ_MEM_FACTOR_MODERATE = 1; + public static final int ADJ_MEM_FACTOR_LOW = 2; + public static final int ADJ_MEM_FACTOR_CRITICAL = 3; + public static final int ADJ_MEM_FACTOR_COUNT = ADJ_MEM_FACTOR_CRITICAL+1; + public static final int ADJ_SCREEN_MOD = ADJ_MEM_FACTOR_COUNT; + public static final int ADJ_SCREEN_OFF = 0; + public static final int ADJ_SCREEN_ON = ADJ_SCREEN_MOD; + public static final int ADJ_COUNT = ADJ_SCREEN_ON*2; static String[] STATE_NAMES = new String[] { "Top ", "Foreground ", "Visible ", "Perceptible", "Backup ", @@ -53,13 +59,25 @@ public final class ProcessTracker { }; public static final class ProcessState { - final long[] mDurations = new long[STATE_COUNT]; + final String mPackage; + final int mUid; + final String mName; + + final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT]; int mCurState = STATE_NOTHING; long mStartTime; + long mTmpTotalTime; + + public ProcessState(String pkg, int uid, String name) { + mPackage = pkg; + mUid = uid; + mName = name; + } + public void setState(int state, int memFactor, long now) { if (state != STATE_NOTHING) { - state += memFactor; + state += memFactor*STATE_COUNT; } if (mCurState != state) { if (mCurState != STATE_NOTHING) { @@ -72,8 +90,59 @@ public final class ProcessTracker { } public static final class ServiceState { - long mStartedDuration; - long mStartedTime; + final long[] mStartedDurations = new long[ADJ_COUNT]; + int mStartedCount; + int mStartedState = STATE_NOTHING; + long mStartedStartTime; + + final long[] mBoundDurations = new long[ADJ_COUNT]; + int mBoundCount; + int mBoundState = STATE_NOTHING; + long mBoundStartTime; + + final long[] mExecDurations = new long[ADJ_COUNT]; + int mExecCount; + int mExecState = STATE_NOTHING; + long mExecStartTime; + + public void setStarted(boolean started, int memFactor, long now) { + int state = started ? memFactor : STATE_NOTHING; + if (mStartedState != state) { + if (mStartedState != STATE_NOTHING) { + mStartedDurations[mStartedState] += now - mStartedStartTime; + } else if (started) { + mStartedCount++; + } + mStartedState = state; + mStartedStartTime = now; + } + } + + public void setBound(boolean bound, int memFactor, long now) { + int state = bound ? memFactor : STATE_NOTHING; + if (mBoundState != state) { + if (mBoundState != STATE_NOTHING) { + mBoundDurations[mBoundState] += now - mBoundStartTime; + } else if (bound) { + mBoundCount++; + } + mBoundState = state; + mBoundStartTime = now; + } + } + + public void setExecuting(boolean executing, int memFactor, long now) { + int state = executing ? memFactor : STATE_NOTHING; + if (mExecState != state) { + if (mExecState != STATE_NOTHING) { + mExecDurations[mExecState] += now - mExecStartTime; + } else if (executing) { + mExecCount++; + } + mExecState = state; + mExecStartTime = now; + } + } } public static final class PackageState { @@ -88,7 +157,7 @@ public final class ProcessTracker { static final class State { final ProcessMap mPackages = new ProcessMap(); - final long[] mMemFactorDurations = new long[STATE_COUNT/STATE_MEM_FACTOR_MOD]; + final long[] mMemFactorDurations = new long[ADJ_COUNT]; int mMemFactor = STATE_NOTHING; long mStartTime; } @@ -114,7 +183,7 @@ public final class ProcessTracker { if (ps != null) { return ps; } - ps = new ProcessState(); + ps = new ProcessState(packageName, uid, processName); as.mProcesses.put(processName, ps); return ps; } @@ -132,15 +201,31 @@ public final class ProcessTracker { public boolean setMemFactor(int memFactor, boolean screenOn, long now) { if (screenOn) { - memFactor += STATE_SCREEN_ON_MOD; + memFactor += ADJ_SCREEN_ON; } if (memFactor != mState.mMemFactor) { if (mState.mMemFactor != STATE_NOTHING) { - mState.mMemFactorDurations[mState.mMemFactor/STATE_MEM_FACTOR_MOD] - += now - mState.mStartTime; + mState.mMemFactorDurations[mState.mMemFactor] += now - mState.mStartTime; } mState.mMemFactor = memFactor; mState.mStartTime = now; + ArrayMap> pmap = mState.mPackages.getMap(); + for (int i=0; i uids = pmap.valueAt(i); + for (int j=0; j services = pkg.mServices; + for (int k=0; k collectProcessesLocked(int[] screenStates, int[] memStates, + int[] procStates, long now) { + ArrayList outProcs = new ArrayList(); + ArrayMap> pmap = mState.mPackages.getMap(); + for (int ip=0; ip procs = pmap.valueAt(ip); + for (int iu=0; iu 0) { + outProcs.add(state.mProcesses.valueAt(iproc)); + } + } + } + } + Collections.sort(outProcs, new Comparator() { + @Override + public int compare(ProcessState lhs, ProcessState rhs) { + if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) { + return -1; + } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) { + return 1; + } + return 0; + } + }); + return outProcs; + } + + void dumpProcessState(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates, + int[] memStates, int[] procStates, long now) { + long totalTime = 0; + int printedScreen = -1; + for (int is=0; is 1) { + printScreenLabel(pw, printedScreen != iscreen + ? iscreen : STATE_NOTHING); + printedScreen = iscreen; + } + if (memStates.length > 1) { + printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING); + printedMem = imem; + } + pw.print(STATE_NAMES[procStates[ip]]); pw.print(": "); + TimeUtils.formatDuration(time, pw); pw.println(running); + totalTime += time; + } + } + } + } + if (totalTime != 0) { + pw.print(prefix); + if (screenStates.length > 1) { + printScreenLabel(pw, STATE_NOTHING); + } + if (memStates.length > 1) { + printMemLabel(pw, STATE_NOTHING); + } + pw.print("TOTAL : "); + TimeUtils.formatDuration(totalTime, pw); + pw.println(); + } + } + + void dumpProcessList(PrintWriter pw, String prefix, ArrayList procs, + int[] screenStates, int[] memStates, int[] procStates, long now) { + String innerPrefix = prefix + " "; + for (int i=procs.size()-1; i>=0; i--) { + ProcessState proc = procs.get(i); + pw.print(prefix); + pw.print(proc.mPackage); + pw.print(" / "); + UserHandle.formatUid(pw, proc.mUid); + pw.print(" / "); + pw.print(proc.mName); + pw.println(":"); + dumpProcessState(pw, innerPrefix, proc, screenStates, memStates, procStates, now); + } + } + + void dumpFilteredProcesses(PrintWriter pw, String header, String prefix, + int[] screenStates, int[] memStates, int[] procStates, long now) { + ArrayList procs = collectProcessesLocked(screenStates, memStates, + procStates, now); + if (procs.size() > 0) { + pw.println(); + pw.println(header); + dumpProcessList(pw, prefix, procs, screenStates, memStates, procStates, now); + } + } + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { final long now = SystemClock.uptimeMillis(); ArrayMap> pmap = mState.mPackages.getMap(); - pw.println("Process Stats:"); + pw.println("Per-Package Process Stats:"); for (int ip=0; ip procs = pmap.valueAt(ip); for (int iu=0; iu= 0) { - time += now - svc.mStartedTime; + if (svc.mStartedCount != 0) { + pw.print(" Started op count "); pw.print(svc.mStartedCount); + pw.println(":"); + dumpSingleTime(pw, " ", svc.mStartedDurations, svc.mStartedState, + svc.mStartedStartTime, now); } - if (time != 0) { - pw.print(" Started: "); - TimeUtils.formatDuration(time, pw); pw.println(); + if (svc.mBoundCount != 0) { + pw.print(" Bound op count "); pw.print(svc.mBoundCount); + pw.println(":"); + dumpSingleTime(pw, " ", svc.mBoundDurations, svc.mBoundState, + svc.mBoundStartTime, now); + } + if (svc.mExecCount != 0) { + pw.print(" Executing op count "); pw.print(svc.mExecCount); + pw.println(":"); + dumpSingleTime(pw, " ", svc.mExecDurations, svc.mExecState, + svc.mExecStartTime, now); } } } } + dumpFilteredProcesses(pw, "Processes running while critical mem:", " ", + new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, + new int[] {ADJ_MEM_FACTOR_CRITICAL}, + new int[] {STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE, + STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS}, + now); + dumpFilteredProcesses(pw, "Processes running while low mem:", " ", + new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, + new int[] {ADJ_MEM_FACTOR_LOW}, + new int[] {STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE, + STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS}, + now); pw.println(); pw.println("Run time Stats:"); - long totalTime = 0; - int printedScreen = -1; - for (int iscreen=0; iscreen bindings = new ArrayMap(); @@ -281,7 +282,8 @@ final class ServiceRecord extends Binder { ServiceRecord(ActivityManagerService ams, BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name, - Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) { + Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter, + ProcessTracker.ServiceState tracker) { this.ams = ams; this.stats = servStats; this.name = name; @@ -297,6 +299,7 @@ final class ServiceRecord extends Binder { dataDir = sInfo.applicationInfo.dataDir; exported = sInfo.exported; this.restarter = restarter; + this.tracker = tracker; createTime = SystemClock.elapsedRealtime(); lastActivity = SystemClock.uptimeMillis(); userId = UserHandle.getUserId(appInfo.uid); @@ -319,6 +322,20 @@ final class ServiceRecord extends Binder { return a; } + public boolean hasAutoCreateConnections() { + // XXX should probably keep a count of the number of auto-create + // connections directly in the service. + for (int conni=connections.size()-1; conni>=0; conni--) { + ArrayList cr = connections.valueAt(conni); + for (int i=0; i