diff options
Diffstat (limited to 'services')
8 files changed, 464 insertions, 160 deletions
diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/java/com/android/server/location/FlpHardwareProvider.java index 60893b8..fab84a8 100644 --- a/services/java/com/android/server/location/FlpHardwareProvider.java +++ b/services/java/com/android/server/location/FlpHardwareProvider.java @@ -26,6 +26,7 @@ import android.location.FusedBatchOptions; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; +import android.location.LocationRequest; import android.content.Context; import android.os.Bundle; @@ -73,10 +74,19 @@ public class FlpHardwareProvider { // register for listening for passive provider data LocationManager manager = (LocationManager) mContext.getSystemService( Context.LOCATION_SERVICE); - manager.requestLocationUpdates( + final long minTime = 0; + final float minDistance = 0; + final boolean oneShot = false; + LocationRequest request = LocationRequest.createFromDeprecatedProvider( LocationManager.PASSIVE_PROVIDER, - 0 /* minTime */, - 0 /* minDistance */, + minTime, + minDistance, + oneShot); + // Don't keep track of this request since it's done on behalf of other clients + // (which are kept track of separately). + request.setHideFromAppOps(true); + manager.requestLocationUpdates( + request, new NetworkLocationListener(), Looper.myLooper()); } diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 6053c61..9c76c19 100644 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -512,8 +512,21 @@ public class GpsLocationProvider implements LocationProviderInterface { public void run() { LocationManager locManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); - locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, - 0, 0, new NetworkLocationListener(), mHandler.getLooper()); + final long minTime = 0; + final float minDistance = 0; + final boolean oneShot = false; + LocationRequest request = LocationRequest.createFromDeprecatedProvider( + LocationManager.PASSIVE_PROVIDER, + minTime, + minDistance, + oneShot); + // Don't keep track of this request since it's done on behalf of other clients + // (which are kept track of separately). + request.setHideFromAppOps(true); + locManager.requestLocationUpdates( + request, + new NetworkLocationListener(), + mHandler.getLooper()); } }); } diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java index b5010f2..976a328 100644 --- a/services/java/com/android/server/power/DisplayPowerController.java +++ b/services/java/com/android/server/power/DisplayPowerController.java @@ -29,7 +29,6 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; -import android.hardware.SystemSensorManager; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -119,7 +118,7 @@ final class DisplayPowerController { // Proximity sensor debounce delay in milliseconds for positive or negative transitions. private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0; - private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500; + private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250; // Trigger proximity if distance is less than 5 cm. private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f; @@ -164,6 +163,10 @@ final class DisplayPowerController { // Notifier for sending asynchronous notifications. private final Notifier mNotifier; + // The display suspend blocker. + // Held while there are pending state change notifications. + private final SuspendBlocker mDisplaySuspendBlocker; + // The display blanker. private final DisplayBlanker mDisplayBlanker; @@ -271,7 +274,7 @@ final class DisplayPowerController { // The raw non-debounced proximity sensor state. private int mPendingProximity = PROXIMITY_UNKNOWN; - private long mPendingProximityDebounceTime; + private long mPendingProximityDebounceTime = -1; // -1 if fully debounced // True if the screen was turned off because of the proximity sensor. // When the screen turns on again, we report user activity to the power manager. @@ -346,10 +349,11 @@ final class DisplayPowerController { public DisplayPowerController(Looper looper, Context context, Notifier notifier, LightsService lights, TwilightService twilight, SensorManager sensorManager, DisplayManagerService displayManager, - DisplayBlanker displayBlanker, + SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker, Callbacks callbacks, Handler callbackHandler) { mHandler = new DisplayControllerHandler(looper); mNotifier = notifier; + mDisplaySuspendBlocker = displaySuspendBlocker; mDisplayBlanker = displayBlanker; mCallbacks = callbacks; mCallbackHandler = callbackHandler; @@ -601,7 +605,7 @@ final class DisplayPowerController { if (!mScreenOffBecauseOfProximity && mProximity == PROXIMITY_POSITIVE) { mScreenOffBecauseOfProximity = true; - sendOnProximityPositive(); + sendOnProximityPositiveWithWakelock(); setScreenOn(false); } } else if (mWaitingForNegativeProximity @@ -616,7 +620,7 @@ final class DisplayPowerController { if (mScreenOffBecauseOfProximity && mProximity != PROXIMITY_POSITIVE) { mScreenOffBecauseOfProximity = false; - sendOnProximityNegative(); + sendOnProximityNegativeWithWakelock(); } } else { mWaitingForNegativeProximity = false; @@ -737,7 +741,7 @@ final class DisplayPowerController { } } } - sendOnStateChanged(); + sendOnStateChangedWithWakelock(); } } @@ -810,49 +814,67 @@ final class DisplayPowerController { private void setProximitySensorEnabled(boolean enable) { if (enable) { if (!mProximitySensorEnabled) { + // Register the listener. + // Proximity sensor state already cleared initially. mProximitySensorEnabled = true; - mPendingProximity = PROXIMITY_UNKNOWN; mSensorManager.registerListener(mProximitySensorListener, mProximitySensor, SensorManager.SENSOR_DELAY_NORMAL, mHandler); } } else { if (mProximitySensorEnabled) { + // Unregister the listener. + // Clear the proximity sensor state for next time. mProximitySensorEnabled = false; mProximity = PROXIMITY_UNKNOWN; + mPendingProximity = PROXIMITY_UNKNOWN; mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); mSensorManager.unregisterListener(mProximitySensorListener); + clearPendingProximityDebounceTime(); // release wake lock (must be last) } } } private void handleProximitySensorEvent(long time, boolean positive) { - if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) { - return; // no change - } - if (mPendingProximity == PROXIMITY_POSITIVE && positive) { - return; // no change - } + if (mProximitySensorEnabled) { + if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) { + return; // no change + } + if (mPendingProximity == PROXIMITY_POSITIVE && positive) { + return; // no change + } - // Only accept a proximity sensor reading if it remains - // stable for the entire debounce delay. - mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); - if (positive) { - mPendingProximity = PROXIMITY_POSITIVE; - mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY; - } else { - mPendingProximity = PROXIMITY_NEGATIVE; - mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY; + // Only accept a proximity sensor reading if it remains + // stable for the entire debounce delay. We hold a wake lock while + // debouncing the sensor. + mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); + if (positive) { + mPendingProximity = PROXIMITY_POSITIVE; + setPendingProximityDebounceTime( + time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock + } else { + mPendingProximity = PROXIMITY_NEGATIVE; + setPendingProximityDebounceTime( + time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock + } + + // Debounce the new sensor reading. + debounceProximitySensor(); } - debounceProximitySensor(); } private void debounceProximitySensor() { - if (mPendingProximity != PROXIMITY_UNKNOWN) { + if (mProximitySensorEnabled + && mPendingProximity != PROXIMITY_UNKNOWN + && mPendingProximityDebounceTime >= 0) { final long now = SystemClock.uptimeMillis(); if (mPendingProximityDebounceTime <= now) { + // Sensor reading accepted. Apply the change then release the wake lock. mProximity = mPendingProximity; - sendUpdatePowerState(); + updatePowerState(); + clearPendingProximityDebounceTime(); // release wake lock (must be last) } else { + // Need to wait a little longer. + // Debounce again later. We continue holding a wake lock while waiting. Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime); @@ -860,6 +882,20 @@ final class DisplayPowerController { } } + private void clearPendingProximityDebounceTime() { + if (mPendingProximityDebounceTime >= 0) { + mPendingProximityDebounceTime = -1; + mDisplaySuspendBlocker.release(); // release wake lock + } + } + + private void setPendingProximityDebounceTime(long debounceTime) { + if (mPendingProximityDebounceTime < 0) { + mDisplaySuspendBlocker.acquire(); // acquire wake lock + } + mPendingProximityDebounceTime = debounceTime; + } + private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) { if (enable) { if (!mLightSensorEnabled) { @@ -1120,7 +1156,8 @@ final class DisplayPowerController { return x + (y - x) * alpha; } - private void sendOnStateChanged() { + private void sendOnStateChangedWithWakelock() { + mDisplaySuspendBlocker.acquire(); mCallbackHandler.post(mOnStateChangedRunnable); } @@ -1128,10 +1165,12 @@ final class DisplayPowerController { @Override public void run() { mCallbacks.onStateChanged(); + mDisplaySuspendBlocker.release(); } }; - private void sendOnProximityPositive() { + private void sendOnProximityPositiveWithWakelock() { + mDisplaySuspendBlocker.acquire(); mCallbackHandler.post(mOnProximityPositiveRunnable); } @@ -1139,10 +1178,12 @@ final class DisplayPowerController { @Override public void run() { mCallbacks.onProximityPositive(); + mDisplaySuspendBlocker.release(); } }; - private void sendOnProximityNegative() { + private void sendOnProximityNegativeWithWakelock() { + mDisplaySuspendBlocker.acquire(); mCallbackHandler.post(mOnProximityNegativeRunnable); } @@ -1150,6 +1191,7 @@ final class DisplayPowerController { @Override public void run() { mCallbacks.onProximityNegative(); + mDisplaySuspendBlocker.release(); } }; diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index 2167f67..fe09a33 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -63,7 +63,6 @@ import android.util.TimeUtils; import android.view.WindowManagerPolicy; import java.io.FileDescriptor; -import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; @@ -287,6 +286,9 @@ public final class PowerManagerService extends IPowerManager.Stub // True if the device should wake up when plugged or unplugged. private boolean mWakeUpWhenPluggedOrUnpluggedConfig; + // True if the device should suspend when the screen is off due to proximity. + private boolean mSuspendWhenScreenOffDueToProximityConfig; + // True if dreams are supported on this device. private boolean mDreamsSupportedConfig; @@ -447,7 +449,7 @@ public final class PowerManagerService extends IPowerManager.Stub // own handler thread to ensure timely operation. mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(), mContext, mNotifier, mLightsService, twilight, sensorManager, - mDisplayManagerService, mDisplayBlanker, + mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker, mDisplayPowerControllerCallbacks, mHandler); mWirelessChargerDetector = new WirelessChargerDetector(sensorManager, @@ -514,6 +516,8 @@ public final class PowerManagerService extends IPowerManager.Stub mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean( com.android.internal.R.bool.config_unplugTurnsOnScreen); + mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean( + com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity); mDreamsSupportedConfig = resources.getBoolean( com.android.internal.R.bool.config_dreamsSupported); mDreamsEnabledByDefaultConfig = resources.getBoolean( @@ -639,6 +643,7 @@ public final class PowerManagerService extends IPowerManager.Stub } } + @SuppressWarnings("deprecation") private static boolean isScreenLock(final WakeLock wakeLock) { switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) { case PowerManager.FULL_WAKE_LOCK: @@ -817,6 +822,7 @@ public final class PowerManagerService extends IPowerManager.Stub } } + @SuppressWarnings("deprecation") private boolean isWakeLockLevelSupportedInternal(int level) { synchronized (mLock) { switch (level) { @@ -1005,6 +1011,7 @@ public final class PowerManagerService extends IPowerManager.Stub } } + @SuppressWarnings("deprecation") private boolean goToSleepNoUpdateLocked(long eventTime, int reason) { if (DEBUG_SPEW) { Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason); @@ -1261,6 +1268,7 @@ public final class PowerManagerService extends IPowerManager.Stub * * This function must have no other side-effects. */ + @SuppressWarnings("deprecation") private void updateWakeLockSummaryLocked(int dirty) { if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) { mWakeLockSummary = 0; @@ -1299,7 +1307,7 @@ public final class PowerManagerService extends IPowerManager.Stub break; case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: if (mWakefulness != WAKEFULNESS_ASLEEP) { - mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_PROXIMITY_SCREEN_OFF; + mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF; } break; } @@ -1458,7 +1466,11 @@ public final class PowerManagerService extends IPowerManager.Stub /** * Returns true if the device is being kept awake by a wake lock, user activity - * or the stay on while powered setting. + * or the stay on while powered setting. We also keep the phone awake when + * the proximity sensor returns a positive result so that the device does not + * lock while in a phone call. This function only controls whether the device + * will go to sleep or dream which is independent of whether it will be allowed + * to suspend. */ private boolean isBeingKeptAwakeLocked() { return mStayOn @@ -1749,10 +1761,8 @@ public final class PowerManagerService extends IPowerManager.Stub * This function must have no other side-effects. */ private void updateSuspendBlockerLocked() { - final boolean needWakeLockSuspendBlocker = (mWakeLockSummary != 0); - final boolean needDisplaySuspendBlocker = (mUserActivitySummary != 0 - || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF - || !mDisplayReady || !mBootCompleted); + final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0); + final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker(); // First acquire suspend blockers if needed. if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) { @@ -1775,6 +1785,27 @@ public final class PowerManagerService extends IPowerManager.Stub } } + /** + * Return true if we must keep a suspend blocker active on behalf of the display. + * We do so if the screen is on or is in transition between states. + */ + private boolean needDisplaySuspendBlocker() { + if (!mDisplayReady) { + return true; + } + if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) { + // If we asked for the screen to be on but it is off due to the proximity + // sensor then we may suspend but only if the configuration allows it. + // On some hardware it may not be safe to suspend because the proximity + // sensor may not be correctly configured as a wake-up source. + if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive + || !mSuspendWhenScreenOffDueToProximityConfig) { + return true; + } + } + return false; + } + @Override // Binder call public boolean isScreenOn() { final long ident = Binder.clearCallingIdentity(); @@ -2115,7 +2146,7 @@ public final class PowerManagerService extends IPowerManager.Stub * * @param brightness The overridden brightness. * - * @see Settings.System#SCREEN_BRIGHTNESS + * @see android.provider.Settings.System#SCREEN_BRIGHTNESS */ @Override // Binder call public void setTemporaryScreenBrightnessSettingOverride(int brightness) { @@ -2255,7 +2286,16 @@ public final class PowerManagerService extends IPowerManager.Stub pw.println(); pw.println("Settings and Configuration:"); + pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig=" + + mWakeUpWhenPluggedOrUnpluggedConfig); + pw.println(" mSuspendWhenScreenOffDueToProximityConfig=" + + mSuspendWhenScreenOffDueToProximityConfig); pw.println(" mDreamsSupportedConfig=" + mDreamsSupportedConfig); + pw.println(" mDreamsEnabledByDefaultConfig=" + mDreamsEnabledByDefaultConfig); + pw.println(" mDreamsActivatedOnSleepByDefaultConfig=" + + mDreamsActivatedOnSleepByDefaultConfig); + pw.println(" mDreamsActivatedOnDockByDefaultConfig=" + + mDreamsActivatedOnDockByDefaultConfig); pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting); pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting); pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting); diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java index ddff0ae..f15c760 100644 --- a/services/java/com/android/server/print/RemotePrintService.java +++ b/services/java/com/android/server/print/RemotePrintService.java @@ -21,11 +21,9 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Binder; -import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; -import android.os.AsyncTask; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -39,8 +37,6 @@ import android.printservice.IPrintService; import android.printservice.IPrintServiceClient; import android.util.Slog; -import com.android.internal.R; - import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -55,7 +51,7 @@ final class RemotePrintService implements DeathRecipient { private static final String LOG_TAG = "RemotePrintService"; - private static final boolean DEBUG = true && Build.IS_DEBUGGABLE; + private static final boolean DEBUG = false; private final Context mContext; @@ -65,7 +61,7 @@ final class RemotePrintService implements DeathRecipient { private final RemotePrintSpooler mSpooler; - private final UserState mUserState; + private final PrintServiceCallbacks mCallbacks; private final int mUserId; @@ -83,14 +79,24 @@ final class RemotePrintService implements DeathRecipient { private boolean mDestroyed; - private boolean mAllPrintJobsHandled; + private boolean mHasActivePrintJobs; private boolean mHasPrinterDiscoverySession; + private List<PrinterId> mDiscoveryPriorityList; + + private List<PrinterId> mTrackedPrinterList; + + public static interface PrintServiceCallbacks { + public void onPrintersAdded(List<PrinterInfo> printers); + public void onPrintersRemoved(List<PrinterId> printerIds); + public void onServiceDied(RemotePrintService service); + } + public RemotePrintService(Context context, ComponentName componentName, int userId, - RemotePrintSpooler spooler, UserState userState) { + RemotePrintSpooler spooler, PrintServiceCallbacks callbacks) { mContext = context; - mUserState = userState; + mCallbacks = callbacks; mComponentName = componentName; mIntent = new Intent().setComponent(mComponentName); mUserId = userId; @@ -99,15 +105,42 @@ final class RemotePrintService implements DeathRecipient { mPrintServiceClient = new RemotePrintServiceClient(this); } + public ComponentName getComponentName() { + return mComponentName; + } + public void destroy() { mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY); } private void handleDestroy() { throwIfDestroyed(); + + // Stop tracking printers. + if (mTrackedPrinterList != null) { + final int trackedPrinterCount = mTrackedPrinterList.size(); + for (int i = 0; i < trackedPrinterCount; i++) { + PrinterId printerId = mTrackedPrinterList.get(i); + if (printerId.getServiceName().equals(mComponentName)) { + handleStopPrinterStateTracking(printerId); + } + } + } + + // Stop printer discovery. + if (mDiscoveryPriorityList != null) { + handleStopPrinterDiscovery(); + } + + // Destroy the discovery session. + if (mHasPrinterDiscoverySession) { + handleDestroyPrinterDiscoverySession(); + } + + // Unbind. ensureUnbound(); - mAllPrintJobsHandled = false; - mHasPrinterDiscoverySession = false; + + // Done mDestroyed = true; } @@ -121,21 +154,9 @@ final class RemotePrintService implements DeathRecipient { } private void handleBinderDied() { - mAllPrintJobsHandled = false; - mHasPrinterDiscoverySession = false; - mPendingCommands.clear(); - ensureUnbound(); - - // Makes sure all active print jobs are failed since the service - // just died. Do this off the main thread since we do to allow - // calls into the spooler on the main thread. - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - failAllActivePrintJobs(); - return null; - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); + mPrintService.asBinder().unlinkToDeath(this, 0); + mPrintService = null; + mCallbacks.onServiceDied(this); } public void dump(PrintWriter pw, String prefix) { @@ -148,32 +169,17 @@ final class RemotePrintService implements DeathRecipient { pw.append(prefix).append(tab).append("bound=") .append(String.valueOf(isBound())).println(); pw.append(prefix).append(tab).append("hasDicoverySession=") - .append(String.valueOf(mHasPrinterDiscoverySession)); - } - - private void failAllActivePrintJobs() { - List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(mComponentName, - PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY); - if (printJobs == null) { - return; - } - final long identity = Binder.clearCallingIdentity(); - try { - final int printJobCount = printJobs.size(); - for (int i = 0; i < printJobCount; i++) { - PrintJobInfo printJob = printJobs.get(i); - mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, - mContext.getString(R.string.reason_unknown)); - } - } finally { - Binder.restoreCallingIdentity(identity); - } + .append(String.valueOf(mHasPrinterDiscoverySession)).println(); + pw.append(prefix).append(tab).append("isDiscoveringPrinters=") + .append(String.valueOf(mDiscoveryPriorityList != null)).println(); + pw.append(prefix).append(tab).append("trackedPrinters=") + .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null"); } private void handleOnAllPrintJobsHandled() { throwIfDestroyed(); - mAllPrintJobsHandled = true; + mHasActivePrintJobs = false; if (isBound()) { if (DEBUG) { @@ -217,7 +223,7 @@ final class RemotePrintService implements DeathRecipient { private void handleOnPrintJobQueued(final PrintJobInfo printJob) { throwIfDestroyed(); - mAllPrintJobsHandled = false; + mHasActivePrintJobs = true; if (!isBound()) { ensureBound(); @@ -296,7 +302,7 @@ final class RemotePrintService implements DeathRecipient { // If the service has no print jobs and no active discovery // session anymore we should disconnect from it. - if (mAllPrintJobsHandled) { + if (!mHasActivePrintJobs) { ensureUnbound(); } } @@ -326,6 +332,11 @@ final class RemotePrintService implements DeathRecipient { } catch (RemoteException re) { Slog.e(LOG_TAG, "Error starting printer dicovery.", re); } + // Take a note that we are doing discovery. + mDiscoveryPriorityList = new ArrayList<PrinterId>(); + if (priorityList != null) { + mDiscoveryPriorityList.addAll(priorityList); + } } } @@ -347,6 +358,8 @@ final class RemotePrintService implements DeathRecipient { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()"); } + // We are not doing discovery anymore. + mDiscoveryPriorityList = null; try { mPrintService.stopPrinterDiscovery(); } catch (RemoteException re) { @@ -406,6 +419,11 @@ final class RemotePrintService implements DeathRecipient { } catch (RemoteException re) { Slog.e(LOG_TAG, "Error requesting start printer tracking.", re); } + // Take a note we are tracking the printer. + if (mTrackedPrinterList == null) { + mTrackedPrinterList = new ArrayList<PrinterId>(); + } + mTrackedPrinterList.add(printerId); } } @@ -428,6 +446,13 @@ final class RemotePrintService implements DeathRecipient { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterTracking()"); } + // We are no longer tracking the printer. + if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) { + return; + } + if (mTrackedPrinterList.isEmpty()) { + mTrackedPrinterList = null; + } try { mPrintService.stopPrinterStateTracking(printerId); } catch (RemoteException re) { @@ -461,6 +486,10 @@ final class RemotePrintService implements DeathRecipient { } mBinding = false; mPendingCommands.clear(); + mHasActivePrintJobs = false; + mHasPrinterDiscoverySession = false; + mDiscoveryPriorityList = null; + mTrackedPrinterList = null; if (isBound()) { try { mPrintService.setClient(null); @@ -500,11 +529,31 @@ final class RemotePrintService implements DeathRecipient { handleBinderDied(); return; } + // If there is a session, then the service died after creating + // a session. Hence, recreate the session. + if (mHasPrinterDiscoverySession) { + handleCreatePrinterDiscoverySession(); + } + // If there is a priority list, then the service died during + // discovery and is restarted. Hence, start discovery. + if (mDiscoveryPriorityList != null) { + handleStartPrinterDiscovery(mDiscoveryPriorityList); + } + // If there is a tracked printer list, then the service died + // during discovery and is restarted. Hence, start tracking. + if (mTrackedPrinterList != null) { + final int trackedPrinterCount = mTrackedPrinterList.size(); + for (int i = 0; i < trackedPrinterCount; i++) { + handleStartPrinterStateTracking(mTrackedPrinterList.get(i)); + } + } + // Finally, do all the pending work. final int pendingCommandCount = mPendingCommands.size(); for (int i = 0; i < pendingCommandCount; i++) { Runnable pendingCommand = mPendingCommands.get(i); pendingCommand.run(); } + mPendingCommands.clear(); } @Override @@ -677,7 +726,7 @@ final class RemotePrintService implements DeathRecipient { throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers); final long identity = Binder.clearCallingIdentity(); try { - service.mUserState.onPrintersAdded(printers); + service.mCallbacks.onPrintersAdded(printers); } finally { Binder.restoreCallingIdentity(identity); } @@ -691,7 +740,7 @@ final class RemotePrintService implements DeathRecipient { throwIfPrinterIdsTampered(service.mComponentName, printerIds); final long identity = Binder.clearCallingIdentity(); try { - service.mUserState.onPrintersRemoved(printerIds); + service.mCallbacks.onPrintersRemoved(printerIds); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java index 28a6186..45469ac 100644 --- a/services/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/java/com/android/server/print/RemotePrintSpooler.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Binder; -import android.os.Build; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -57,7 +56,7 @@ final class RemotePrintSpooler { private static final String LOG_TAG = "RemotePrintSpooler"; - private static final boolean DEBUG = true && Build.IS_DEBUGGABLE; + private static final boolean DEBUG = false; private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000; diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java index 5392975..70fe370 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/java/com/android/server/print/UserState.java @@ -23,7 +23,8 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.os.Build; +import android.os.AsyncTask; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -32,6 +33,7 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.print.IPrinterDiscoveryObserver; import android.print.PrintJobInfo; +import android.print.PrintManager; import android.print.PrinterId; import android.print.PrinterInfo; import android.printservice.PrintServiceInfo; @@ -43,7 +45,9 @@ import android.util.ArraySet; import android.util.Log; import android.util.Slog; +import com.android.internal.R; import com.android.internal.os.SomeArgs; +import com.android.server.print.RemotePrintService.PrintServiceCallbacks; import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks; import java.io.FileDescriptor; @@ -58,11 +62,11 @@ import java.util.Set; /** * Represents the print state for a user. */ -final class UserState implements PrintSpoolerCallbacks { +final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { private static final String LOG_TAG = "UserState"; - private static final boolean DEBUG = true && Build.IS_DEBUGGABLE; + private static final boolean DEBUG = false; private static final int MAX_ITEMS_PER_CALLBACK = 50; @@ -246,6 +250,7 @@ final class UserState implements PrintSpoolerCallbacks { } } + @Override public void onPrintersAdded(List<PrinterInfo> printers) { synchronized (mLock) { throwIfDestroyedLocked(); @@ -257,11 +262,11 @@ final class UserState implements PrintSpoolerCallbacks { if (mPrinterDiscoverySession == null) { return; } - // Request an updated. mPrinterDiscoverySession.onPrintersAddedLocked(printers); } } + @Override public void onPrintersRemoved(List<PrinterId> printerIds) { synchronized (mLock) { throwIfDestroyedLocked(); @@ -273,11 +278,28 @@ final class UserState implements PrintSpoolerCallbacks { if (mPrinterDiscoverySession == null) { return; } - // Request an updated. mPrinterDiscoverySession.onPrintersRemovedLocked(printerIds); } } + @Override + public void onServiceDied(RemotePrintService service) { + synchronized (mLock) { + throwIfDestroyedLocked(); + // No services - nothing to do. + if (mActiveServices.isEmpty()) { + return; + } + // Fail all print jobs. + failActivePrintJobsForService(service.getComponentName()); + // No session - nothing to do. + if (mPrinterDiscoverySession == null) { + return; + } + mPrinterDiscoverySession.onServiceDiedLocked(service); + } + } + public void updateIfNeededLocked() { throwIfDestroyedLocked(); if (readConfigurationLocked()) { @@ -516,23 +538,72 @@ final class UserState implements PrintSpoolerCallbacks { if (!mActiveServices.containsKey(serviceName)) { RemotePrintService service = new RemotePrintService( mContext, serviceName, mUserId, mSpooler, this); - mActiveServices.put(serviceName, service); - if (mPrinterDiscoverySession != null) { - mPrinterDiscoverySession.onServiceAddedLocked(service); - } + addServiceLocked(service); } } else { RemotePrintService service = mActiveServices.remove(serviceName); if (service != null) { - service.destroy(); - if (mPrinterDiscoverySession != null) { - mPrinterDiscoverySession.onServiceRemovedLocked(serviceName); - } + removeServiceLocked(service); } } } } + private void addServiceLocked(RemotePrintService service) { + mActiveServices.put(service.getComponentName(), service); + if (mPrinterDiscoverySession != null) { + mPrinterDiscoverySession.onServiceAddedLocked(service); + } + } + + private void removeServiceLocked(RemotePrintService service) { + // Fail all print jobs. + failActivePrintJobsForService(service.getComponentName()); + // If discovery is in progress, tear down the service. + if (mPrinterDiscoverySession != null) { + mPrinterDiscoverySession.onServiceRemovedLocked(service); + } else { + // Otherwise, just destroy it. + service.destroy(); + } + } + + private void failActivePrintJobsForService(final ComponentName serviceName) { + // Makes sure all active print jobs are failed since the service + // just died. Do this off the main thread since we do to allow + // calls into the spooler on the main thread. + if (Looper.getMainLooper().isCurrentThread()) { + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + failActivePrintJobsForServiceInternal(serviceName); + return null; + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); + } else { + failActivePrintJobsForServiceInternal(serviceName); + } + } + + private void failActivePrintJobsForServiceInternal(ComponentName serviceName) { + List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(serviceName, + PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY); + if (printJobs == null) { + return; + } + final long identity = Binder.clearCallingIdentity(); + try { + final int printJobCount = printJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = printJobs.get(i); + mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, + mContext.getString(R.string.reason_unknown)); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + private void throwIfDestroyedLocked() { if (mDestroyed) { throw new IllegalStateException("Cannot interact with a destroyed instance."); @@ -603,17 +674,18 @@ final class UserState implements PrintSpoolerCallbacks { return; } + final boolean discoveryStarted = !mStartedPrinterDiscoveryTokens.isEmpty(); + + // Remember we got a start request to match with an end. + mStartedPrinterDiscoveryTokens.add(observer.asBinder()); + // If printer discovery is ongoing and the start request has a list // of printer to be checked, then we just request validating them. - if (!mStartedPrinterDiscoveryTokens.isEmpty() - && priorityList != null && !priorityList.isEmpty()) { + if (discoveryStarted && priorityList != null && !priorityList.isEmpty()) { validatePrinters(priorityList); return; } - // Remember we got a start request to match with an end. - mStartedPrinterDiscoveryTokens.add(observer.asBinder()); - // The service are already performing discovery - nothing to do. if (mStartedPrinterDiscoveryTokens.size() > 1) { return; @@ -822,32 +894,20 @@ final class UserState implements PrintSpoolerCallbacks { } } - public void onServiceRemovedLocked(ComponentName serviceName) { + public void onServiceRemovedLocked(RemotePrintService service) { if (mIsDestroyed) { Log.w(LOG_TAG, "Not updating removed service - session destroyed"); return; } - // No printers - nothing to do. - if (mPrinters.isEmpty()) { - return; - } - // Remove the printers for that service. - List<PrinterId> removedPrinterIds = null; - final int printerCount = mPrinters.size(); - for (int i = 0; i < printerCount; i++) { - PrinterId printerId = mPrinters.keyAt(i); - if (printerId.getServiceName().equals(serviceName)) { - if (removedPrinterIds == null) { - removedPrinterIds = new ArrayList<PrinterId>(); - } - removedPrinterIds.add(printerId); - } - } - if (!removedPrinterIds.isEmpty()) { - mHandler.obtainMessage( - SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED, - removedPrinterIds).sendToTarget(); - } + // Remove the reported and tracked printers for that service. + ComponentName serviceName = service.getComponentName(); + removePrintersForServiceLocked(serviceName); + service.destroy(); + } + + public void onServiceDiedLocked(RemotePrintService service) { + // Remove the reported by that service. + removePrintersForServiceLocked(service.getComponentName()); } public void onServiceAddedLocked(RemotePrintService service) { @@ -908,6 +968,34 @@ final class UserState implements PrintSpoolerCallbacks { } } + private void removePrintersForServiceLocked(ComponentName serviceName) { + // No printers - nothing to do. + if (mPrinters.isEmpty()) { + return; + } + // Remove the printers for that service. + List<PrinterId> removedPrinterIds = null; + final int printerCount = mPrinters.size(); + for (int i = 0; i < printerCount; i++) { + PrinterId printerId = mPrinters.keyAt(i); + if (printerId.getServiceName().equals(serviceName)) { + if (removedPrinterIds == null) { + removedPrinterIds = new ArrayList<PrinterId>(); + } + removedPrinterIds.add(printerId); + } + } + final int removedPrinterCount = removedPrinterIds.size(); + for (int i = 0; i < removedPrinterCount; i++) { + mPrinters.remove(removedPrinterIds.get(i)); + } + if (removedPrinterIds != null) { + mHandler.obtainMessage( + SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED, + removedPrinterIds).sendToTarget(); + } + } + private void handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters) { final int observerCount = mDiscoveryObservers.beginBroadcast(); for (int i = 0; i < observerCount; i++) { @@ -1026,14 +1114,17 @@ final class UserState implements PrintSpoolerCallbacks { public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4; public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5; - public static final int MSG_START_PRINTER_DISCOVERY = 6; - public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 7; - public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 8; - public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 9; - public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 10; - public static final int MSG_VALIDATE_PRINTERS = 11; - public static final int MSG_START_PRINTER_STATE_TRACKING = 12; - public static final int MSG_STOP_PRINTER_STATE_TRACKING = 13; + public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6; + public static final int MSG_START_PRINTER_DISCOVERY = 7; + public static final int MSG_STOP_PRINTER_DISCOVERY = 8; + public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9; + public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10; + public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11; + public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12; + public static final int MSG_VALIDATE_PRINTERS = 13; + public static final int MSG_START_PRINTER_STATE_TRACKING = 14; + public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15; + public static final int MSG_DESTROY_SERVICE = 16; SessionHandler(Looper looper) { super(looper, null, false); @@ -1074,11 +1165,21 @@ final class UserState implements PrintSpoolerCallbacks { service.createPrinterDiscoverySession(); } break; + case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: { + RemotePrintService service = (RemotePrintService) message.obj; + service.destroyPrinterDiscoverySession(); + } break; + case MSG_START_PRINTER_DISCOVERY: { RemotePrintService service = (RemotePrintService) message.obj; service.startPrinterDiscovery(null); } break; + case MSG_STOP_PRINTER_DISCOVERY: { + RemotePrintService service = (RemotePrintService) message.obj; + service.stopPrinterDiscovery(); + } break; + case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: { List<RemotePrintService> services = (List<RemotePrintService>) message.obj; handleDispatchCreatePrinterDiscoverySession(services); @@ -1124,7 +1225,12 @@ final class UserState implements PrintSpoolerCallbacks { PrinterId printerId = (PrinterId) args.arg2; args.recycle(); handleStopPrinterStateTracking(service, printerId); - } + } break; + + case MSG_DESTROY_SERVICE: { + RemotePrintService service = (RemotePrintService) message.obj; + service.destroy(); + } break; } } } diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java index c215f40..46f100e 100644 --- a/services/java/com/android/server/wifi/WifiService.java +++ b/services/java/com/android/server/wifi/WifiService.java @@ -170,7 +170,20 @@ public final class WifiService extends IWifiManager.Stub { } /* Client commands are forwarded to state machine */ case WifiManager.CONNECT_NETWORK: - case WifiManager.SAVE_NETWORK: + case WifiManager.SAVE_NETWORK: { + WifiConfiguration config = (WifiConfiguration) msg.obj; + if (config.isValid()) { + mWifiStateMachine.sendMessage(Message.obtain(msg)); + } else { + Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg); + if (msg.what == WifiManager.CONNECT_NETWORK) { + replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED); + } else { + replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED); + } + } + break; + } case WifiManager.FORGET_NETWORK: case WifiManager.START_WPS: case WifiManager.CANCEL_WPS: @@ -185,6 +198,17 @@ public final class WifiService extends IWifiManager.Stub { } } } + + private void replyFailed(Message msg, int what) { + Message reply = msg.obtain(); + reply.what = what; + reply.arg1 = WifiManager.INVALID_ARGS; + try { + msg.replyTo.send(reply); + } catch (RemoteException e) { + // There's not much we can do if reply can't be sent! + } + } } private ClientHandler mClientHandler; @@ -325,11 +349,13 @@ public final class WifiService extends IWifiManager.Stub { private class BatchedScanRequest extends DeathRecipient { BatchedScanSettings settings; int uid; + int pid; - BatchedScanRequest(BatchedScanSettings settings, IBinder binder, int uid) { + BatchedScanRequest(BatchedScanSettings settings, IBinder binder) { super(0, null, binder, null); this.settings = settings; - this.uid = uid; + this.uid = getCallingUid(); + this.pid = getCallingPid(); } public void binderDied() { stopBatchedScan(settings, mBinder); @@ -337,6 +363,10 @@ public final class WifiService extends IWifiManager.Stub { public String toString() { return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}"; } + + public boolean isSameApp() { + return (this.uid == getCallingUid() && this.pid == getCallingPid()); + } } private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>(); @@ -359,7 +389,7 @@ public final class WifiService extends IWifiManager.Stub { if (mBatchedScanSupported == false) return false; requested = new BatchedScanSettings(requested); if (requested.isInvalid()) return false; - BatchedScanRequest r = new BatchedScanRequest(requested, binder, Binder.getCallingUid()); + BatchedScanRequest r = new BatchedScanRequest(requested, binder); synchronized(mBatchedScanners) { mBatchedScanners.add(r); resolveBatchedScannersLocked(); @@ -393,16 +423,18 @@ public final class WifiService extends IWifiManager.Stub { public void stopBatchedScan(BatchedScanSettings settings, IBinder binder) { enforceChangePermission(); if (mBatchedScanSupported == false) return; + ArrayList<BatchedScanRequest> found = new ArrayList<BatchedScanRequest>(); synchronized(mBatchedScanners) { - BatchedScanRequest found = null; for (BatchedScanRequest r : mBatchedScanners) { - if (r.mBinder.equals(binder) && r.settings.equals(settings)) { - found = r; - break; + if (r.isSameApp() && (settings == null || settings.equals(r.settings))) { + found.add(r); + if (settings != null) break; } } - if (found != null) { - mBatchedScanners.remove(found); + for (BatchedScanRequest r : found) { + mBatchedScanners.remove(r); + } + if (found.size() != 0) { resolveBatchedScannersLocked(); } } @@ -547,7 +579,11 @@ public final class WifiService extends IWifiManager.Stub { */ public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { enforceChangePermission(); - mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget(); + if (wifiConfig.isValid()) { + mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget(); + } else { + Slog.e(TAG, "Invalid WifiConfiguration"); + } } /** @@ -580,7 +616,11 @@ public final class WifiService extends IWifiManager.Stub { enforceChangePermission(); if (wifiConfig == null) return; - mWifiStateMachine.setWifiApConfiguration(wifiConfig); + if (wifiConfig.isValid()) { + mWifiStateMachine.setWifiApConfiguration(wifiConfig); + } else { + Slog.e(TAG, "Invalid WifiConfiguration"); + } } /** @@ -638,10 +678,15 @@ public final class WifiService extends IWifiManager.Stub { */ public int addOrUpdateNetwork(WifiConfiguration config) { enforceChangePermission(); - if (mWifiStateMachineChannel != null) { - return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config); + if (config.isValid()) { + if (mWifiStateMachineChannel != null) { + return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config); + } else { + Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); + return -1; + } } else { - Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); + Slog.e(TAG, "bad network configuration"); return -1; } } |