diff options
Diffstat (limited to 'services')
18 files changed, 508 insertions, 215 deletions
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 3d6b6e7..c774763 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -2619,6 +2619,18 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); } + if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { + const InputDeviceInfo::MotionRange& x = mOrientedRanges.x; + const InputDeviceInfo::MotionRange& y = mOrientedRanges.y; + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, + x.fuzz, x.resolution); + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, + y.fuzz, y.resolution); + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, + x.fuzz, x.resolution); + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, + y.fuzz, y.resolution); + } } } @@ -2701,12 +2713,6 @@ void TouchInputMapper::dump(String8& dump) { mPointerYZoomScale); dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n", mPointerGestureMaxSwipeWidth); - } else if (mDeviceMode == DEVICE_MODE_NAVIGATION) { - dump.appendFormat(INDENT3 "Navigation Gesture Detector:\n"); - dump.appendFormat(INDENT4 "AssistStartY: %0.3f\n", - mNavigationAssistStartY); - dump.appendFormat(INDENT4 "AssistEndY: %0.3f\n", - mNavigationAssistEndY); } } @@ -3278,10 +3284,6 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { // Abort current pointer usages because the state has changed. abortPointerUsage(when, 0 /*policyFlags*/); - } else if (mDeviceMode == DEVICE_MODE_NAVIGATION) { - // Compute navigation parameters. - mNavigationAssistStartY = mSurfaceHeight * 0.9f; - mNavigationAssistEndY = mSurfaceHeight * 0.5f; } // Inform the dispatcher about the changes. @@ -3458,6 +3460,19 @@ void TouchInputMapper::parseCalibration() { out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale); + + out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT; + String8 coverageCalibrationString; + if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { + if (coverageCalibrationString == "none") { + out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; + } else if (coverageCalibrationString == "box") { + out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX; + } else if (coverageCalibrationString != "default") { + ALOGW("Invalid value for touch.coverage.calibration: '%s'", + coverageCalibrationString.string()); + } + } } void TouchInputMapper::resolveCalibration() { @@ -3496,6 +3511,11 @@ void TouchInputMapper::resolveCalibration() { } else { mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; } + + // Coverage + if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) { + mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; + } } void TouchInputMapper::dumpCalibration(String8& dump) { @@ -3588,6 +3608,17 @@ void TouchInputMapper::dumpCalibration(String8& dump) { dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale); } + + switch (mCalibration.coverageCalibration) { + case Calibration::COVERAGE_CALIBRATION_NONE: + dump.append(INDENT4 "touch.coverage.calibration: none\n"); + break; + case Calibration::COVERAGE_CALIBRATION_BOX: + dump.append(INDENT4 "touch.coverage.calibration: box\n"); + break; + default: + ALOG_ASSERT(false); + } } void TouchInputMapper::reset(nsecs_t when) { @@ -3621,7 +3652,6 @@ void TouchInputMapper::reset(nsecs_t when) { mPointerGesture.reset(); mPointerSimple.reset(); - mNavigation.reset(); if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); @@ -3772,8 +3802,6 @@ void TouchInputMapper::sync(nsecs_t when) { mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.idToIndex, mCurrentCookedPointerData.touchingIdBits); - } else if (mDeviceMode == DEVICE_MODE_NAVIGATION) { - dispatchNavigationAssist(when, policyFlags); } dispatchHoverExit(when, policyFlags); @@ -4198,13 +4226,31 @@ void TouchInputMapper::cookPointerData() { distance = 0; } - // X and Y + // Coverage + int32_t rawLeft, rawTop, rawRight, rawBottom; + switch (mCalibration.coverageCalibration) { + case Calibration::COVERAGE_CALIBRATION_BOX: + rawLeft = (in.toolMinor & 0xffff0000) >> 16; + rawRight = in.toolMinor & 0x0000ffff; + rawBottom = in.toolMajor & 0x0000ffff; + rawTop = (in.toolMajor & 0xffff0000) >> 16; + break; + default: + rawLeft = rawTop = rawRight = rawBottom = 0; + break; + } + + // X, Y, and the bounding box for coverage information // Adjust coords for surface orientation. - float x, y; + float x, y, left, top, right, bottom; switch (mSurfaceOrientation) { case DISPLAY_ORIENTATION_90: x = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate; + left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; + top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; orientation -= M_PI_2; if (orientation < - M_PI_2) { orientation += M_PI; @@ -4213,10 +4259,18 @@ void TouchInputMapper::cookPointerData() { case DISPLAY_ORIENTATION_180: x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate; y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate; + left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; + right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; + bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; + top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; break; case DISPLAY_ORIENTATION_270: x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate; y = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; + right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; + bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; orientation += M_PI_2; if (orientation > M_PI_2) { orientation -= M_PI; @@ -4225,6 +4279,10 @@ void TouchInputMapper::cookPointerData() { default: x = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; y = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; break; } @@ -4237,11 +4295,18 @@ void TouchInputMapper::cookPointerData() { out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); + if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); + } else { + out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); + out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); + } // Write output properties. PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i]; @@ -5495,44 +5560,6 @@ void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { dispatchPointerSimple(when, policyFlags, false, false); } -void TouchInputMapper::dispatchNavigationAssist(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedPointerData.touchingIdBits.count() == 1) { - if (mLastCookedPointerData.touchingIdBits.isEmpty()) { - // First pointer down. - uint32_t id = mCurrentCookedPointerData.touchingIdBits.firstMarkedBit(); - const PointerCoords& coords = mCurrentCookedPointerData.pointerCoordsForId(id); - if (coords.getY() >= mNavigationAssistStartY) { - // Start tracking the possible assist swipe. - mNavigation.activeAssistId = id; - return; - } - } else if (mNavigation.activeAssistId >= 0 - && mCurrentCookedPointerData.touchingIdBits.hasBit(mNavigation.activeAssistId)) { - const PointerCoords& coords = mCurrentCookedPointerData.pointerCoordsForId( - mNavigation.activeAssistId); - if (coords.getY() > mNavigationAssistEndY) { - // Swipe is still in progress. - return; - } - - // Detected assist swipe. - int32_t metaState = mContext->getGlobalMetaState(); - NotifyKeyArgs downArgs(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, - policyFlags | POLICY_FLAG_VIRTUAL, - AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_ASSIST, 0, metaState, when); - getListener()->notifyKey(&downArgs); - - NotifyKeyArgs upArgs(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, - policyFlags | POLICY_FLAG_VIRTUAL, - AKEY_EVENT_ACTION_UP, 0, AKEYCODE_ASSIST, 0, metaState, when); - getListener()->notifyKey(&upArgs); - } - } - - // Cancel the assist swipe. - mNavigation.activeAssistId = -1; -} - void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, diff --git a/services/input/InputReader.h b/services/input/InputReader.h index ed2a5c1..0189ba7 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -1267,6 +1267,14 @@ protected: bool haveDistanceScale; float distanceScale; + enum CoverageCalibration { + COVERAGE_CALIBRATION_DEFAULT, + COVERAGE_CALIBRATION_NONE, + COVERAGE_CALIBRATION_BOX, + }; + + CoverageCalibration coverageCalibration; + inline void applySizeScaleAndBias(float* outSize) const { if (haveSizeScale) { *outSize *= sizeScale; @@ -1437,10 +1445,6 @@ private: // The maximum swipe width. float mPointerGestureMaxSwipeWidth; - // The start and end Y thresholds for invoking the assist navigation swipe. - float mNavigationAssistStartY; - float mNavigationAssistEndY; - struct PointerDistanceHeapElement { uint32_t currentPointerIndex : 8; uint32_t lastPointerIndex : 8; @@ -1615,15 +1619,6 @@ private: } } mPointerSimple; - struct Navigation { - // The id of a pointer that is tracking a possible assist swipe. - int32_t activeAssistId; // -1 if none - - void reset() { - activeAssistId = -1; - } - } mNavigation; - // The pointer and scroll velocity controls. VelocityControl mPointerVelocityControl; VelocityControl mWheelXVelocityControl; @@ -1659,8 +1654,6 @@ private: bool down, bool hovering); void abortPointerSimple(nsecs_t when, uint32_t policyFlags); - void dispatchNavigationAssist(nsecs_t when, uint32_t policyFlags); - // Dispatches a motion event. // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the // method will take care of setting the index and transmuting the action to DOWN or UP diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3e19094..37a8cb8 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2261,9 +2261,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault()); if (resetMask != 0 || resetDns) { - LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties(); - if (linkProperties != null) { - for (String iface : linkProperties.getAllInterfaceNames()) { + if (curLp != null) { + for (String iface : curLp.getAllInterfaceNames()) { if (TextUtils.isEmpty(iface) == false) { if (resetMask != 0) { if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")"); @@ -2285,6 +2284,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) loge("Exception resetting dns cache: " + e); } } + } else { + loge("Can't reset connection for type "+netType); } } } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 142357d..f784030 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -135,8 +135,8 @@ public class LocationManagerService extends ILocationManager.Stub { // --- fields below are final after systemReady() --- private LocationFudger mLocationFudger; private GeofenceManager mGeofenceManager; - private PowerManager.WakeLock mWakeLock; private PackageManager mPackageManager; + private PowerManager mPowerManager; private GeocoderProxy mGeocodeProvider; private IGpsStatusProvider mGpsStatusProvider; private INetInitiatedListener mNetInitiatedListener; @@ -145,9 +145,6 @@ public class LocationManagerService extends ILocationManager.Stub { private LocationBlacklist mBlacklist; private HandlerThread mHandlerThread; - // --- fields below are protected by mWakeLock --- - private int mPendingBroadcasts; - // --- fields below are protected by mLock --- // Set of providers that are explicitly enabled private final Set<String> mEnabledProviders = new HashSet<String>(); @@ -210,10 +207,8 @@ public class LocationManagerService extends ILocationManager.Stub { // fetch package manager mPackageManager = mContext.getPackageManager(); - // prepare wake lock - PowerManager powerManager = - (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); + // fetch power manager + mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); // prepare worker thread mHandlerThread = new HandlerThread(THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND); @@ -469,6 +464,7 @@ public class LocationManagerService extends ILocationManager.Stub { final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); int mPendingBroadcasts; + PowerManager.WakeLock mWakeLock; Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid, String packageName) { @@ -483,6 +479,10 @@ public class LocationManagerService extends ILocationManager.Stub { mUid = uid; mPid = pid; mPackageName = packageName; + + // construct/configure wakelock + mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); + mWakeLock.setWorkSource(new WorkSource(mUid, mPackageName)); } @Override @@ -645,10 +645,7 @@ public class LocationManagerService extends ILocationManager.Stub { removeUpdatesLocked(this); } synchronized (this) { - if (mPendingBroadcasts > 0) { - LocationManagerService.this.decrementPendingBroadcasts(); - mPendingBroadcasts = 0; - } + clearPendingBroadcastsLocked(); } } @@ -664,32 +661,45 @@ public class LocationManagerService extends ILocationManager.Stub { // containing the sending of the broadcaset private void incrementPendingBroadcastsLocked() { if (mPendingBroadcasts++ == 0) { - LocationManagerService.this.incrementPendingBroadcasts(); + mWakeLock.acquire(); } } private void decrementPendingBroadcastsLocked() { if (--mPendingBroadcasts == 0) { - LocationManagerService.this.decrementPendingBroadcasts(); + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + } + + public void clearPendingBroadcastsLocked() { + if (mPendingBroadcasts > 0) { + mPendingBroadcasts = 0; + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } } } } @Override public void locationCallbackFinished(ILocationListener listener) { - //Do not use getReceiver here as that will add the ILocationListener to + //Do not use getReceiverLocked here as that will add the ILocationListener to //the receiver list if it is not found. If it is not found then the //LocationListener was removed when it had a pending broadcast and should //not be added back. - IBinder binder = listener.asBinder(); - Receiver receiver = mReceivers.get(binder); - if (receiver != null) { - synchronized (receiver) { - // so wakelock calls will succeed - long identity = Binder.clearCallingIdentity(); - receiver.decrementPendingBroadcastsLocked(); - Binder.restoreCallingIdentity(identity); - } + synchronized (mLock) { + IBinder binder = listener.asBinder(); + Receiver receiver = mReceivers.get(binder); + if (receiver != null) { + synchronized (receiver) { + // so wakelock calls will succeed + long identity = Binder.clearCallingIdentity(); + receiver.decrementPendingBroadcastsLocked(); + Binder.restoreCallingIdentity(identity); + } + } } } @@ -1171,7 +1181,8 @@ public class LocationManagerService extends ILocationManager.Stub { } } - private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) { + private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid, + String packageName) { IBinder binder = listener.asBinder(); Receiver receiver = mReceivers.get(binder); if (receiver == null) { @@ -1188,7 +1199,7 @@ public class LocationManagerService extends ILocationManager.Stub { return receiver; } - private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) { + private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName) { Receiver receiver = mReceivers.get(intent); if (receiver == null) { receiver = new Receiver(null, intent, pid, uid, packageName); @@ -1252,7 +1263,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } - private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent, + private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent, int pid, int uid, String packageName) { if (intent == null && listener == null) { throw new IllegalArgumentException("need either listener or intent"); @@ -1260,9 +1271,9 @@ public class LocationManagerService extends ILocationManager.Stub { throw new IllegalArgumentException("cannot register both listener and intent"); } else if (intent != null) { checkPendingIntent(intent); - return getReceiver(intent, pid, uid, packageName); + return getReceiverLocked(intent, pid, uid, packageName); } else { - return getReceiver(listener, pid, uid, packageName); + return getReceiverLocked(listener, pid, uid, packageName); } } @@ -1284,9 +1295,10 @@ public class LocationManagerService extends ILocationManager.Stub { // We don't check for MODE_IGNORED here; we will do that when we go to deliver // a location. checkLocationAccess(uid, packageName, allowedResolutionLevel); - Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName); synchronized (mLock) { + Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid, + packageName); requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName); } } finally { @@ -1333,16 +1345,17 @@ public class LocationManagerService extends ILocationManager.Stub { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); - Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName); - // providers may use public location API's, need to clear identity - long identity = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { + synchronized (mLock) { + Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName); + + // providers may use public location API's, need to clear identity + long identity = Binder.clearCallingIdentity(); + try { removeUpdatesLocked(receiver); + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } } @@ -1352,10 +1365,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { receiver.getListener().asBinder().unlinkToDeath(receiver, 0); synchronized (receiver) { - if (receiver.mPendingBroadcasts > 0) { - decrementPendingBroadcasts(); - receiver.mPendingBroadcasts = 0; - } + receiver.clearPendingBroadcastsLocked(); } } @@ -1957,43 +1967,6 @@ public class LocationManagerService extends ILocationManager.Stub { } }; - // Wake locks - - private void incrementPendingBroadcasts() { - synchronized (mWakeLock) { - if (mPendingBroadcasts++ == 0) { - try { - mWakeLock.acquire(); - log("Acquired wakelock"); - } catch (Exception e) { - // This is to catch a runtime exception thrown when we try to release an - // already released lock. - Slog.e(TAG, "exception in acquireWakeLock()", e); - } - } - } - } - - private void decrementPendingBroadcasts() { - synchronized (mWakeLock) { - if (--mPendingBroadcasts == 0) { - try { - // Release wake lock - if (mWakeLock.isHeld()) { - mWakeLock.release(); - log("Released wakelock"); - } else { - log("Can't release wakelock again!"); - } - } catch (Exception e) { - // This is to catch a runtime exception thrown when we try to release an - // already released lock. - Slog.e(TAG, "exception in releaseWakeLock()", e); - } - } - } - } - // Geocoder @Override diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index d7adbf7..f402f4b 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -64,6 +64,7 @@ import com.android.internal.app.IMediaContainerService; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.NativeDaemonConnector.Command; +import com.android.server.NativeDaemonConnector.SensitiveArg; import com.android.server.am.ActivityManagerService; import com.android.server.pm.PackageManagerService; import com.android.server.pm.UserManagerService; @@ -1642,8 +1643,8 @@ class MountService extends IMountService.Stub int rc = StorageResultCode.OperationSucceeded; try { - mConnector.execute("asec", "create", id, sizeMb, fstype, key, ownerUid, - external ? "1" : "0"); + mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key), + ownerUid, external ? "1" : "0"); } catch (NativeDaemonConnectorException e) { rc = StorageResultCode.OperationFailedInternalError; } @@ -1743,7 +1744,7 @@ class MountService extends IMountService.Stub int rc = StorageResultCode.OperationSucceeded; try { - mConnector.execute("asec", "mount", id, key, ownerUid); + mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid); } catch (NativeDaemonConnectorException e) { int code = e.getCode(); if (code != VoldResponseCode.OpFailedStorageBusy) { @@ -2019,7 +2020,7 @@ class MountService extends IMountService.Stub final NativeDaemonEvent event; try { - event = mConnector.execute("cryptfs", "checkpw", password); + event = mConnector.execute("cryptfs", "checkpw", new SensitiveArg(password)); final int code = Integer.parseInt(event.getMessage()); if (code == 0) { @@ -2058,7 +2059,7 @@ class MountService extends IMountService.Stub } try { - mConnector.execute("cryptfs", "enablecrypto", "inplace", password); + mConnector.execute("cryptfs", "enablecrypto", "inplace", new SensitiveArg(password)); } catch (NativeDaemonConnectorException e) { // Encryption failed return e.getCode(); @@ -2083,7 +2084,7 @@ class MountService extends IMountService.Stub final NativeDaemonEvent event; try { - event = mConnector.execute("cryptfs", "changepw", password); + event = mConnector.execute("cryptfs", "changepw", new SensitiveArg(password)); return Integer.parseInt(event.getMessage()); } catch (NativeDaemonConnectorException e) { // Encryption failed @@ -2116,7 +2117,7 @@ class MountService extends IMountService.Stub final NativeDaemonEvent event; try { - event = mConnector.execute("cryptfs", "verifypw", password); + event = mConnector.execute("cryptfs", "verifypw", new SensitiveArg(password)); Slog.i(TAG, "cryptfs verifypw => " + event.getMessage()); return Integer.parseInt(event.getMessage()); } catch (NativeDaemonConnectorException e) { @@ -2482,8 +2483,8 @@ class MountService extends IMountService.Stub int rc = StorageResultCode.OperationSucceeded; try { - mConnector.execute( - "obb", "mount", mObbState.voldPath, hashedKey, mObbState.ownerGid); + mConnector.execute("obb", "mount", mObbState.voldPath, new SensitiveArg(hashedKey), + mObbState.ownerGid); } catch (NativeDaemonConnectorException e) { int code = e.getCode(); if (code != VoldResponseCode.OpFailedStorageBusy) { diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index c3f2afa..47840e0 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -204,9 +204,28 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } /** + * Wrapper around argument that indicates it's sensitive and shouldn't be + * logged. + */ + public static class SensitiveArg { + private final Object mArg; + + public SensitiveArg(Object arg) { + mArg = arg; + } + + @Override + public String toString() { + return String.valueOf(mArg); + } + } + + /** * Make command for daemon, escaping arguments as needed. */ - private void makeCommand(StringBuilder builder, String cmd, Object... args) { + @VisibleForTesting + static void makeCommand(StringBuilder rawBuilder, StringBuilder logBuilder, int sequenceNumber, + String cmd, Object... args) { if (cmd.indexOf('\0') >= 0) { throw new IllegalArgumentException("Unexpected command: " + cmd); } @@ -214,16 +233,26 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo throw new IllegalArgumentException("Arguments must be separate from command"); } - builder.append(cmd); + rawBuilder.append(sequenceNumber).append(' ').append(cmd); + logBuilder.append(sequenceNumber).append(' ').append(cmd); for (Object arg : args) { final String argString = String.valueOf(arg); if (argString.indexOf('\0') >= 0) { throw new IllegalArgumentException("Unexpected argument: " + arg); } - builder.append(' '); - appendEscaped(builder, argString); + rawBuilder.append(' '); + logBuilder.append(' '); + + appendEscaped(rawBuilder, argString); + if (arg instanceof SensitiveArg) { + logBuilder.append("[scrubbed]"); + } else { + appendEscaped(logBuilder, argString); + } } + + rawBuilder.append('\0'); } /** @@ -303,27 +332,27 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { + final long startTime = SystemClock.elapsedRealtime(); + final ArrayList<NativeDaemonEvent> events = Lists.newArrayList(); + final StringBuilder rawBuilder = new StringBuilder(); + final StringBuilder logBuilder = new StringBuilder(); final int sequenceNumber = mSequenceNumber.incrementAndGet(); - final StringBuilder cmdBuilder = - new StringBuilder(Integer.toString(sequenceNumber)).append(' '); - final long startTime = SystemClock.elapsedRealtime(); - makeCommand(cmdBuilder, cmd, args); + makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args); - final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */ - log("SND -> {" + logCmd + "}"); + final String rawCmd = rawBuilder.toString(); + final String logCmd = logBuilder.toString(); - cmdBuilder.append('\0'); - final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */ + log("SND -> {" + logCmd + "}"); synchronized (mDaemonLock) { if (mOutputStream == null) { throw new NativeDaemonConnectorException("missing output stream"); } else { try { - mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); + mOutputStream.write(rawCmd.getBytes(Charsets.UTF_8)); } catch (IOException e) { throw new NativeDaemonConnectorException("problem sending command", e); } @@ -332,7 +361,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo NativeDaemonEvent event = null; do { - event = mResponseQueue.remove(sequenceNumber, timeout, sentCmd); + event = mResponseQueue.remove(sequenceNumber, timeout, logCmd); if (event == null) { loge("timed-out waiting for response to " + logCmd); throw new NativeDaemonFailureException(logCmd, event); @@ -447,10 +476,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private static class ResponseQueue { private static class PendingCmd { - public int cmdNum; + public final int cmdNum; + public final String logCmd; + public BlockingQueue<NativeDaemonEvent> responses = new ArrayBlockingQueue<NativeDaemonEvent>(10); - public String request; // The availableResponseCount member is used to track when we can remove this // instance from the ResponseQueue. @@ -468,7 +498,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // hold references to this instance already so it can be removed from // mPendingCmds queue. public int availableResponseCount; - public PendingCmd(int c, String r) {cmdNum = c; request = r;} + + public PendingCmd(int cmdNum, String logCmd) { + this.cmdNum = cmdNum; + this.logCmd = logCmd; + } } private final LinkedList<PendingCmd> mPendingCmds; @@ -497,7 +531,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // let any waiter timeout waiting for this PendingCmd pendingCmd = mPendingCmds.remove(); Slog.e("NativeDaemonConnector.ResponseQueue", - "Removing request: " + pendingCmd.request + " (" + + "Removing request: " + pendingCmd.logCmd + " (" + pendingCmd.cmdNum + ")"); } found = new PendingCmd(cmdNum, null); @@ -515,7 +549,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // note that the timeout does not count time in deep sleep. If you don't want // the device to sleep, hold a wakelock - public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String origCmd) { + public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String logCmd) { PendingCmd found = null; synchronized (mPendingCmds) { for (PendingCmd pendingCmd : mPendingCmds) { @@ -525,7 +559,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } if (found == null) { - found = new PendingCmd(cmdNum, origCmd); + found = new PendingCmd(cmdNum, logCmd); mPendingCmds.add(found); } found.availableResponseCount--; @@ -547,7 +581,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo pw.println("Pending requests:"); synchronized (mPendingCmds) { for (PendingCmd pendingCmd : mPendingCmds) { - pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.request); + pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.logCmd); } } } diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index d2acb40..3b84c732 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -34,7 +34,6 @@ import static com.android.server.NetworkManagementService.NetdResponseCode.Tethe import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult; import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED; -import android.bluetooth.BluetoothTetheringDataTracker; import android.content.Context; import android.net.INetworkManagementEventObserver; import android.net.InterfaceConfiguration; @@ -59,6 +58,7 @@ import android.util.SparseBooleanArray; import com.android.internal.net.NetworkStatsFactory; import com.android.internal.util.Preconditions; import com.android.server.NativeDaemonConnector.Command; +import com.android.server.NativeDaemonConnector.SensitiveArg; import com.android.server.net.LockdownVpnTracker; import com.google.android.collect.Maps; @@ -990,7 +990,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub mConnector.execute("softap", "set", wlanIface); } else { mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID, - getSecurityType(wifiConfig), wifiConfig.preSharedKey); + getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)); } mConnector.execute("softap", "startap"); } catch (NativeDaemonConnectorException e) { @@ -1039,7 +1039,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub mConnector.execute("softap", "set", wlanIface); } else { mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID, - getSecurityType(wifiConfig), wifiConfig.preSharedKey); + getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)); } } catch (NativeDaemonConnectorException e) { throw e.rethrowAsParcelableException(); diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 6a1ef45..29aaeaf 100644 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -40,6 +40,8 @@ import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.database.ContentObserver; @@ -88,7 +90,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.NoSuchElementException; +import java.util.Set; import libcore.io.IoUtils; @@ -283,13 +287,14 @@ public class NotificationManagerService extends INotificationManager.Stub } public void record(StatusBarNotification nr) { - // Nuke heavy parts of notification before storing in archive - nr.getNotification().lightenPayload(); - if (mBuffer.size() == BUFFER_SIZE) { mBuffer.removeFirst(); } - mBuffer.addLast(nr); + + // We don't want to store the heavy bits of the notification in the archive, + // but other clients in the system process might be using the object, so we + // store a (lightened) copy. + mBuffer.addLast(nr.cloneLight()); } @@ -533,6 +538,60 @@ public class NotificationManagerService extends INotificationManager.Stub } /** + * Remove notification access for any services that no longer exist. + */ + void disableNonexistentListeners() { + int currentUser = ActivityManager.getCurrentUser(); + String flatIn = Settings.Secure.getStringForUser( + mContext.getContentResolver(), + Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, + currentUser); + if (!TextUtils.isEmpty(flatIn)) { + if (DBG) Slog.v(TAG, "flat before: " + flatIn); + PackageManager pm = mContext.getPackageManager(); + List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( + new Intent(NotificationListenerService.SERVICE_INTERFACE), + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, + currentUser); + + Set<ComponentName> installed = new HashSet<ComponentName>(); + for (int i = 0, count = installedServices.size(); i < count; i++) { + ResolveInfo resolveInfo = installedServices.get(i); + ServiceInfo info = resolveInfo.serviceInfo; + + if (!android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE.equals( + info.permission)) { + Slog.w(TAG, "Skipping notification listener service " + + info.packageName + "/" + info.name + + ": it does not require the permission " + + android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE); + continue; + } + installed.add(new ComponentName(info.packageName, info.name)); + } + + String flatOut = ""; + if (!installed.isEmpty()) { + String[] enabled = flatIn.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR); + ArrayList<String> remaining = new ArrayList<String>(enabled.length); + for (int i = 0; i < enabled.length; i++) { + ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]); + if (installed.contains(enabledComponent)) { + remaining.add(enabled[i]); + } + } + flatOut = TextUtils.join(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR, remaining); + } + if (DBG) Slog.v(TAG, "flat after: " + flatOut); + if (!flatIn.equals(flatOut)) { + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, + flatOut, currentUser); + } + } + } + + /** * Called whenever packages change, the user switches, or ENABLED_NOTIFICATION_LISTENERS * is altered. (For example in response to USER_SWITCHED in our broadcast receiver) */ @@ -704,7 +763,8 @@ public class NotificationManagerService extends INotificationManager.Stub final int N = mListeners.size(); for (int i=N-1; i>=0; i--) { final NotificationListenerInfo info = mListeners.get(i); - if (info.listener == listener && info.userid == userid) { + if (info.listener.asBinder() == listener.asBinder() + && info.userid == userid) { mListeners.remove(i); if (info.connection != null) { mContext.unbindService(info.connection); @@ -1073,15 +1133,20 @@ public class NotificationManagerService extends INotificationManager.Stub String action = intent.getAction(); boolean queryRestart = false; + boolean queryRemove = false; boolean packageChanged = false; + boolean cancelNotifications = true; if (action.equals(Intent.ACTION_PACKAGE_ADDED) - || action.equals(Intent.ACTION_PACKAGE_REMOVED) + || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) || action.equals(Intent.ACTION_PACKAGE_RESTARTED) || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { String pkgList[] = null; + boolean queryReplace = queryRemove && + intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); + if (DBG) Slog.i(TAG, "queryReplace=" + queryReplace); if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } else if (queryRestart) { @@ -1101,7 +1166,7 @@ public class NotificationManagerService extends INotificationManager.Stub .getApplicationEnabledSetting(pkgName); if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { - return; + cancelNotifications = false; } } pkgList = new String[]{pkgName}; @@ -1110,8 +1175,10 @@ public class NotificationManagerService extends INotificationManager.Stub boolean anyListenersInvolved = false; if (pkgList != null && (pkgList.length > 0)) { for (String pkgName : pkgList) { - cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart, - UserHandle.USER_ALL); + if (cancelNotifications) { + cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart, + UserHandle.USER_ALL); + } if (mEnabledListenerPackageNames.contains(pkgName)) { anyListenersInvolved = true; } @@ -1119,6 +1186,10 @@ public class NotificationManagerService extends INotificationManager.Stub } if (anyListenersInvolved) { + // if we're not replacing a package, clean up orphaned bits + if (!queryReplace) { + disableNonexistentListeners(); + } // make sure we're still bound to any of our // listeners who may have just upgraded rebindListenerServices(); @@ -1319,7 +1390,7 @@ public class NotificationManagerService extends INotificationManager.Stub return ; } - final boolean isSystemToast = ("android".equals(pkg)); + final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) { if (!isSystemToast) { @@ -1535,7 +1606,7 @@ public class NotificationManagerService extends INotificationManager.Stub Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification); } checkCallerIsSystemOrSameApp(pkg); - final boolean isSystemNotification = ("android".equals(pkg)); + final boolean isSystemNotification = isCallerSystem() || ("android".equals(pkg)); userId = ActivityManager.handleIncomingUser(callingPid, callingUid, userId, true, false, "enqueueNotification", pkg); @@ -2013,19 +2084,26 @@ public class NotificationManagerService extends INotificationManager.Stub cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId); } + // Return true if the caller is a system or phone UID and therefore should not have + // any notifications or toasts blocked. + boolean isCallerSystem() { + final int uid = Binder.getCallingUid(); + final int appid = UserHandle.getAppId(uid); + return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); + } + void checkCallerIsSystem() { - int uid = Binder.getCallingUid(); - if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) { + if (isCallerSystem()) { return; } - throw new SecurityException("Disallowed call for uid " + uid); + throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); } void checkCallerIsSystemOrSameApp(String pkg) { - int uid = Binder.getCallingUid(); - if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) { + if (isCallerSystem()) { return; } + final int uid = Binder.getCallingUid(); try { ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( pkg, 0, UserHandle.getCallingUserId()); diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 2b5544b..2f8250f 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -95,6 +95,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -405,7 +406,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { synchronized (mLock) { final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); - return getUserStateLocked(resolvedUserId).mInstalledServices; + // The automation service is a fake one and should not be reported + // to clients as being installed - it really is not. + UserState userState = getUserStateLocked(resolvedUserId); + if (userState.mUiAutomationService != null) { + List<AccessibilityServiceInfo> installedServices = + new ArrayList<AccessibilityServiceInfo>(); + installedServices.addAll(userState.mInstalledServices); + installedServices.remove(userState.mUiAutomationService); + return installedServices; + } + return userState.mInstalledServices; } } @@ -415,9 +426,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { synchronized (mLock) { final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); + + // The automation service is a fake one and should not be reported + // to clients as being enabled. The automation service is always the + // only active one, if it exists. + UserState userState = getUserStateLocked(resolvedUserId); + if (userState.mUiAutomationService != null) { + return Collections.emptyList(); + } + result = mEnabledServicesForFeedbackTempList; result.clear(); - List<Service> services = getUserStateLocked(resolvedUserId).mBoundServices; + List<Service> services = userState.mBoundServices; while (feedbackType != 0) { final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType)); feedbackType &= ~feedbackTypeBit; diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java index 3b63937..0fbde37 100644 --- a/services/java/com/android/server/accounts/AccountManagerService.java +++ b/services/java/com/android/server/accounts/AccountManagerService.java @@ -2802,12 +2802,19 @@ public class AccountManagerService if (sharedAccounts == null || sharedAccounts.length == 0) return unfiltered; String requiredAccountType = ""; try { - for (String packageName : packages) { - PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0); + // If there's an explicit callingPackage specified, check if that package + // opted in to see restricted accounts. + if (callingPackage != null) { + PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0); if (pi != null && pi.restrictedAccountType != null) { requiredAccountType = pi.restrictedAccountType; - // If it matches the package name of the original caller, use this choice. - if (callingPackage != null && packageName.equals(callingPackage)) { + } + } else { + // Otherwise check if the callingUid has a package that has opted in + for (String packageName : packages) { + PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0); + if (pi != null && pi.restrictedAccountType != null) { + requiredAccountType = pi.restrictedAccountType; break; } } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 0f1700d..c344023 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -3655,7 +3655,9 @@ final class ActivityStack { } if (activityRemoved) { - resumeTopActivityLocked(null); + synchronized (mService) { + resumeTopActivityLocked(null); + } } return res; diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java index 1c883ec..ff1281e 100644 --- a/services/java/com/android/server/content/SyncManager.java +++ b/services/java/com/android/server/content/SyncManager.java @@ -1971,6 +1971,10 @@ public class SyncManager { for (int i = 0, N = info.periodicSyncs.size(); i < N; i++) { final Bundle extras = info.periodicSyncs.get(i).first; final Long periodInMillis = info.periodicSyncs.get(i).second * 1000; + // Skip if the period is invalid + if (periodInMillis <= 0) { + continue; + } // find when this periodic sync was last scheduled to run final long lastPollTimeAbsolute = status.getPeriodicSyncTime(i); diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 1a0455c..22ce284 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -8120,7 +8120,7 @@ public class PackageManagerService extends IPackageManager.Stub { allUsers = sUserManager.getUserIds(); perUserInstalled = new boolean[allUsers.length]; for (int i = 0; i < allUsers.length; i++) { - perUserInstalled[i] = ps.getInstalled(allUsers[i]); + perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false; } } boolean sysPkg = (isSystemApp(oldPackage)); @@ -8689,7 +8689,7 @@ public class PackageManagerService extends IPackageManager.Stub { allUsers = sUserManager.getUserIds(); perUserInstalled = new boolean[allUsers.length]; for (int i = 0; i < allUsers.length; i++) { - perUserInstalled[i] = ps.getInstalled(allUsers[i]); + perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false; } } diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/java/com/android/server/wifi/WifiController.java index 6e6b8cc..87b4394 100644 --- a/services/java/com/android/server/wifi/WifiController.java +++ b/services/java/com/android/server/wifi/WifiController.java @@ -34,6 +34,7 @@ import android.net.wifi.WifiStateMachine; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.SystemClock; import android.os.WorkSource; import android.provider.Settings; import android.util.Slog; @@ -70,6 +71,17 @@ class WifiController extends StateMachine { */ private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */ + /** + * See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}. This is the default value if a + * Settings.Global value is not present. This is the minimum time after wifi is disabled + * we'll act on an enable. Enable requests received before this delay will be deferred. + */ + private static final long DEFAULT_REENABLE_DELAY_MS = 500; + + // finding that delayed messages can sometimes be delivered earlier than expected + // probably rounding errors.. add a margin to prevent problems + private static final long DEFER_MARGIN_MS = 5; + NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", ""); private static final String ACTION_DEVICE_IDLE = @@ -86,6 +98,8 @@ class WifiController extends StateMachine { */ private final WorkSource mTmpWorkSource = new WorkSource(); + private long mReEnableDelayMillis; + private static final int BASE = Protocol.BASE_WIFI_CONTROLLER; static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1; @@ -98,6 +112,7 @@ class WifiController extends StateMachine { static final int CMD_WIFI_TOGGLED = BASE + 8; static final int CMD_AIRPLANE_TOGGLED = BASE + 9; static final int CMD_SET_AP = BASE + 10; + static final int CMD_DEFERRED_TOGGLE = BASE + 11; private DefaultState mDefaultState = new DefaultState(); private StaEnabledState mStaEnabledState = new StaEnabledState(); @@ -135,9 +150,13 @@ class WifiController extends StateMachine { addState(mStaDisabledWithScanState, mDefaultState); addState(mApEnabledState, mDefaultState); addState(mEcmState, mDefaultState); - setInitialState(mApStaDisabledState); - setLogRecSize(25); - setLogOnlyTransitions(true); + if (mSettingsStore.isScanAlwaysAvailable()) { + setInitialState(mStaDisabledWithScanState); + } else { + setInitialState(mApStaDisabledState); + } + setLogRecSize(100); + setLogOnlyTransitions(false); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_DEVICE_IDLE); @@ -168,6 +187,7 @@ class WifiController extends StateMachine { registerForWifiIdleTimeChange(handler); readWifiSleepPolicy(); registerForWifiSleepPolicyChange(handler); + readWifiReEnableDelay(); } private void readStayAwakeConditions() { @@ -186,6 +206,11 @@ class WifiController extends StateMachine { Settings.Global.WIFI_SLEEP_POLICY_NEVER); } + private void readWifiReEnableDelay() { + mReEnableDelayMillis = Settings.Global.getLong(mContext.getContentResolver(), + Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS); + } + /** * Observes settings changes to scan always mode. */ @@ -336,6 +361,9 @@ class WifiController extends StateMachine { case CMD_AIRPLANE_TOGGLED: case CMD_EMERGENCY_MODE_CHANGED: break; + case CMD_DEFERRED_TOGGLE: + log("DEFERRED_TOGGLE ignored due to state change"); + break; default: throw new RuntimeException("WifiController.handleMessage " + msg.what); } @@ -345,9 +373,17 @@ class WifiController extends StateMachine { } class ApStaDisabledState extends State { + private int mDeferredEnableSerialNumber = 0; + private boolean mHaveDeferredEnable = false; + private long mDisabledTimestamp; + @Override public void enter() { mWifiStateMachine.setSupplicantRunning(false); + // Supplicant can't restart right away, so not the time we switched off + mDisabledTimestamp = SystemClock.elapsedRealtime(); + mDeferredEnableSerialNumber++; + mHaveDeferredEnable = false; } @Override public boolean processMessage(Message msg) { @@ -355,6 +391,14 @@ class WifiController extends StateMachine { case CMD_WIFI_TOGGLED: case CMD_AIRPLANE_TOGGLED: if (mSettingsStore.isWifiToggleEnabled()) { + if (doDeferEnable(msg)) { + if (mHaveDeferredEnable) { + // have 2 toggles now, inc serial number an ignore both + mDeferredEnableSerialNumber++; + } + mHaveDeferredEnable = !mHaveDeferredEnable; + break; + } if (mDeviceIdle == false) { transitionTo(mDeviceActiveState); } else { @@ -374,12 +418,37 @@ class WifiController extends StateMachine { transitionTo(mApEnabledState); } break; + case CMD_DEFERRED_TOGGLE: + if (msg.arg1 != mDeferredEnableSerialNumber) { + log("DEFERRED_TOGGLE ignored due to serial mismatch"); + break; + } + log("DEFERRED_TOGGLE handled"); + sendMessage((Message)(msg.obj)); + break; default: return NOT_HANDLED; } return HANDLED; } + private boolean doDeferEnable(Message msg) { + long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; + if (delaySoFar >= mReEnableDelayMillis) { + return false; + } + + log("WifiController msg " + msg + " deferred for " + + (mReEnableDelayMillis - delaySoFar) + "ms"); + + // need to defer this action. + Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); + deferredMsg.obj = Message.obtain(msg); + deferredMsg.arg1 = ++mDeferredEnableSerialNumber; + sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); + return true; + } + } class StaEnabledState extends State { @@ -421,11 +490,19 @@ class WifiController extends StateMachine { } class StaDisabledWithScanState extends State { + private int mDeferredEnableSerialNumber = 0; + private boolean mHaveDeferredEnable = false; + private long mDisabledTimestamp; + @Override public void enter() { mWifiStateMachine.setSupplicantRunning(true); mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE); mWifiStateMachine.setDriverStart(true); + // Supplicant can't restart right away, so not the time we switched off + mDisabledTimestamp = SystemClock.elapsedRealtime(); + mDeferredEnableSerialNumber++; + mHaveDeferredEnable = false; } @Override @@ -433,6 +510,14 @@ class WifiController extends StateMachine { switch (msg.what) { case CMD_WIFI_TOGGLED: if (mSettingsStore.isWifiToggleEnabled()) { + if (doDeferEnable(msg)) { + if (mHaveDeferredEnable) { + // have 2 toggles now, inc serial number and ignore both + mDeferredEnableSerialNumber++; + } + mHaveDeferredEnable = !mHaveDeferredEnable; + break; + } if (mDeviceIdle == false) { transitionTo(mDeviceActiveState); } else { @@ -457,11 +542,37 @@ class WifiController extends StateMachine { transitionTo(mApStaDisabledState); } break; + case CMD_DEFERRED_TOGGLE: + if (msg.arg1 != mDeferredEnableSerialNumber) { + log("DEFERRED_TOGGLE ignored due to serial mismatch"); + break; + } + logd("DEFERRED_TOGGLE handled"); + sendMessage((Message)(msg.obj)); + break; default: return NOT_HANDLED; } return HANDLED; } + + private boolean doDeferEnable(Message msg) { + long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; + if (delaySoFar >= mReEnableDelayMillis) { + return false; + } + + log("WifiController msg " + msg + " deferred for " + + (mReEnableDelayMillis - delaySoFar) + "ms"); + + // need to defer this action. + Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); + deferredMsg.obj = Message.obtain(msg); + deferredMsg.arg1 = ++mDeferredEnableSerialNumber; + sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); + return true; + } + } class ApEnabledState extends State { diff --git a/services/java/com/android/server/wifi/WifiNotificationController.java b/services/java/com/android/server/wifi/WifiNotificationController.java index 17ef7c8..a9206e0 100644 --- a/services/java/com/android/server/wifi/WifiNotificationController.java +++ b/services/java/com/android/server/wifi/WifiNotificationController.java @@ -91,10 +91,12 @@ final class WifiNotificationController { private final Context mContext; private final WifiStateMachine mWifiStateMachine; private NetworkInfo mNetworkInfo; + private volatile int mWifiState; WifiNotificationController(Context context, WifiStateMachine wsm) { mContext = context; mWifiStateMachine = wsm; + mWifiState = WifiManager.WIFI_STATE_UNKNOWN; IntentFilter filter = new IntentFilter(); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); @@ -106,6 +108,8 @@ final class WifiNotificationController { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN); resetNotification(); } else if (intent.getAction().equals( WifiManager.NETWORK_STATE_CHANGED_ACTION)) { @@ -141,6 +145,7 @@ final class WifiNotificationController { // don't bother doing any of the following if (!mNotificationEnabled) return; if (networkInfo == null) return; + if (mWifiState != WifiManager.WIFI_STATE_ENABLED) return; NetworkInfo.State state = networkInfo.getState(); if ((state == NetworkInfo.State.DISCONNECTED) diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java index 8ddc776..66ef978 100644 --- a/services/java/com/android/server/wifi/WifiService.java +++ b/services/java/com/android/server/wifi/WifiService.java @@ -651,7 +651,12 @@ public final class WifiService extends IWifiManager.Stub { Slog.i(TAG, "WifiService trying to set country code to " + countryCode + " with persist set to " + persist); enforceChangePermission(); - mWifiStateMachine.setCountryCode(countryCode, persist); + final long token = Binder.clearCallingIdentity(); + try { + mWifiStateMachine.setCountryCode(countryCode, persist); + } finally { + Binder.restoreCallingIdentity(token); + } } /** @@ -668,7 +673,12 @@ public final class WifiService extends IWifiManager.Stub { if (!isDualBandSupported()) return; Slog.i(TAG, "WifiService trying to set frequency band to " + band + " with persist set to " + persist); - mWifiStateMachine.setFrequencyBand(band, persist); + final long token = Binder.clearCallingIdentity(); + try { + mWifiStateMachine.setFrequencyBand(band, persist); + } finally { + Binder.restoreCallingIdentity(token); + } } diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp index 485c289..433950d 100644 --- a/services/jni/com_android_server_BatteryService.cpp +++ b/services/jni/com_android_server_BatteryService.cpp @@ -144,7 +144,7 @@ static jint getBatteryHealth(const char* status) static int readFromFile(const String8& path, char* buf, size_t size) { - if (!path) + if (path.isEmpty()) return -1; int fd = open(path.string(), O_RDONLY, 0); if (fd == -1) { diff --git a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java index 275d807..e2253a2 100644 --- a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java +++ b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java @@ -17,10 +17,13 @@ package com.android.server; import static com.android.server.NativeDaemonConnector.appendEscaped; +import static com.android.server.NativeDaemonConnector.makeCommand; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.MediumTest; +import com.android.server.NativeDaemonConnector.SensitiveArg; + /** * Tests for {@link NativeDaemonConnector}. */ @@ -67,4 +70,28 @@ public class NativeDaemonConnectorTest extends AndroidTestCase { appendEscaped(builder, "caf\u00E9 c\u00F6ffee"); assertEquals("\"caf\u00E9 c\u00F6ffee\"", builder.toString()); } + + public void testSensitiveArgs() throws Exception { + final StringBuilder rawBuilder = new StringBuilder(); + final StringBuilder logBuilder = new StringBuilder(); + + rawBuilder.setLength(0); + logBuilder.setLength(0); + makeCommand(rawBuilder, logBuilder, 1, "foo", "bar", "baz"); + assertEquals("1 foo bar baz\0", rawBuilder.toString()); + assertEquals("1 foo bar baz", logBuilder.toString()); + + rawBuilder.setLength(0); + logBuilder.setLength(0); + makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("bar"), "baz"); + assertEquals("1 foo bar baz\0", rawBuilder.toString()); + assertEquals("1 foo [scrubbed] baz", logBuilder.toString()); + + rawBuilder.setLength(0); + logBuilder.setLength(0); + makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("foo bar"), "baz baz", + new SensitiveArg("wat")); + assertEquals("1 foo \"foo bar\" \"baz baz\" wat\0", rawBuilder.toString()); + assertEquals("1 foo [scrubbed] \"baz baz\" [scrubbed]", logBuilder.toString()); + } } |