diff options
Diffstat (limited to 'services/java')
7 files changed, 170 insertions, 84 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 81b8d40..041c13b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -582,7 +582,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { !network.isTeardownRequested()) { if (ni.isConnected() == true) { // add the pid-specific dns - handleDnsConfigurationChange(); + handleDnsConfigurationChange(networkType); if (DBG) Slog.d(TAG, "special network already active"); return Phone.APN_ALREADY_ACTIVE; } @@ -914,7 +914,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } // do this before we broadcast the change - handleConnectivityChange(); + handleConnectivityChange(prevNetType); sendStickyBroadcast(intent); /* @@ -1070,9 +1070,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - // do this before we broadcast the change - handleConnectivityChange(); - sendStickyBroadcast(intent); /* * If the failover network is already connected, then immediately send @@ -1143,7 +1140,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } thisNet.setTeardownRequested(false); thisNet.updateNetworkSettings(); - handleConnectivityChange(); + handleConnectivityChange(type); sendConnectedBroadcast(info); } @@ -1170,38 +1167,29 @@ public class ConnectivityService extends IConnectivityManager.Stub { } /** - * After any kind of change in the connectivity state of any network, - * make sure that anything that depends on the connectivity state of - * more than one network is set up correctly. We're mainly concerned - * with making sure that the list of DNS servers is set up according - * to which networks are connected, and ensuring that the right routing - * table entries exist. + * After a change in the connectivity state of any network, We're mainly + * concerned with making sure that the list of DNS servers is setupup + * according to which networks are connected, and ensuring that the + * right routing table entries exist. */ - private void handleConnectivityChange() { + private void handleConnectivityChange(int netType) { /* * If a non-default network is enabled, add the host routes that - * will allow it's DNS servers to be accessed. Only - * If both mobile and wifi are enabled, add the host routes that - * will allow MMS traffic to pass on the mobile network. But - * remove the default route for the mobile network, so that there - * will be only one default route, to ensure that all traffic - * except MMS will travel via Wi-Fi. + * will allow it's DNS servers to be accessed. */ - handleDnsConfigurationChange(); + handleDnsConfigurationChange(netType); - for (int netType : mPriorityList) { - if (mNetTrackers[netType].getNetworkInfo().isConnected()) { - if (mNetAttributes[netType].isDefault()) { - mNetTrackers[netType].addDefaultRoute(); - } else { - mNetTrackers[netType].addPrivateDnsRoutes(); - } + if (mNetTrackers[netType].getNetworkInfo().isConnected()) { + if (mNetAttributes[netType].isDefault()) { + mNetTrackers[netType].addDefaultRoute(); } else { - if (mNetAttributes[netType].isDefault()) { - mNetTrackers[netType].removeDefaultRoute(); - } else { - mNetTrackers[netType].removePrivateDnsRoutes(); - } + mNetTrackers[netType].addPrivateDnsRoutes(); + } + } else { + if (mNetAttributes[netType].isDefault()) { + mNetTrackers[netType].removeDefaultRoute(); + } else { + mNetTrackers[netType].removePrivateDnsRoutes(); } } } @@ -1272,41 +1260,36 @@ public class ConnectivityService extends IConnectivityManager.Stub { SystemProperties.set("net.dnschange", "" + (n+1)); } - private void handleDnsConfigurationChange() { + private void handleDnsConfigurationChange(int netType) { // add default net's dns entries - for (int x = mPriorityList.length-1; x>= 0; x--) { - int netType = mPriorityList[x]; - NetworkStateTracker nt = mNetTrackers[netType]; - if (nt != null && nt.getNetworkInfo().isConnected() && - !nt.isTeardownRequested()) { - String[] dnsList = nt.getNameServers(); - if (mNetAttributes[netType].isDefault()) { - int j = 1; - for (String dns : dnsList) { - if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { - if (DBG) { - Slog.d(TAG, "adding dns " + dns + " for " + - nt.getNetworkInfo().getTypeName()); - } - SystemProperties.set("net.dns" + j++, dns); + NetworkStateTracker nt = mNetTrackers[netType]; + if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { + String[] dnsList = nt.getNameServers(); + if (mNetAttributes[netType].isDefault()) { + int j = 1; + for (String dns : dnsList) { + if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { + if (DBG) { + Slog.d(TAG, "adding dns " + dns + " for " + + nt.getNetworkInfo().getTypeName()); } + SystemProperties.set("net.dns" + j++, dns); } - for (int k=j ; k<mNumDnsEntries; k++) { - if (DBG) Slog.d(TAG, "erasing net.dns" + k); - SystemProperties.set("net.dns" + k, ""); - } - mNumDnsEntries = j; - } else { - // set per-pid dns for attached secondary nets - List pids = mNetRequestersPids[netType]; - for (int y=0; y< pids.size(); y++) { - Integer pid = (Integer)pids.get(y); - writePidDns(dnsList, pid.intValue()); - } + } + for (int k=j ; k<mNumDnsEntries; k++) { + if (DBG) Slog.d(TAG, "erasing net.dns" + k); + SystemProperties.set("net.dns" + k, ""); + } + mNumDnsEntries = j; + } else { + // set per-pid dns for attached secondary nets + List pids = mNetRequestersPids[netType]; + for (int y=0; y< pids.size(); y++) { + Integer pid = (Integer)pids.get(y); + writePidDns(dnsList, pid.intValue()); } } } - bumpDns(); } @@ -1437,9 +1420,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED: handleNotificationChange(msg.arg1 == 1, msg.arg2, (Notification) msg.obj); + break; case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: - handleDnsConfigurationChange(); + info = (NetworkInfo) msg.obj; + type = info.getType(); + handleDnsConfigurationChange(type); break; case NetworkStateTracker.EVENT_ROAMING_CHANGED: diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 2fb481c..4ee89cc 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -151,6 +151,7 @@ class PowerManagerService extends IPowerManager.Stub static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF; private final int MY_UID; + private final int MY_PID; private boolean mDoneBooting = false; private boolean mBootCompleted = false; @@ -309,7 +310,7 @@ class PowerManagerService extends IPowerManager.Stub long ident = Binder.clearCallingIdentity(); try { PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken, - MY_UID, mTag); + MY_UID, MY_PID, mTag); mHeld = true; } finally { Binder.restoreCallingIdentity(ident); @@ -434,11 +435,11 @@ class PowerManagerService extends IPowerManager.Stub } } - PowerManagerService() - { + PowerManagerService() { // Hack to get our uid... should have a func for this. long token = Binder.clearCallingIdentity(); - MY_UID = Binder.getCallingUid(); + MY_UID = Process.myUid(); + MY_PID = Process.myPid(); Binder.restoreCallingIdentity(token); // XXX remove this when the kernel doesn't timeout wake locks @@ -573,13 +574,13 @@ class PowerManagerService extends IPowerManager.Stub private class WakeLock implements IBinder.DeathRecipient { - WakeLock(int f, IBinder b, String t, int u) { + WakeLock(int f, IBinder b, String t, int u, int p) { super(); flags = f; binder = b; tag = t; uid = u == MY_UID ? Process.SYSTEM_UID : u; - pid = Binder.getCallingPid(); + pid = p; if (u != MY_UID || ( !"KEEP_SCREEN_ON_FLAG".equals(tag) && !"KeyInputQueue".equals(tag))) { @@ -631,21 +632,23 @@ class PowerManagerService extends IPowerManager.Stub public void acquireWakeLock(int flags, IBinder lock, String tag) { int uid = Binder.getCallingUid(); + int pid = Binder.getCallingPid(); if (uid != Process.myUid()) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); } long ident = Binder.clearCallingIdentity(); try { synchronized (mLocks) { - acquireWakeLockLocked(flags, lock, uid, tag); + acquireWakeLockLocked(flags, lock, uid, pid, tag); } } finally { Binder.restoreCallingIdentity(ident); } } - public void acquireWakeLockLocked(int flags, IBinder lock, int uid, String tag) { + public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag) { int acquireUid = -1; + int acquirePid = -1; String acquireName = null; int acquireType = -1; @@ -657,7 +660,7 @@ class PowerManagerService extends IPowerManager.Stub WakeLock wl; boolean newlock; if (index < 0) { - wl = new WakeLock(flags, lock, tag, uid); + wl = new WakeLock(flags, lock, tag, uid, pid); switch (wl.flags & LOCK_MASK) { case PowerManager.FULL_WAKE_LOCK: @@ -730,13 +733,14 @@ class PowerManagerService extends IPowerManager.Stub } if (newlock) { acquireUid = wl.uid; + acquirePid = wl.pid; acquireName = wl.tag; acquireType = wl.monitorType; } if (acquireType >= 0) { try { - mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType); + mBatteryStats.noteStartWakelock(acquireUid, acquirePid, acquireName, acquireType); } catch (RemoteException e) { // Ignore } @@ -756,6 +760,7 @@ class PowerManagerService extends IPowerManager.Stub private void releaseWakeLockLocked(IBinder lock, int flags, boolean death) { int releaseUid; + int releasePid; String releaseName; int releaseType; @@ -800,13 +805,14 @@ class PowerManagerService extends IPowerManager.Stub // Unlink the lock from the binder. wl.binder.unlinkToDeath(wl, 0); releaseUid = wl.uid; + releasePid = wl.pid; releaseName = wl.tag; releaseType = wl.monitorType; if (releaseType >= 0) { long origId = Binder.clearCallingIdentity(); try { - mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType); + mBatteryStats.noteStopWakelock(releaseUid, releasePid, releaseName, releaseType); } catch (RemoteException e) { // Ignore } finally { diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 59deef3..e259887 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -8081,12 +8081,12 @@ public class WindowManagerService extends IWindowManager.Stub if (oldHold != newHold) { try { if (oldHold != null) { - mBatteryStats.noteStopWakelock(oldHold.mUid, + mBatteryStats.noteStopWakelock(oldHold.mUid, -1, "window", BatteryStats.WAKE_TYPE_WINDOW); } if (newHold != null) { - mBatteryStats.noteStartWakelock(newHold.mUid, + mBatteryStats.noteStartWakelock(newHold.mUid, -1, "window", BatteryStats.WAKE_TYPE_WINDOW); } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index dff6a8a..e5d1025 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -199,6 +199,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // The minimum amount of time between successive GC requests for a process. static final int GC_MIN_INTERVAL = 60*1000; + // The rate at which we check for apps using excessive wake locks -- 15 mins. + static final int WAKE_LOCK_CHECK_DELAY = 15*60*1000; + // How long we allow a receiver to run before giving up on it. static final int BROADCAST_TIMEOUT = 10*1000; @@ -770,6 +773,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen boolean mDidAppSwitch; /** + * Last time (in realtime) at which we checked for wake lock usage. + */ + long mLastWakeLockCheckTime; + + /** * Set while we are wanting to sleep, to prevent any * activities from being started/resumed. */ @@ -914,6 +922,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen static final int POST_HEAVY_NOTIFICATION_MSG = 24; static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25; static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26; + static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27; AlertDialog mUidAlert; @@ -1173,6 +1182,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } catch (RemoteException e) { } } break; + case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: { + synchronized (ActivityManagerService.this) { + checkExcessiveWakeLocksLocked(true); + mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); + if (mSleeping) { + Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); + mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); + } + } + } break; } } }; @@ -2555,6 +2574,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mProcDeaths[0]++; + BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); + synchronized (stats) { + stats.noteProcessDiedLocked(app.info.uid, pid); + } + // Clean up already done if the process has been re-started. if (app.pid == pid && app.thread != null && app.thread.asBinder() == thread.asBinder()) { @@ -3570,6 +3594,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { + // Start looking for apps that are abusing wake locks. + Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); + mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); // Tell anyone interested that we are done booting! SystemProperties.set("sys.boot_completed", "1"); broadcastIntentLocked(null, null, @@ -5375,6 +5402,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } else { Slog.w(TAG, "goingToSleep with no resumed activity!"); } + + // Initialize the wake times of all processes. + checkExcessiveWakeLocksLocked(false); + mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); + Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); + mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); } } @@ -5424,6 +5457,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mWindowManager.setEventDispatching(true); mSleeping = false; mMainStack.resumeTopActivityLocked(null); + mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); } } @@ -11259,6 +11293,52 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + final void checkExcessiveWakeLocksLocked(boolean doKills) { + BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); + if (mLastWakeLockCheckTime == 0) { + doKills = false; + } + if (stats.isScreenOn()) { + doKills = false; + } + final long curRealtime = SystemClock.elapsedRealtime(); + final long timeSince = curRealtime - mLastWakeLockCheckTime; + mLastWakeLockCheckTime = curRealtime; + if (timeSince < 5*60*1000) { + doKills = false; + } + int i = mLruProcesses.size(); + while (i > 0) { + i--; + ProcessRecord app = mLruProcesses.get(i); + if (app.curAdj >= HIDDEN_APP_MIN_ADJ) { + long wtime; + synchronized (stats) { + wtime = stats.getProcessWakeTime(app.info.uid, + app.pid, curRealtime); + } + long timeUsed = wtime - app.lastWakeTime; + Slog.i(TAG, "Wake for " + app + ": over " + + timeSince + " used " + timeUsed + + " (" + ((timeUsed*100)/timeSince) + "%)"); + // If a process has held a wake lock for more + // than 50% of the time during this period, + // that sounds pad. Kill! + if (doKills && timeSince > 0 + && ((timeUsed*100)/timeSince) >= 50) { + Slog.i(TAG, "Excessive wake lock in " + app.processName + + " (pid " + app.pid + "): held " + timeUsed + + " during " + timeSince); + EventLog.writeEvent(EventLogTags.AM_KILL, app.pid, + app.processName, app.setAdj, "excessive wake lock"); + Process.killProcessQuiet(app.pid); + } else { + app.lastWakeTime = wtime; + } + } + } + } + private final boolean updateOomAdjLocked( ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) { app.hiddenAdj = hiddenAdj; @@ -11281,6 +11361,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Likewise do a gc when an app is moving in to the // background (such as a service stopping). scheduleAppGcLocked(app); + // And note its current wake lock time. + BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); + synchronized (stats) { + app.lastWakeTime = stats.getProcessWakeTime(app.info.uid, + app.pid, SystemClock.elapsedRealtime()); + } } app.setRawAdj = app.curRawAdj; } diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java index 37da6f7..7314e04 100644 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ b/services/java/com/android/server/am/BatteryStatsService.java @@ -93,31 +93,31 @@ public final class BatteryStatsService extends IBatteryStats.Stub { return data; } - public void noteStartWakelock(int uid, String name, int type) { + public void noteStartWakelock(int uid, int pid, String name, int type) { enforceCallingPermission(); synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStartWakeLocked(name, type); + mStats.noteStartWakeLocked(uid, pid, name, type); } } - public void noteStopWakelock(int uid, String name, int type) { + public void noteStopWakelock(int uid, int pid, String name, int type) { enforceCallingPermission(); synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStopWakeLocked(name, type); + mStats.noteStopWakeLocked(uid, pid, name, type); } } public void noteStartSensor(int uid, int sensor) { enforceCallingPermission(); synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStartSensor(sensor); + mStats.noteStartSensorLocked(uid, sensor); } } public void noteStopSensor(int uid, int sensor) { enforceCallingPermission(); synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStopSensor(sensor); + mStats.noteStopSensorLocked(uid, sensor); } } diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 18b1acb..73e489f 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -74,6 +74,7 @@ class ProcessRecord { Bundle instrumentationArguments;// as given to us ComponentName instrumentationResultClass;// copy of instrumentationClass BroadcastRecord curReceiver;// receiver currently running in the app + long lastWakeTime; // How long proc held wake lock at last check long lastRequestedGc; // When we last asked the app to do a gc long lastLowMemory; // When we last told the app that memory is low boolean reportLowMemory; // Set to true when waiting to report low mem @@ -158,7 +159,7 @@ class ProcessRecord { pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting="); pw.print(starting); pw.print(" lastPss="); pw.println(lastPss); pw.print(prefix); pw.print("lastActivityTime="); pw.print(lastActivityTime); - pw.print(" lruWeight="); pw.println(lruWeight); + pw.print(" lruWeight="); pw.print(lruWeight); pw.print(" hidden="); pw.print(hidden); pw.print(" empty="); pw.println(empty); pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj); @@ -177,6 +178,10 @@ class ProcessRecord { pw.print(" persistentActivities="); pw.println(persistentActivities); pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq); pw.print(" lruSeq="); pw.println(lruSeq); + pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime); + pw.print(" lastRequestedGc="); pw.print(lastRequestedGc); + pw.print(" lastLowMemory="); pw.print(lastLowMemory); + pw.print(" reportLowMemory="); pw.println(reportLowMemory); if (killedBackground) { pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground); } diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index 75365ad..35f1875 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -149,7 +149,9 @@ class ServiceRecord extends Binder { pw.print(" foregroundId="); pw.print(foregroundId); pw.print(" foregroundNoti="); pw.println(foregroundNoti); } - pw.print(prefix); pw.print("lastActivity="); pw.print(lastActivity-now); + pw.print(prefix); pw.print("createTime="); + pw.print(createTime-SystemClock.elapsedRealtime()); + pw.print(" lastActivity="); pw.print(lastActivity-now); pw.print(" executingStart="); pw.print(executingStart-now); pw.print(" restartTime="); pw.println(restartTime); if (startRequested || lastStartId != 0) { @@ -213,7 +215,8 @@ class ServiceRecord extends Binder { dataDir = sInfo.applicationInfo.dataDir; exported = sInfo.exported; this.restarter = restarter; - createTime = lastActivity = SystemClock.uptimeMillis(); + createTime = SystemClock.elapsedRealtime(); + lastActivity = SystemClock.uptimeMillis(); } public AppBindRecord retrieveAppBindingLocked(Intent intent, |