diff options
6 files changed, 138 insertions, 92 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 3172077..4f0d2d5 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -561,6 +561,11 @@ public final class ActivityManagerService extends ActivityManagerNative BroadcastRecord mPendingBroadcast = null; /** + * The receiver index that is pending, to restart the broadcast if needed. + */ + int mPendingBroadcastRecvIndex; + + /** * Keeps track of all IIntentReceivers that have been registered for * broadcasts. Hash keys are the receiver IBinder, hash value is * a ReceiverList. @@ -747,6 +752,7 @@ public final class ActivityManagerService extends ActivityManagerNative ComponentName mTopComponent; String mTopAction; String mTopData; + boolean mProcessesReady = false; boolean mSystemReady = false; boolean mBooting = false; boolean mWaitingUpdate = false; @@ -964,7 +970,11 @@ public final class ActivityManagerService extends ActivityManagerNative return; } - broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"), + Intent intent = new Intent("android.intent.action.ANR"); + if (!mProcessesReady) { + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } + broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, false, false, MY_PID, Process.SYSTEM_UID); @@ -1051,7 +1061,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Only process broadcast timeouts if the system is ready. That way // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended // to do heavy lifting for system up - if (mSystemReady) { + if (mProcessesReady) { broadcastTimeout(); } } break; @@ -1717,10 +1727,12 @@ public final class ActivityManagerService extends ActivityManagerNative if (!knownToBeDead || app.thread == null) { // We already have the app running, or are waiting for it to // come up (we have a pid but not yet its thread), so keep it. + if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app); return app; } else { // An application record is attached to a previous process, // clean it up now. + if (DEBUG_PROCESSES) Slog.v(TAG, "App died: " + app); handleAppDiedLocked(app, true); } } @@ -1732,6 +1744,8 @@ public final class ActivityManagerService extends ActivityManagerNative // If we are in the background, then check to see if this process // is bad. If so, we will just silently fail. if (mBadProcesses.get(info.processName, info.uid) != null) { + if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid + + "/" + info.processName); return null; } } else { @@ -1739,6 +1753,8 @@ public final class ActivityManagerService extends ActivityManagerNative // crash count so that we won't make it bad until they see at // least one crash dialog again, and make the process good again // if it had been bad. + if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid + + "/" + info.processName); mProcessCrashTimes.remove(info.processName, info.uid); if (mBadProcesses.get(info.processName, info.uid) != null) { EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid, @@ -1760,12 +1776,13 @@ public final class ActivityManagerService extends ActivityManagerNative // If the system is not ready yet, then hold off on starting this // process until it is. - if (!mSystemReady + if (!mProcessesReady && !isAllowedWhileBooting(info) && !allowWhileBooting) { if (!mProcessesOnHold.contains(app)) { mProcessesOnHold.add(app); } + if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app); return app; } @@ -1787,6 +1804,8 @@ public final class ActivityManagerService extends ActivityManagerNative app.pid = 0; } + if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + "startProcessLocked removing on hold: " + app); mProcessesOnHold.remove(app); updateCpuStats(); @@ -3040,11 +3059,8 @@ public final class ActivityManagerService extends ActivityManagerNative Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED, Uri.fromParts("package", packageName, null)); intent.putExtra(Intent.EXTRA_UID, pkgUid); - synchronized (this) { - broadcastIntentLocked(null, null, intent, - null, null, 0, null, null, null, - false, false, MY_PID, Process.SYSTEM_UID); - } + broadcastIntentInPackage("android", Process.SYSTEM_UID, intent, + null, null, 0, null, null, null, false, false); } catch (RemoteException e) { } } finally { @@ -3148,6 +3164,7 @@ public final class ActivityManagerService extends ActivityManagerNative public void closeSystemDialogs(String reason) { Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); if (reason != null) { intent.putExtra("reason", reason); } @@ -3225,6 +3242,9 @@ public final class ActivityManagerService extends ActivityManagerNative forceStopPackageLocked(packageName, uid, false, false, true); Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, Uri.fromParts("package", packageName, null)); + if (!mProcessesReady) { + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } intent.putExtra(Intent.EXTRA_UID, uid); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, @@ -3427,6 +3447,8 @@ public final class ActivityManagerService extends ActivityManagerNative } if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) { Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping"); + mPendingBroadcast.state = BroadcastRecord.IDLE; + mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; scheduleBroadcastsLocked(); } @@ -3502,7 +3524,7 @@ public final class ActivityManagerService extends ActivityManagerNative mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); - boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info); + boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); List providers = normalMode ? generateApplicationProvidersLocked(app) : null; if (!normalMode) { @@ -3561,6 +3583,8 @@ public final class ActivityManagerService extends ActivityManagerNative // Remove this record from the list of starting applications. mPersistentStartingProcesses.remove(app); + if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + "Attach application locked removing on hold: " + app); mProcessesOnHold.remove(app); boolean badApp = false; @@ -3702,7 +3726,9 @@ public final class ActivityManagerService extends ActivityManagerNative ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mProcessesOnHold); for (int ip=0; ip<NP; ip++) { - this.startProcessLocked(procs.get(ip), "on-hold", null); + if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: " + + procs.get(ip)); + startProcessLocked(procs.get(ip), "on-hold", null); } } @@ -5253,7 +5279,7 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException(msg); } - if (!mSystemReady && !mDidUpdate && !mWaitingUpdate + if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate && !cpi.processName.equals("system")) { // If this content provider does not run in the system // process, and the system is not yet ready to run other @@ -6040,6 +6066,11 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Removing system update proc: " + proc); removeProcessLocked(proc, true); } + + // Now that we have cleaned up any update processes, we + // are ready to start launching real processes and know that + // we won't trample on them any more. + mProcessesReady = true; } } @@ -7283,8 +7314,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (dumpAll) { pw.println(" Total persistent processes: " + numPers); pw.println(" mStartRunning=" + mStartRunning - + " mSystemReady=" + mSystemReady - + " mBooting=" + mBooting + + " mProcessesReady=" + mProcessesReady + + " mSystemReady=" + mSystemReady); + pw.println(" mBooting=" + mBooting + " mBooted=" + mBooted + " mFactoryTest=" + mFactoryTest); pw.println(" mGoingToSleep=" + mMainStack.mGoingToSleep); @@ -8098,6 +8130,8 @@ public final class ActivityManagerService extends ActivityManagerNative restart = true; } } + if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + "Clean-up removing on hold: " + app); mProcessesOnHold.remove(app); if (app == mHomeProcess) { @@ -10118,7 +10152,7 @@ public final class ActivityManagerService extends ActivityManagerNative } boolean replaced = false; if (replacePending) { - for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) { + for (int i=mOrderedBroadcasts.size()-1; i>0; i--) { if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) { if (DEBUG_BROADCAST) Slog.v(TAG, "***** DROPPING ORDERED: " + intent); @@ -10137,35 +10171,41 @@ public final class ActivityManagerService extends ActivityManagerNative return BROADCAST_SUCCESS; } - public final int broadcastIntent(IApplicationThread caller, - Intent intent, String resolvedType, IIntentReceiver resultTo, - int resultCode, String resultData, Bundle map, - String requiredPermission, boolean serialized, boolean sticky) { + final Intent verifyBroadcastLocked(Intent intent) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } - synchronized(this) { - int flags = intent.getFlags(); - - if (!mSystemReady) { - // if the caller really truly claims to know what they're doing, go - // ahead and allow the broadcast without launching any receivers - if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { - intent = new Intent(intent); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){ - Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent - + " before boot completion"); - throw new IllegalStateException("Cannot broadcast before boot completed"); - } - } - - if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { - throw new IllegalArgumentException( - "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + int flags = intent.getFlags(); + + if (!mProcessesReady) { + // if the caller really truly claims to know what they're doing, go + // ahead and allow the broadcast without launching any receivers + if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { + intent = new Intent(intent); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { + Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent + + " before boot completion"); + throw new IllegalStateException("Cannot broadcast before boot completed"); } + } + + if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { + throw new IllegalArgumentException( + "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + } + + return intent; + } + + public final int broadcastIntent(IApplicationThread caller, + Intent intent, String resolvedType, IIntentReceiver resultTo, + int resultCode, String resultData, Bundle map, + String requiredPermission, boolean serialized, boolean sticky) { + synchronized(this) { + intent = verifyBroadcastLocked(intent); final ProcessRecord callerApp = getRecordForAppLocked(caller); final int callingPid = Binder.getCallingPid(); @@ -10186,6 +10226,8 @@ public final class ActivityManagerService extends ActivityManagerNative int resultCode, String resultData, Bundle map, String requiredPermission, boolean serialized, boolean sticky) { synchronized(this) { + intent = verifyBroadcastLocked(intent); + final long origId = Binder.clearCallingIdentity(); int res = broadcastIntentLocked(null, packageName, intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, @@ -10399,6 +10441,8 @@ public final class ActivityManagerService extends ActivityManagerNative private final void processCurBroadcastLocked(BroadcastRecord r, ProcessRecord app) throws RemoteException { + if (DEBUG_BROADCAST) Slog.v(TAG, + "Process cur broadcast " + r + " for app " + app); if (app.thread == null) { throw new RemoteException(); } @@ -10418,9 +10462,13 @@ public final class ActivityManagerService extends ActivityManagerNative ensurePackageDexOpt(r.intent.getComponent().getPackageName()); app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver, r.resultCode, r.resultData, r.resultExtras, r.ordered); + if (DEBUG_BROADCAST) Slog.v(TAG, + "Process cur broadcast " + r + " DELIVERED for app " + app); started = true; } finally { if (!started) { + if (DEBUG_BROADCAST) Slog.v(TAG, + "Process cur broadcast " + r + ": NOT STARTED!"); r.receiver = null; r.curApp = null; app.curReceiver = null; @@ -10585,6 +10633,8 @@ public final class ActivityManagerService extends ActivityManagerNative } else { Slog.w(TAG, "pending app " + mPendingBroadcast.curApp + " died before responding to broadcast"); + mPendingBroadcast.state = BroadcastRecord.IDLE; + mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; } } @@ -10615,7 +10665,7 @@ public final class ActivityManagerService extends ActivityManagerNative // one time heavy lifting after system upgrades and can take // significant amounts of time. int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; - if (mSystemReady && r.dispatchTime > 0) { + if (mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) { @@ -10686,7 +10736,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast " + r); if (DEBUG_BROADCAST) Slog.v(TAG, - "Submitting BROADCAST_TIMEOUT_MSG for " + "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " + (r.receiverTime + BROADCAST_TIMEOUT)); Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG); mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT); @@ -10754,10 +10804,15 @@ public final class ActivityManagerService extends ActivityManagerNative } if (r.curApp != null && r.curApp.crashing) { // If the target process is crashing, just skip it. + if (DEBUG_BROADCAST) Slog.v(TAG, + "Skipping deliver ordered " + r + " to " + r.curApp + + ": process crashing"); skip = true; } if (skip) { + if (DEBUG_BROADCAST) Slog.v(TAG, + "Skipping delivery of ordered " + r + " for whatever reason"); r.receiver = null; r.curFilter = null; r.state = BroadcastRecord.IDLE; @@ -10789,6 +10844,8 @@ public final class ActivityManagerService extends ActivityManagerNative } // Not running -- get it started, to be executed when the app comes up. + if (DEBUG_BROADCAST) Slog.v(TAG, + "Need to start app " + targetProcess + " for broadcast " + r); if ((r.curApp=startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, @@ -10810,6 +10867,7 @@ public final class ActivityManagerService extends ActivityManagerNative } mPendingBroadcast = r; + mPendingBroadcastRecvIndex = recIdx; } } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 4fc8020..a4497d6 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -1104,26 +1104,30 @@ public class ActivityStack { // 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. - if (mLastStartedActivity != null && !mLastStartedActivity.finishing) { - long now = SystemClock.uptimeMillis(); - final boolean inTime = mLastStartedActivity.startTime != 0 - && (mLastStartedActivity.startTime + START_WARN_TIME) >= now; - final int lastUid = mLastStartedActivity.info.applicationInfo.uid; - final int nextUid = next.info.applicationInfo.uid; - if (inTime && lastUid != nextUid - && lastUid != next.launchedFromUid - && mService.checkPermission( - android.Manifest.permission.STOP_APP_SWITCHES, - -1, next.launchedFromUid) - != PackageManager.PERMISSION_GRANTED) { - mService.showLaunchWarningLocked(mLastStartedActivity, next); + // XXX "App Redirected" dialog is getting too many false positives + // at this point, so turn off for now. + if (false) { + if (mLastStartedActivity != null && !mLastStartedActivity.finishing) { + long now = SystemClock.uptimeMillis(); + final boolean inTime = mLastStartedActivity.startTime != 0 + && (mLastStartedActivity.startTime + START_WARN_TIME) >= now; + final int lastUid = mLastStartedActivity.info.applicationInfo.uid; + final int nextUid = next.info.applicationInfo.uid; + if (inTime && lastUid != nextUid + && lastUid != next.launchedFromUid + && mService.checkPermission( + android.Manifest.permission.STOP_APP_SWITCHES, + -1, next.launchedFromUid) + != PackageManager.PERMISSION_GRANTED) { + mService.showLaunchWarningLocked(mLastStartedActivity, next); + } else { + next.startTime = now; + mLastStartedActivity = next; + } } else { - next.startTime = now; + next.startTime = SystemClock.uptimeMillis(); mLastStartedActivity = next; } - } else { - next.startTime = SystemClock.uptimeMillis(); - mLastStartedActivity = next; } // We need to start pausing the current activity so the top one diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java index 9f86378..23cb42a 100644 --- a/telephony/java/com/android/internal/telephony/CallManager.java +++ b/telephony/java/com/android/internal/telephony/CallManager.java @@ -238,9 +238,7 @@ public final class CallManager { Phone.State s = Phone.State.IDLE; for (Phone phone : mPhones) { - if (phone.getState() == Phone.State.ANSWERING) { - return Phone.State.ANSWERING; - } else if (phone.getState() == Phone.State.RINGING) { + if (phone.getState() == Phone.State.RINGING) { s = Phone.State.RINGING; } else if (phone.getState() == Phone.State.OFFHOOK) { if (s == Phone.State.IDLE) s = Phone.State.OFFHOOK; @@ -357,20 +355,6 @@ public final class CallManager { return getFirstActiveRingingCall().getPhone(); } - /** - * @return the first answering call - */ - public Call getFirstAnsweringCall() { - for (Phone phone : mPhones) { - if (phone.getState() == Phone.State.ANSWERING) { - return phone.getForegroundCall(); - } - } - return null; - } - - - public void setAudioMode() { Context context = getContext(); if (context == null) return; @@ -1359,7 +1343,7 @@ public final class CallManager { */ public Call getFirstActiveBgCall() { for (Call call : mBackgroundCalls) { - if (!call.isIdle()) { + if (call.getState() != Call.State.IDLE) { return call; } } diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 7464cc7..9afade3 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -55,12 +55,10 @@ public interface Phone { * <li>OFFHOOK = The phone is off hook. At least one call * exists that is dialing, active or holding and no calls are * ringing or waiting.</li> - * <li>ANSWERING = The incoming call is picked up but the - * call is not established yet.</li> * </ul> */ enum State { - IDLE, RINGING, OFFHOOK, ANSWERING; + IDLE, RINGING, OFFHOOK; }; /** diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index 0a87ddb..35aa3b3 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -143,23 +143,15 @@ public class SipPhone extends SipPhoneBase { // in case the active/holding call disappeared and this // is no longer call waiting - if (ringingCall.getState() == Call.State.INCOMING) { + if ((ringingCall.getState() == Call.State.INCOMING) || + (ringingCall.getState() == Call.State.WAITING)) { Log.v(LOG_TAG, "acceptCall"); // Always unmute when answering a new call setMute(false); - // make ringingCall foreground - foregroundCall.switchWith(ringingCall); - foregroundCall.acceptCall(); - } else if (ringingCall.getState() == Call.State.WAITING) { - setMute(false); - switchHoldingAndActive(); - // make ringingCall foreground - foregroundCall.switchWith(ringingCall); - foregroundCall.acceptCall(); + ringingCall.acceptCall(); } else { throw new CallStateException("phone not ringing"); } - updatePhoneState(); } } @@ -482,8 +474,8 @@ public class SipPhone extends SipPhoneBase { } void acceptCall() throws CallStateException { - if (this != foregroundCall) { - throw new CallStateException("acceptCall() in a non-fg call"); + if (this != ringingCall) { + throw new CallStateException("acceptCall() in a non-ringing call"); } if (connections.size() != 1) { throw new CallStateException("acceptCall() in a conf call"); @@ -646,6 +638,18 @@ public class SipPhone extends SipPhoneBase { if (newState == Call.State.INCOMING) { setState(mOwner.getState()); // INCOMING or WAITING } else { + if (mOwner == ringingCall) { + if (ringingCall.getState() == Call.State.WAITING) { + try { + switchHoldingAndActive(); + } catch (CallStateException e) { + // disconnect the call. + onCallEnded(DisconnectCause.LOCAL); + return; + } + } + foregroundCall.switchWith(ringingCall); + } if (newState == Call.State.ACTIVE) call.startAudio(); setState(newState); } diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java index 2efbd17..9098e6f 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java @@ -538,8 +538,6 @@ abstract class SipPhoneBase extends PhoneBase { if (getRingingCall().isRinging()) { state = State.RINGING; - } else if (getForegroundCall().isRinging()) { - state = State.ANSWERING; } else if (getForegroundCall().isIdle() && getBackgroundCall().isIdle()) { state = State.IDLE; |