diff options
Diffstat (limited to 'services/java/com/android/server')
6 files changed, 182 insertions, 95 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a372fb8..eab60a7 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1394,9 +1394,7 @@ private NetworkStateTracker makeWimaxStateTracker() { private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { @Override public void onUidRulesChanged(int uid, int uidRules) { - // only someone like NPMS should only be calling us - mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); - + // caller is NPMS, since we only register with them if (LOGD_RULES) { log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")"); } @@ -1415,9 +1413,7 @@ private NetworkStateTracker makeWimaxStateTracker() { @Override public void onMeteredIfacesChanged(String[] meteredIfaces) { - // only someone like NPMS should only be calling us - mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); - + // caller is NPMS, since we only register with them if (LOGD_RULES) { log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")"); } @@ -1429,6 +1425,27 @@ private NetworkStateTracker makeWimaxStateTracker() { } } } + + @Override + public void onRestrictBackgroundChanged(boolean restrictBackground) { + // caller is NPMS, since we only register with them + if (LOGD_RULES) { + log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); + } + + // kick off connectivity change broadcast for active network, since + // global background policy change is radical. + final int networkType = mActiveDefaultNetwork; + if (isNetworkTypeValid(networkType)) { + final NetworkStateTracker tracker = mNetTrackers[networkType]; + if (tracker != null) { + final NetworkInfo info = tracker.getNetworkInfo(); + if (info != null && info.isConnected()) { + sendConnectedBroadcast(info); + } + } + } + } }; /** diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index e6a1e68..5c53902 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -138,6 +138,7 @@ import java.io.StringWriter; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -3520,13 +3521,7 @@ public final class ActivityManagerService extends ActivityManagerNative } // Just in case... - if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) { - if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity); - mMainStack.mPausingActivity = null; - } - if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) { - mMainStack.mLastPausedActivity = null; - } + mMainStack.appDiedLocked(app); // Remove this application's activities from active lists. mMainStack.removeHistoryRecordsForAppLocked(app); @@ -7231,7 +7226,7 @@ public final class ActivityManagerService extends ActivityManagerNative mMainStack.stopIfSleepingLocked(); final long endTime = System.currentTimeMillis() + timeout; while (mMainStack.mResumedActivity != null - || mMainStack.mPausingActivity != null) { + || mMainStack.mPausingActivities.size() > 0) { long delay = endTime - System.currentTimeMillis(); if (delay <= 0) { Slog.w(TAG, "Activity manager shutdown timed out"); @@ -9025,8 +9020,13 @@ public final class ActivityManagerService extends ActivityManagerNative } pw.println(" "); - if (mMainStack.mPausingActivity != null) { - pw.println(" mPausingActivity: " + mMainStack.mPausingActivity); + if (mMainStack.mPausingActivities.size() > 0) { + pw.println(" mPausingActivities: " + Arrays.toString( + mMainStack.mPausingActivities.toArray())); + } + if (mMainStack.mInputPausedActivities.size() > 0) { + pw.println(" mInputPausedActivities: " + Arrays.toString( + mMainStack.mInputPausedActivities.toArray())); } pw.println(" mResumedActivity: " + mMainStack.mResumedActivity); pw.println(" mFocusedActivity: " + mFocusedActivity); @@ -14759,7 +14759,13 @@ public final class ActivityManagerService extends ActivityManagerNative private final ActivityRecord resumedAppLocked() { ActivityRecord resumedActivity = mMainStack.mResumedActivity; if (resumedActivity == null || resumedActivity.app == null) { - resumedActivity = mMainStack.mPausingActivity; + for (int i=mMainStack.mPausingActivities.size()-1; i>=0; i--) { + ActivityRecord r = mMainStack.mPausingActivities.get(i); + if (r.app != null) { + resumedActivity = r; + break; + } + } if (resumedActivity == null || resumedActivity.app == null) { resumedActivity = mMainStack.topRunningActivityLocked(null); } diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index cdab6c6..977ee84 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -602,6 +602,7 @@ final class ActivityRecord { public void windowsDrawn() { synchronized(service) { + stack.reportActivityDrawnLocked(this); if (launchTime != 0) { final long curTime = SystemClock.uptimeMillis(); final long thisTime = curTime - launchTime; @@ -690,7 +691,9 @@ final class ActivityRecord { // Hmmm, who might we be waiting for? r = stack.mResumedActivity; if (r == null) { - r = stack.mPausingActivity; + if (stack.mPausingActivities.size() > 0) { + r = stack.mPausingActivities.get(stack.mPausingActivities.size()-1); + } } // Both of those null? Fall back to 'this' again if (r == null) { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index c3ae6a1..0d21760 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -227,7 +227,13 @@ final class ActivityStack { * When we are in the process of pausing an activity, before starting the * next one, this variable holds the activity that is currently being paused. */ - ActivityRecord mPausingActivity = null; + final ArrayList<ActivityRecord> mPausingActivities = new ArrayList<ActivityRecord>(); + + /** + * These activities currently have their input paused, as they want for + * the next top activity to have its windows visible. + */ + final ArrayList<ActivityRecord> mInputPausedActivities = new ArrayList<ActivityRecord>(); /** * This is the last activity that we put into the paused state. This is @@ -807,9 +813,9 @@ final class ActivityStack { startPausingLocked(false, true); return; } - if (mPausingActivity != null) { + if (mPausingActivities.size() > 0) { // Still waiting for something to pause; can't sleep yet. - if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity); + if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivities); return; } @@ -872,11 +878,6 @@ final class ActivityStack { } private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) { - if (mPausingActivity != null) { - RuntimeException e = new RuntimeException(); - Slog.e(TAG, "Trying to pause when pause is already pending for " - + mPausingActivity, e); - } ActivityRecord prev = mResumedActivity; if (prev == null) { RuntimeException e = new RuntimeException(); @@ -884,19 +885,25 @@ final class ActivityStack { resumeTopActivityLocked(null); return; } + if (mPausingActivities.contains(prev)) { + RuntimeException e = new RuntimeException(); + Slog.e(TAG, "Trying to pause when pause when already pausing " + prev, e); + } if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev); else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev); mResumedActivity = null; - mPausingActivity = prev; + mPausingActivities.add(prev); mLastPausedActivity = prev; prev.state = ActivityState.PAUSING; prev.task.touchActiveTime(); prev.updateThumbnail(screenshotActivities(prev), null); mService.updateCpuStats(); + ActivityRecord pausing; if (prev.app != null && prev.app.thread != null) { if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev); + pausing = prev; try { EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY, System.identityHashCode(prev), @@ -909,12 +916,14 @@ final class ActivityStack { } catch (Exception e) { // Ignore exception, if process died other code will cleanup. Slog.w(TAG, "Exception thrown during pause", e); - mPausingActivity = null; + mPausingActivities.remove(prev); mLastPausedActivity = null; + pausing = null; } } else { - mPausingActivity = null; + mPausingActivities.remove(prev); mLastPausedActivity = null; + pausing = null; } // If we are not going to sleep, we want to ensure the device is @@ -928,18 +937,28 @@ final class ActivityStack { } } - - if (mPausingActivity != null) { + if (pausing != null) { // Have the window manager pause its key dispatching until the new // activity has started. If we're pausing the activity just because // the screen is being turned off and the UI is sleeping, don't interrupt // key dispatch; the same activity will pick it up again on wakeup. if (!uiSleeping) { - prev.pauseKeyDispatchingLocked(); + pausing.pauseKeyDispatchingLocked(); + mInputPausedActivities.add(prev); } else { if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off"); } + if (pausing.configDestroy) { + // The previous is being paused because the configuration + // is changing, which means it is actually stopping... + // To juggle the fact that we are also starting a new + // instance right now, we need to first completely stop + // the current instance before starting the new one. + if (DEBUG_PAUSE) Slog.v(TAG, "Destroying at pause: " + prev); + destroyActivityLocked(pausing, true, false, "pause-config"); + } + // Schedule a pause timeout in case the app doesn't respond. // We don't give it much time because this directly impacts the // responsiveness seen by the user. @@ -951,7 +970,10 @@ final class ActivityStack { // This activity failed to schedule the // pause, so just treat it as being paused now. if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next."); - resumeTopActivityLocked(null); + } + + if (!mService.isSleeping()) { + resumeTopActivityLocked(pausing); } } @@ -966,16 +988,17 @@ final class ActivityStack { if (index >= 0) { r = mHistory.get(index); mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); - if (mPausingActivity == r) { + if (mPausingActivities.contains(r)) { if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r + (timeout ? " (due to timeout)" : " (pause complete)")); r.state = ActivityState.PAUSED; - completePauseLocked(); + completePauseLocked(r); } else { + ActivityRecord old = mPausingActivities.size() > 0 + ? mPausingActivities.get(0) : null; EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE, System.identityHashCode(r), r.shortComponentName, - mPausingActivity != null - ? mPausingActivity.shortComponentName : "(none)"); + old != null ? old.shortComponentName : "(none)"); } } } @@ -1001,8 +1024,14 @@ final class ActivityStack { ProcessRecord fgApp = null; if (mResumedActivity != null) { fgApp = mResumedActivity.app; - } else if (mPausingActivity != null) { - fgApp = mPausingActivity.app; + } else { + for (int i=mPausingActivities.size()-1; i>=0; i--) { + ActivityRecord pausing = mPausingActivities.get(i); + if (pausing.app == r.app) { + fgApp = pausing.app; + break; + } + } } if (r.app != null && fgApp != null && r.app != fgApp && r.lastVisibleTime > mService.mPreviousProcessVisibleTime @@ -1014,58 +1043,49 @@ final class ActivityStack { } } - private final void completePauseLocked() { - ActivityRecord prev = mPausingActivity; + private final void completePauseLocked(ActivityRecord prev) { if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev); - if (prev != null) { - if (prev.finishing) { - if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev); - prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE); - } else if (prev.app != null) { - if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev); - if (prev.waitingVisible) { - prev.waitingVisible = false; - mWaitingVisibleActivities.remove(prev); - if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v( - TAG, "Complete pause, no longer waiting: " + prev); - } - if (prev.configDestroy) { - // The previous is being paused because the configuration - // is changing, which means it is actually stopping... - // To juggle the fact that we are also starting a new - // instance right now, we need to first completely stop - // the current instance before starting the new one. - if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev); - destroyActivityLocked(prev, true, false, "pause-config"); + if (prev.finishing) { + if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev); + prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE); + } else if (prev.app != null) { + if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev); + if (prev.waitingVisible) { + prev.waitingVisible = false; + mWaitingVisibleActivities.remove(prev); + if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v( + TAG, "Complete pause, no longer waiting: " + prev); + } + if (prev.configDestroy) { + // The previous is being paused because the configuration + // is changing, which means it is actually stopping... + // To juggle the fact that we are also starting a new + // instance right now, we need to first completely stop + // the current instance before starting the new one. + if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev); + destroyActivityLocked(prev, true, false, "pause-config"); + } else { + mStoppingActivities.add(prev); + if (mStoppingActivities.size() > 3) { + // If we already have a few activities waiting to stop, + // then give up on things going idle and start clearing + // them out. + if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle"); + scheduleIdleLocked(); } else { - mStoppingActivities.add(prev); - if (mStoppingActivities.size() > 3) { - // If we already have a few activities waiting to stop, - // then give up on things going idle and start clearing - // them out. - if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle"); - scheduleIdleLocked(); - } else { - checkReadyForSleepLocked(); - } + checkReadyForSleepLocked(); } - } else { - if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev); - prev = null; } - mPausingActivity = null; + } else { + if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev); + prev = null; } + mPausingActivities.remove(prev); - if (!mService.isSleeping()) { - resumeTopActivityLocked(prev); - } else { + if (mService.isSleeping()) { checkReadyForSleepLocked(); } - - if (prev != null) { - prev.resumeKeyDispatchingLocked(); - } if (prev.app != null && prev.cpuTimeAtResume > 0 && mService.mBatteryStatsService.isOnBattery()) { @@ -1122,7 +1142,9 @@ final class ActivityStack { if (mMainStack) { mService.setFocusedActivityLocked(next); } - next.resumeKeyDispatchingLocked(); + if (mInputPausedActivities.remove(next)) { + next.resumeKeyDispatchingLocked(); + } ensureActivitiesVisibleLocked(null, 0); mService.mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); @@ -1352,13 +1374,6 @@ final class ActivityStack { if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next); - // If we are currently pausing an activity, then don't do anything - // until that is done. - if (mPausingActivity != null) { - if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity); - return false; - } - // Okay we are now going to start a switch, to 'next'. We may first // have to pause the current activity, but this is an important point // where we have decided to go to 'next' so keep track of that. @@ -2440,7 +2455,7 @@ final class ActivityStack { err = startActivityUncheckedLocked(r, sourceRecord, grantedUriPermissions, grantedMode, onlyIfNeeded, true); - if (mDismissKeyguardOnNextActivity && mPausingActivity == null) { + if (mDismissKeyguardOnNextActivity && mPausingActivities.size() == 0) { // Someone asked to have the keyguard dismissed on the next // activity start, but we are not actually doing an activity // switch... just dismiss the keyguard now, because we @@ -3111,7 +3126,18 @@ final class ActivityStack { } mService.notifyAll(); } - + + void reportActivityDrawnLocked(ActivityRecord r) { + if (mResumedActivity == r) { + // Once the resumed activity has been drawn, we can stop + // pausing input on all other activities. + for (int i=mInputPausedActivities.size()-1; i>=0; i--) { + mInputPausedActivities.get(i).resumeKeyDispatchingLocked(); + } + mInputPausedActivities.clear(); + } + } + void reportActivityVisibleLocked(ActivityRecord r) { for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) { WaitResult w = mWaitingActivityVisible.get(i); @@ -3170,7 +3196,9 @@ final class ActivityStack { mService.setFocusedActivityLocked(topRunningActivityLocked(null)); } } - r.resumeKeyDispatchingLocked(); + if (mInputPausedActivities.remove(r)) { + r.resumeKeyDispatchingLocked(); + } try { r.stopped = false; if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r @@ -3496,7 +3524,7 @@ final class ActivityStack { // Tell window manager to prepare for this one to be removed. mService.mWindowManager.setAppVisibility(r.appToken, false); - if (mPausingActivity == null) { + if (!mPausingActivities.contains(r)) { if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r); if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false"); startPausingLocked(false, false); @@ -3580,6 +3608,20 @@ final class ActivityStack { return r; } + final void appDiedLocked(ProcessRecord app) { + for (int i=mPausingActivities.size()-1; i>=0; i--) { + ActivityRecord r = mPausingActivities.get(i); + if (r.app == app) { + if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + r); + mPausingActivities.remove(i); + mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); + } + } + if (mLastPausedActivity != null && mLastPausedActivity.app == app) { + mLastPausedActivity = null; + } + } + /** * Perform the common clean-up of an activity record. This is called both * as part of destroyActivityLocked() (when destroying the client-side diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 9772d6a..a890068 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -195,6 +195,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 3; private static final int MSG_PROCESS_DIED = 4; private static final int MSG_LIMIT_REACHED = 5; + private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6; private final Context mContext; private final IActivityManager mActivityManager; @@ -1225,6 +1226,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateNotificationsLocked(); writePolicyLocked(); } + + mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0) + .sendToTarget(); } @Override @@ -1573,6 +1577,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } return true; } + case MSG_RESTRICT_BACKGROUND_CHANGED: { + final boolean restrictBackground = msg.arg1 != 0; + final int length = mListeners.beginBroadcast(); + for (int i = 0; i < length; i++) { + final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); + if (listener != null) { + try { + listener.onRestrictBackgroundChanged(restrictBackground); + } catch (RemoteException e) { + } + } + } + mListeners.finishBroadcast(); + } default: { return false; } diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index e7ba358..240cc1c 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -51,6 +51,7 @@ import java.util.Map; public class NetworkStatsRecorder { private static final String TAG = "NetworkStatsRecorder"; private static final boolean LOGD = true; + private static final boolean LOGV = false; private final FileRotator mRotator; private final NonMonotonicObserver<String> mObserver; @@ -170,7 +171,7 @@ public class NetworkStatsRecorder { mLastSnapshot = snapshot; - if (LOGD && unknownIfaces.size() > 0) { + if (LOGV && unknownIfaces.size() > 0) { Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats"); } } |
