summaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java74
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java37
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java11
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java102
-rw-r--r--services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java2
-rw-r--r--services/backup/java/com/android/server/backup/utils/TarBackupReader.java20
-rw-r--r--services/companion/TEST_MAPPING12
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java10
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java30
-rw-r--r--services/core/java/com/android/server/DynamicSystemService.java10
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java87
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java9
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java6
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java18
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java117
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java142
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java39
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java77
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java141
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java184
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java50
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java8
-rw-r--r--services/core/java/com/android/server/audio/AudioEventLogger.java31
-rw-r--r--[-rwxr-xr-x]services/core/java/com/android/server/audio/AudioService.java142
-rw-r--r--[-rwxr-xr-x]services/core/java/com/android/server/audio/MediaFocusControl.java0
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/Face10.java36
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java2
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java67
-rw-r--r--services/core/java/com/android/server/connectivity/KeepaliveTracker.java50
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java2
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java2
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java4
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java24
-rw-r--r--services/core/java/com/android/server/hdmi/ActiveSourceAction.java2
-rw-r--r--services/core/java/com/android/server/hdmi/ActiveSourceHandler.java8
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecController.java14
-rwxr-xr-xservices/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java59
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java6
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java12
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java16
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java5
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java33
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java39
-rw-r--r--services/core/java/com/android/server/inputmethod/TEST_MAPPING7
-rw-r--r--services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java28
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java43
-rw-r--r--services/core/java/com/android/server/location/LocationProviderManager.java322
-rw-r--r--services/core/java/com/android/server/location/geofence/GeofenceManager.java22
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java20
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java101
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssManagerService.java2
-rw-r--r--services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java4
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java187
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerRegistration.java54
-rw-r--r--services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java2
-rw-r--r--services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java75
-rw-r--r--services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java10
-rw-r--r--services/core/java/com/android/server/location/util/SystemSettingsHelper.java9
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java2
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStorage.java2
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java29
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java2
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java103
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/ApkChecksums.java510
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java4
-rw-r--r--services/core/java/com/android/server/pm/ComponentResolver.java83
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java36
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java232
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java223
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java13
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java1
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java73
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java65
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java15
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java14
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java6
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java10
-rw-r--r--services/core/java/com/android/server/security/VerityUtils.java18
-rw-r--r--services/core/java/com/android/server/slice/SliceFullAccessList.java2
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java3
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java13
-rw-r--r--services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java19
-rw-r--r--services/core/java/com/android/server/timezonedetector/TEST_MAPPING12
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java2
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java14
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java123
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java9
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java129
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java14
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java79
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java626
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettings.java10
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java2
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java5
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java5
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java11
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java2
-rw-r--r--services/core/java/com/android/server/wm/OWNERS1
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java7
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java13
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java22
-rw-r--r--services/core/java/com/android/server/wm/Task.java116
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java52
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java77
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java32
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/com_android_server_am_CachedAppOptimizer.cpp18
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp15
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp23
-rw-r--r--services/core/jni/com_android_server_security_VerityUtils.cpp36
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java22
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java2
-rw-r--r--services/incremental/Android.bp6
-rw-r--r--services/incremental/BinderIncrementalService.cpp7
-rw-r--r--services/incremental/BinderIncrementalService.h2
-rw-r--r--services/incremental/IncrementalService.cpp38
-rw-r--r--services/incremental/IncrementalService.h2
-rw-r--r--services/incremental/ServiceWrappers.cpp4
-rw-r--r--services/incremental/ServiceWrappers.h3
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp61
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java193
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java57
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java83
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java106
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java79
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java79
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java92
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java23
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java2
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java63
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java21
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java25
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java56
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java73
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java46
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java46
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java56
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java29
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java228
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java39
183 files changed, 4867 insertions, 2665 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index 070626be9f80..df4a52e308b6 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -256,6 +256,7 @@ class EventDispatcher {
return actionMasked;
}
}
+
/**
* Sends down events to the view hierarchy for all pointers which are not already being
* delivered i.e. pointers that are not yet injected.
@@ -285,6 +286,79 @@ class EventDispatcher {
}
/**
+ * Sends down events to the view hierarchy for all pointers which are not already being
+ * delivered with original down location. i.e. pointers that are not yet injected. The down time
+ * is also replaced by the original one.
+ *
+ *
+ * @param prototype The prototype from which to create the injected events.
+ * @param policyFlags The policy flags associated with the event.
+ */
+ void sendDownForAllNotInjectedPointersWithOriginalDown(MotionEvent prototype, int policyFlags) {
+ // Inject the injected pointers.
+ int pointerIdBits = 0;
+ final int pointerCount = prototype.getPointerCount();
+ final MotionEvent event = computeInjectionDownEvent(prototype);
+ for (int i = 0; i < pointerCount; i++) {
+ final int pointerId = prototype.getPointerId(i);
+ // Do not send event for already delivered pointers.
+ if (!mState.isInjectedPointerDown(pointerId)) {
+ pointerIdBits |= (1 << pointerId);
+ final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
+ sendMotionEvent(
+ event,
+ action,
+ mState.getLastReceivedEvent(),
+ pointerIdBits,
+ policyFlags);
+ }
+ }
+ }
+
+ private MotionEvent computeInjectionDownEvent(MotionEvent prototype) {
+ final int pointerCount = prototype.getPointerCount();
+ if (pointerCount != mState.getReceivedPointerTracker().getReceivedPointerDownCount()) {
+ Slog.w(LOG_TAG, "The pointer count doesn't match the received count.");
+ return MotionEvent.obtain(prototype);
+ }
+ MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[pointerCount];
+ MotionEvent.PointerProperties[] properties =
+ new MotionEvent.PointerProperties[pointerCount];
+ for (int i = 0; i < pointerCount; ++i) {
+ final int pointerId = prototype.getPointerId(i);
+ final float x = mState.getReceivedPointerTracker().getReceivedPointerDownX(pointerId);
+ final float y = mState.getReceivedPointerTracker().getReceivedPointerDownY(pointerId);
+ coords[i] = new MotionEvent.PointerCoords();
+ coords[i].x = x;
+ coords[i].y = y;
+ properties[i] = new MotionEvent.PointerProperties();
+ properties[i].id = pointerId;
+ properties[i].toolType = MotionEvent.TOOL_TYPE_FINGER;
+ }
+ MotionEvent event =
+ MotionEvent.obtain(
+ prototype.getDownTime(),
+ // The event time is used for downTime while sending ACTION_DOWN. We adjust
+ // it to avoid the motion velocity is too fast in the beginning after
+ // Delegating.
+ prototype.getDownTime(),
+ prototype.getAction(),
+ pointerCount,
+ properties,
+ coords,
+ prototype.getMetaState(),
+ prototype.getButtonState(),
+ prototype.getXPrecision(),
+ prototype.getYPrecision(),
+ prototype.getDeviceId(),
+ prototype.getEdgeFlags(),
+ prototype.getSource(),
+ prototype.getFlags());
+ return event;
+ }
+
+ /**
+ *
* Sends up events to the view hierarchy for all pointers which are already being delivered i.e.
* pointers that are injected.
*
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
index 07e82111d4e5..5b46cb4ab378 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
@@ -294,7 +294,7 @@ class MultiFingerSwipe extends GestureMatcher {
+ Float.toString(mGestureDetectionThresholdPixels));
}
if (getState() == STATE_CLEAR) {
- if (moveDelta < mTouchSlop) {
+ if (moveDelta < (mTargetFingerCount * mTouchSlop)) {
// This still counts as a touch not a swipe.
continue;
} else if (mStrokeBuffers[pointerIndex].size() == 0) {
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index d127172c3aa6..8305be393ab1 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -608,7 +608,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
mReceivedPointerTracker.getReceivedPointerDownY(id)
- rawEvent.getY(index);
final double moveDelta = Math.hypot(deltaX, deltaY);
- if (moveDelta < mTouchSlop) {
+ if (moveDelta < (2 * mTouchSlop)) {
return;
}
}
@@ -644,23 +644,20 @@ public class TouchExplorer extends BaseEventStreamTransformation
if (mGestureDetector.isMultiFingerGesturesEnabled()) {
if (mGestureDetector.isTwoFingerPassthroughEnabled()) {
if (event.getPointerCount() == 3) {
- boolean isOnBottomEdge = true;
// If three fingers went down on the bottom edge of the screen, delegate
// immediately.
- final long screenHeight =
- mContext.getResources().getDisplayMetrics().heightPixels;
- for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) {
- if (mReceivedPointerTracker.getReceivedPointerDownY(i)
- < (screenHeight - mEdgeSwipeHeightPixels)) {
- isOnBottomEdge = false;
- }
- }
- if (isOnBottomEdge) {
+ if (allPointersDownOnBottomEdge(event)) {
if (DEBUG) {
Slog.d(LOG_TAG, "Three-finger edge swipe detected.");
}
mState.startDelegating();
- mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
+ if (mState.isTouchExploring()) {
+ mDispatcher.sendDownForAllNotInjectedPointers(event,
+ policyFlags);
+ } else {
+ mDispatcher.sendDownForAllNotInjectedPointersWithOriginalDown(
+ event, policyFlags);
+ }
}
}
}
@@ -1063,6 +1060,22 @@ public class TouchExplorer extends BaseEventStreamTransformation
return downEvent;
}
+ private boolean allPointersDownOnBottomEdge(MotionEvent event) {
+ final long screenHeight =
+ mContext.getResources().getDisplayMetrics().heightPixels;
+ for (int i = 0; i < event.getPointerCount(); ++i) {
+ final int pointerId = event.getPointerId(i);
+ final float pointerDownY = mReceivedPointerTracker.getReceivedPointerDownY(pointerId);
+ if (pointerDownY < (screenHeight - mEdgeSwipeHeightPixels)) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "The pointer is not on the bottom edge" + pointerDownY);
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
public TouchState getState() {
return mState;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
index 49a85864407b..a401bcd3eabd 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
@@ -19,6 +19,8 @@ package com.android.server.accessibility.magnification;
import static android.os.IBinder.DeathRecipient;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Slog;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -47,9 +49,10 @@ class WindowMagnificationConnectionWrapper {
mConnection.asBinder().linkToDeath(deathRecipient, 0);
}
- boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
+ boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+ @Nullable RemoteCallback endCallback) {
try {
- mConnection.enableWindowMagnification(displayId, scale, centerX, centerY);
+ mConnection.enableWindowMagnification(displayId, scale, centerX, centerY, endCallback);
} catch (RemoteException e) {
if (DBG) {
Slog.e(TAG, "Error calling enableWindowMagnification()", e);
@@ -71,9 +74,9 @@ class WindowMagnificationConnectionWrapper {
return true;
}
- boolean disableWindowMagnification(int displayId) {
+ boolean disableWindowMagnification(int displayId, @Nullable RemoteCallback endCallback) {
try {
- mConnection.disableWindowMagnification(displayId);
+ mConnection.disableWindowMagnification(displayId, endCallback);
} catch (RemoteException e) {
if (DBG) {
Slog.e(TAG, "Error calling disableWindowMagnification()", e);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 3ee5b28ee338..7d6067c8e1da 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -176,7 +176,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
Slog.i(LOG_TAG, "onDestroy(); delayed = "
+ mDetectingState.toString());
}
- mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, true);
+ mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
resetToDetectState();
}
@@ -211,14 +211,14 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
final float scale = MathUtils.constrain(
mWindowMagnificationMgr.getPersistedScale(),
MIN_SCALE, MAX_SCALE);
- mWindowMagnificationMgr.enableWindowMagnifier(mDisplayId, scale, centerX, centerY);
+ mWindowMagnificationMgr.enableWindowMagnification(mDisplayId, scale, centerX, centerY);
}
private void disableWindowMagnifier() {
if (DEBUG_ALL) {
Slog.i(LOG_TAG, "disableWindowMagnifier()");
}
- mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, false);
+ mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, false);
}
private void toggleMagnification(float centerX, float centerY) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index ed2b26f24478..d3d56d7f857d 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -24,6 +24,7 @@ import android.content.IntentFilter;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.MathUtils;
@@ -73,7 +74,7 @@ public class WindowMagnificationManager implements
public void onReceive(Context context, Intent intent) {
final int displayId = context.getDisplayId();
removeMagnificationButton(displayId);
- disableWindowMagnification(displayId);
+ disableWindowMagnification(displayId, false);
}
};
@@ -84,6 +85,7 @@ public class WindowMagnificationManager implements
/**
* Sets {@link IWindowMagnificationConnection}.
+ *
* @param connection {@link IWindowMagnificationConnection}
*/
public void setConnection(@Nullable IWindowMagnificationConnection connection) {
@@ -124,7 +126,6 @@ public class WindowMagnificationManager implements
}
/**
- *
* @return {@code true} if {@link IWindowMagnificationConnection} is available
*/
public boolean isConnected() {
@@ -136,10 +137,10 @@ public class WindowMagnificationManager implements
/**
* Requests {@link IWindowMagnificationConnection} through
* {@link StatusBarManagerInternal#requestWindowMagnificationConnection(boolean)} and
- * destroys all window magnifiers if necessary.
+ * destroys all window magnifications if necessary.
*
* @param connect {@code true} if needs connection, otherwise set the connection to null and
- * destroy all window magnifiers.
+ * destroy all window magnifications.
* @return {@code true} if {@link IWindowMagnificationConnection} state is going to change.
*/
public boolean requestConnection(boolean connect) {
@@ -171,7 +172,7 @@ public class WindowMagnificationManager implements
private void disableAllWindowMagnifiers() {
for (int i = 0; i < mWindowMagnifiers.size(); i++) {
final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i);
- magnifier.disable();
+ magnifier.disableWindowMagnificationInternal(null);
}
mWindowMagnifiers.clear();
}
@@ -187,12 +188,12 @@ public class WindowMagnificationManager implements
@Override
public boolean processScroll(int displayId, float distanceX, float distanceY) {
- moveWindowMagnifier(displayId, -distanceX, -distanceY);
+ moveWindowMagnification(displayId, -distanceX, -distanceY);
return /* event consumed: */ true;
}
/**
- * Scales the magnified region on the specified display if the window magnifier is enabled.
+ * Scales the magnified region on the specified display if window magnification is initiated.
*
* @param displayId The logical display id.
* @param scale The target scale, must be >= 1
@@ -209,37 +210,69 @@ public class WindowMagnificationManager implements
}
/**
- * Enables the window magnifier with specified center and scale on the specified display.
- * @param displayId The logical display id.
+ * Enables window magnification with specified center and scale on the given display and
+ * animating the transition.
+ *
+ * @param displayId The logical display id.
+ * @param scale The target scale, must be >= 1.
+ * @param centerX The screen-relative X coordinate around which to center,
+ * or {@link Float#NaN} to leave unchanged.
+ * @param centerY The screen-relative Y coordinate around which to center,
+ * or {@link Float#NaN} to leave unchanged.
+ */
+ void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
+ enableWindowMagnification(displayId, scale, centerX, centerY, null);
+ }
+
+ /**
+ * Enables window magnification with specified center and scale on the specified display and
+ * animating the transition.
+ *
+ * @param displayId The logical display id.
* @param scale The target scale, must be >= 1.
* @param centerX The screen-relative X coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
* @param centerY The screen-relative Y coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
+ * @param endCallback Called when the animation is ended without any interruption or the
+ * window magnifier is disabled already.
*/
- void enableWindowMagnifier(int displayId, float scale, float centerX, float centerY) {
+ void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
+ @Nullable Runnable endCallback) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
magnifier = createWindowMagnifier(displayId);
}
- magnifier.enable(scale, centerX, centerY);
+ magnifier.enableWindowMagnificationInternal(scale, centerX, centerY, endCallback);
}
}
/**
- * Disables the window magnifier on the specified display.
+ * Disables window magnification on the given display.
+ *
+ * @param displayId The logical display id.
+ * @param clear {@true} Clears the state of window magnification.
+ */
+ void disableWindowMagnification(int displayId, boolean clear) {
+ disableWindowMagnification(displayId, clear, null);
+ }
+
+ /**
+ * Disables window magnification on the specified display and animating the transition.
*
* @param displayId The logical display id.
- * @param clear {@true} Clears the state of the window magnifier
+ * @param clear {@true} Clears the state of window magnification.
+ * @param endCallback Called when the animation is ended without any interruption or the
+ * window magnifier is disabled already.
*/
- void disableWindowMagnifier(int displayId, boolean clear) {
+ void disableWindowMagnification(int displayId, boolean clear, Runnable endCallback) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
return;
}
- magnifier.disable();
+ magnifier.disableWindowMagnificationInternal(endCallback);
if (clear) {
mWindowMagnifiers.delete(displayId);
}
@@ -264,10 +297,10 @@ public class WindowMagnificationManager implements
}
/**
- * Indicates whether this window magnifier is enabled on specified display.
+ * Indicates whether window magnification is enabled on specified display.
*
* @param displayId The logical display id.
- * @return {@code true} if the window magnifier is enabled.
+ * @return {@code true} if the window magnification is enabled.
*/
boolean isWindowMagnifierEnabled(int displayId) {
synchronized (mLock) {
@@ -323,7 +356,7 @@ public class WindowMagnificationManager implements
}
/**
- * Moves the window magnifier with specified offset.
+ * Moves window magnification on the specified display with the specified offset.
*
* @param displayId The logical display id.
* @param offsetX the amount in pixels to offset the region in the X direction, in current
@@ -331,7 +364,7 @@ public class WindowMagnificationManager implements
* @param offsetY the amount in pixels to offset the region in the Y direction, in current
* screen pixels.
*/
- void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
+ void moveWindowMagnification(int displayId, float offsetX, float offsetY) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
@@ -366,6 +399,7 @@ public class WindowMagnificationManager implements
/**
* Creates the windowMagnifier based on the specified display and stores it.
+ *
* @param displayId logical display id.
*/
@GuardedBy("mLock")
@@ -425,7 +459,8 @@ public class WindowMagnificationManager implements
}
/**
- * A class to manipulate the window magnifier and contains the relevant information.
+ * A class manipulates window magnification per display and contains the magnification
+ * information.
*/
private static class WindowMagnifier {
@@ -434,31 +469,34 @@ public class WindowMagnificationManager implements
private boolean mEnabled;
private final WindowMagnificationManager mWindowMagnificationManager;
- //Records the bounds of window magnifier.
+ //Records the bounds of window magnification.
private final Rect mBounds = new Rect();
//The magnified bounds on the screen.
private final Rect mSourceBounds = new Rect();
+
WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
mDisplayId = displayId;
mWindowMagnificationManager = windowMagnificationManager;
}
@GuardedBy("mLock")
- void enable(float scale, float centerX, float centerY) {
+ void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
+ @Nullable Runnable endCallback) {
if (mEnabled) {
return;
}
final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
- if (mWindowMagnificationManager.enableWindowMagnification(mDisplayId, normScale,
- centerX, centerY)) {
+ if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale,
+ centerX, centerY, endCallback)) {
mScale = normScale;
mEnabled = true;
}
}
@GuardedBy("mLock")
- void disable() {
- if (mEnabled && mWindowMagnificationManager.disableWindowMagnification(mDisplayId)) {
+ void disableWindowMagnificationInternal(@Nullable Runnable endCallback) {
+ if (mEnabled && mWindowMagnificationManager.disableWindowMagnificationInternal(
+ mDisplayId, endCallback)) {
mEnabled = false;
}
}
@@ -519,19 +557,21 @@ public class WindowMagnificationManager implements
}
}
- private boolean enableWindowMagnification(int displayId, float scale, float centerX,
- float centerY) {
+ private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX,
+ float centerY, Runnable endCallback) {
return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
- displayId, scale, centerX, centerY);
+ displayId, scale, centerX, centerY,
+ endCallback != null ? new RemoteCallback(bundle -> endCallback.run()) : null);
}
private boolean setScaleInternal(int displayId, float scale) {
return mConnectionWrapper != null && mConnectionWrapper.setScale(displayId, scale);
}
- private boolean disableWindowMagnification(int displayId) {
+ private boolean disableWindowMagnificationInternal(int displayId, Runnable endCallback) {
return mConnectionWrapper != null && mConnectionWrapper.disableWindowMagnification(
- displayId);
+ displayId,
+ endCallback != null ? new RemoteCallback(bundle -> endCallback.run()) : null);
}
private boolean moveWindowMagnifierInternal(int displayId, float offsetX, float offsetY) {
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index b9625397d237..16077cb6082f 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -228,7 +228,7 @@ public class FullRestoreEngine extends RestoreEngine {
PackageManagerInternal.class);
RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
mBackupManagerService.getPackageManager(), allowApks, info, signatures,
- pmi, mUserId);
+ pmi, mUserId, mBackupEligibilityRules);
mManifestSignatures.put(info.packageName, signatures);
mPackagePolicies.put(pkg, restorePolicy);
mPackageInstallers.put(pkg, info.installerPackageName);
diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
index 3789fa14e87b..6963248734a3 100644
--- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
+++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
@@ -389,13 +389,29 @@ public class TarBackupReader {
public RestorePolicy chooseRestorePolicy(PackageManager packageManager,
boolean allowApks, FileMetadata info, Signature[] signatures,
PackageManagerInternal pmi, int userId) {
+ return chooseRestorePolicy(packageManager, allowApks, info, signatures, pmi, userId,
+ BackupEligibilityRules.forBackup(packageManager, pmi, userId));
+ }
+
+ /**
+ * Chooses restore policy.
+ *
+ * @param packageManager - PackageManager instance.
+ * @param allowApks - allow restore set to include apks.
+ * @param info - file metadata.
+ * @param signatures - array of signatures parsed from backup file.
+ * @param userId - ID of the user for which restore is performed.
+ * @param eligibilityRules - {@link BackupEligibilityRules} for this operation.
+ * @return a restore policy constant.
+ */
+ public RestorePolicy chooseRestorePolicy(PackageManager packageManager,
+ boolean allowApks, FileMetadata info, Signature[] signatures,
+ PackageManagerInternal pmi, int userId, BackupEligibilityRules eligibilityRules) {
if (signatures == null) {
return RestorePolicy.IGNORE;
}
RestorePolicy policy = RestorePolicy.IGNORE;
- BackupEligibilityRules eligibilityRules = BackupEligibilityRules.forBackup(packageManager,
- pmi, userId);
// Okay, got the manifest info we need...
try {
PackageInfo pkgInfo = packageManager.getPackageInfoAsUser(
diff --git a/services/companion/TEST_MAPPING b/services/companion/TEST_MAPPING
new file mode 100644
index 000000000000..63f54fa35158
--- /dev/null
+++ b/services/companion/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {
+ "include-filter": "android.os.cts.CompanionDeviceManagerTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index eb38f5199ce5..7b9728cb4f08 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -393,12 +393,14 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
.toString());
long identity = Binder.clearCallingIdentity();
try {
- return PendingIntent.getActivity(getContext(),
+ return PendingIntent.getActivityAsUser(getContext(),
0 /* request code */,
NotificationAccessConfirmationActivityContract.launcherIntent(
userId, component, packageTitle),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_CANCEL_CURRENT);
+ | PendingIntent.FLAG_CANCEL_CURRENT,
+ null /* options */,
+ new UserHandle(userId));
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -612,8 +614,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
}
- private AtomicFile getStorageFileForUser(int uid) {
- return mUidToStorage.computeIfAbsent(uid, (u) ->
+ private AtomicFile getStorageFileForUser(int userId) {
+ return mUidToStorage.computeIfAbsent(userId, (u) ->
new AtomicFile(new File(
//TODO deprecated method - what's the right replacement?
Environment.getUserSystemDirectory(u),
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f372c6f85ec6..0d79240a4b59 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -166,6 +166,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private String mAddress;
private String mName;
private final ContentResolver mContentResolver;
+ private final int mUserId;
private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
private IBinder mBluetoothBinder;
@@ -481,6 +482,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mName = null;
mErrorRecoveryRetryCounter = 0;
mContentResolver = context.getContentResolver();
+ mUserId = mContentResolver.getUserId();
// Observe BLE scan only mode settings change.
registerForBleScanModeChange();
mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
@@ -625,7 +627,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
if (mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation)
- && Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0)
+ && Settings.Secure.getIntForUser(mContentResolver,
+ SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0, mUserId)
== 0) {
// if the valid flag is not set, don't load the address and name
if (DBG) {
@@ -633,8 +636,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
return;
}
- mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
- mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
+ mName = Settings.Secure.getStringForUser(
+ mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, mUserId);
+ mAddress = Settings.Secure.getStringForUser(
+ mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, mUserId);
if (DBG) {
Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
}
@@ -648,26 +653,31 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
*/
private void storeNameAndAddress(String name, String address) {
if (name != null) {
- Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
+ Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name,
+ mUserId);
mName = name;
if (DBG) {
- Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getString(mContentResolver,
- SECURE_SETTINGS_BLUETOOTH_NAME));
+ Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getStringForUser(
+ mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME,
+ mUserId));
}
}
if (address != null) {
- Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
+ Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS,
+ address, mUserId);
mAddress = address;
if (DBG) {
Slog.d(TAG,
- "Stored Bluetoothaddress: " + Settings.Secure.getString(mContentResolver,
- SECURE_SETTINGS_BLUETOOTH_ADDRESS));
+ "Stored Bluetoothaddress: " + Settings.Secure.getStringForUser(
+ mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS,
+ mUserId));
}
}
if ((name != null) && (address != null)) {
- Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
+ Settings.Secure.putIntForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1,
+ mUserId);
}
}
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index b09b2605a791..500e768372f5 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -126,6 +126,16 @@ public class DynamicSystemService extends IDynamicSystemService.Stub {
}
@Override
+ public boolean closePartition() throws RemoteException {
+ IGsiService service = getGsiService();
+ if (service.closePartition() != 0) {
+ Slog.i(TAG, "Partition installation completes with error");
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public boolean finishInstallation() throws RemoteException {
IGsiService service = getGsiService();
if (service.closeInstall() != 0) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index eb8308b56f2e..e433fbd94d4f 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -64,6 +64,7 @@ import android.telephony.DisconnectCause;
import android.telephony.LocationAccessPolicy;
import android.telephony.PhoneCapability;
import android.telephony.PhoneStateListener;
+import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.PreciseDisconnectCause;
@@ -142,13 +143,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
int callerUid;
int callerPid;
- int events;
+ long events;
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
- boolean matchPhoneStateListenerEvent(int events) {
+ boolean matchPhoneStateListenerEvent(long events) {
return (callback != null) && ((events & this.events) != 0);
}
@@ -177,7 +178,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ onSubscriptionsChangedListenerCallback
+ " onOpportunisticSubscriptionsChangedListenererCallback="
+ onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId
- + " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + "}";
+ + " phoneId=" + phoneId + " events=" + Long.toHexString(events) + "}";
}
}
@@ -306,6 +307,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private final LocalLog mListenLog = new LocalLog(00);
+ private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
+
/**
* Per-phone map of precise data connection state. The key of the map is the pair of transport
* type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
@@ -318,19 +321,19 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
// Starting in Q, almost all cellular location requires FINE location enforcement.
// Prior to Q, cellular was available with COARSE location enforcement. Bits in this
// list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later.
- static final int ENFORCE_LOCATION_PERMISSION_MASK =
+ static final long ENFORCE_LOCATION_PERMISSION_MASK =
PhoneStateListener.LISTEN_CELL_LOCATION
| PhoneStateListener.LISTEN_CELL_INFO
| PhoneStateListener.LISTEN_REGISTRATION_FAILURE
| PhoneStateListener.LISTEN_BARRING_INFO;
- static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
+ static final long ENFORCE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
| PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
| PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
| PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED;
- static final int ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK =
+ static final long ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE
| PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
@@ -339,11 +342,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
| PhoneStateListener.LISTEN_REGISTRATION_FAILURE
| PhoneStateListener.LISTEN_BARRING_INFO;
- static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK =
+ static final long READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK =
PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL
| PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS;
- static final int READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK =
+ static final long READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT
| PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED
| PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED
@@ -495,6 +498,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
cutListToSize(mImsReasonInfo, mNumPhones);
cutListToSize(mPreciseDataConnectionStates, mNumPhones);
cutListToSize(mBarringInfo, mNumPhones);
+ cutListToSize(mPhysicalChannelConfigs, mNumPhones);
return;
}
@@ -528,6 +532,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mPreciseDataConnectionStates.add(new ArrayMap<>());
mBarringInfo.add(i, new BarringInfo());
mTelephonyDisplayInfos[i] = null;
+ mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig(
+ PhysicalChannelConfig.CONNECTION_UNKNOWN,0));
}
}
@@ -588,6 +594,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mOutgoingSmsEmergencyNumber = new EmergencyNumber[numPhones];
mBarringInfo = new ArrayList<>();
mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones];
+ mPhysicalChannelConfigs = new ArrayList<>();
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -617,6 +624,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mPreciseDataConnectionStates.add(new ArrayMap<>());
mBarringInfo.add(i, new BarringInfo());
mTelephonyDisplayInfos[i] = null;
+ mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig(
+ PhysicalChannelConfig.CONNECTION_UNKNOWN,0));
}
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -795,23 +804,23 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
@Override
public void listenWithFeature(String callingPackage, String callingFeatureId,
- IPhoneStateListener callback, int events, boolean notifyNow) {
+ IPhoneStateListener callback, long events, boolean notifyNow) {
listenForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, callingPackage,
callingFeatureId, callback, events, notifyNow);
}
@Override
public void listenForSubscriber(int subId, String callingPackage, String callingFeatureId,
- IPhoneStateListener callback, int events, boolean notifyNow) {
+ IPhoneStateListener callback, long events, boolean notifyNow) {
listen(callingPackage, callingFeatureId, callback, events, notifyNow, subId);
}
private void listen(String callingPackage, @Nullable String callingFeatureId,
- IPhoneStateListener callback, int events, boolean notifyNow, int subId) {
+ IPhoneStateListener callback, long events, boolean notifyNow, int subId) {
int callerUserId = UserHandle.getCallingUserId();
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
String str = "listen: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
- + " events=0x" + Integer.toHexString(events) + " notifyNow=" + notifyNow + " subId="
+ + " events=0x" + Long.toHexString(events) + " notifyNow=" + notifyNow + " subId="
+ subId + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId;
mListenLog.log(str);
if (VDBG) {
@@ -1098,6 +1107,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION) != 0) {
+ try {
+ r.callback.onPhysicalChannelConfigurationChanged(
+ mPhysicalChannelConfigs);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -2258,6 +2275,47 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ /**
+ * Send a notification to registrants that the configs of physical channel has changed for
+ * a particular subscription.
+ *
+ * @param subId the subId
+ * @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel.
+ */
+ public void notifyPhysicalChannelConfigurationForSubscriber(
+ int subId, List<PhysicalChannelConfig> configs) {
+ if (!checkNotifyPermission("notifyPhysicalChannelConfiguration()")) {
+ return;
+ }
+
+ if (VDBG) {
+ log("notifyPhysicalChannelConfiguration: subId=" + subId + " configs=" + configs);
+ }
+
+ synchronized (mRecords) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mPhysicalChannelConfigs.set(phoneId, configs.get(phoneId));
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION)
+ && idMatch(r.subId, subId, phoneId)) {
+ try {
+ if (DBG_LOC) {
+ log("notifyPhysicalChannelConfiguration: "
+ + "mPhysicalChannelConfigs="
+ + configs + " r=" + r);
+ }
+ r.callback.onPhysicalChannelConfigurationChanged(configs);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -2310,6 +2368,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
pw.println("mDefaultPhoneId=" + mDefaultPhoneId);
pw.println("mDefaultSubId=" + mDefaultSubId);
+ pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs);
pw.decreaseIndent();
@@ -2536,7 +2595,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
== PackageManager.PERMISSION_GRANTED;
}
- private boolean checkListenerPermission(int events, int subId, String callingPackage,
+ private boolean checkListenerPermission(long events, int subId, String callingPackage,
@Nullable String callingFeatureId, String message) {
LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder =
new LocationAccessPolicy.LocationPermissionQuery.Builder()
@@ -2742,7 +2801,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
private void checkPossibleMissNotify(Record r, int phoneId) {
- int events = r.events;
+ long events = r.events;
if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
try {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 6dbb1e922f60..bcb7bfacfaf3 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -489,6 +489,9 @@ final class UiModeManagerService extends SystemService {
* @return True if the new value is different from the old value. False otherwise.
*/
private boolean updateNightModeFromSettingsLocked(Context context, Resources res, int userId) {
+ if (mCarModeEnabled || mCar) {
+ return false;
+ }
int oldNightMode = mNightMode;
if (mSetupWizardComplete) {
mNightMode = Secure.getIntForUser(context.getContentResolver(),
@@ -1033,7 +1036,7 @@ final class UiModeManagerService extends SystemService {
private void persistNightMode(int user) {
// Only persist setting if not in car mode
- if (mCarModeEnabled) return;
+ if (mCarModeEnabled || mCar) return;
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE, mNightMode, user);
Secure.putLongForUser(getContext().getContentResolver(),
@@ -1046,7 +1049,7 @@ final class UiModeManagerService extends SystemService {
private void persistNightModeOverrides(int user) {
// Only persist setting if not in car mode
- if (mCarModeEnabled) return;
+ if (mCarModeEnabled || mCar) return;
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE_OVERRIDE_ON, mOverrideNightModeOn ? 1 : 0, user);
Secure.putIntForUser(getContext().getContentResolver(),
@@ -1097,7 +1100,7 @@ final class UiModeManagerService extends SystemService {
}
// Override night mode in power save mode if not in car mode
- if (mPowerSave && !mCarModeEnabled) {
+ if (mPowerSave && !mCarModeEnabled && !mCar) {
uiMode &= ~Configuration.UI_MODE_NIGHT_NO;
uiMode |= Configuration.UI_MODE_NIGHT_YES;
} else {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 35e88eb804cb..7d81d412e369 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2114,7 +2114,7 @@ public class AccountManagerService
* Owner or system user account was renamed, rename the account for
* those users with which the account was shared.
*/
- List<UserInfo> users = getUserManager().getUsers(true);
+ List<UserInfo> users = getUserManager().getAliveUsers();
for (UserInfo user : users) {
if (user.isRestricted()
&& (user.restrictedProfileParentId == parentUserId)) {
@@ -2373,7 +2373,7 @@ public class AccountManagerService
int parentUserId = accounts.userId;
if (canHaveProfile(parentUserId)) {
// Remove from any restricted profiles that are sharing this account.
- List<UserInfo> users = getUserManager().getUsers(true);
+ List<UserInfo> users = getUserManager().getAliveUsers();
for (UserInfo user : users) {
if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
removeSharedAccountAsUser(account, user.id, callingUid);
@@ -4267,7 +4267,7 @@ public class AccountManagerService
*/
@NonNull
public AccountAndUser[] getAllAccounts() {
- final List<UserInfo> users = getUserManager().getUsers(true);
+ final List<UserInfo> users = getUserManager().getAliveUsers();
final int[] userIds = new int[users.size()];
for (int i = 0; i < userIds.length; i++) {
userIds[i] = users.get(i).id;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c31d73246ff6..343e05d982fd 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2268,21 +2268,23 @@ public final class ActiveServices {
clist.remove(0);
}
- if (r.binding.service.app != null) {
- if (r.binding.service.app.whitelistManager) {
- updateWhitelistManagerLocked(r.binding.service.app);
+ final ProcessRecord app = r.binding.service.app;
+ if (app != null) {
+ if (app.whitelistManager) {
+ updateWhitelistManagerLocked(app);
}
// This could have made the service less important.
if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
- r.binding.service.app.treatLikeActivity = true;
- mAm.updateLruProcessLocked(r.binding.service.app,
- r.binding.service.app.hasClientActivities()
- || r.binding.service.app.treatLikeActivity, null);
+ app.treatLikeActivity = true;
+ mAm.updateLruProcessLocked(app,
+ app.hasClientActivities()
+ || app.treatLikeActivity, null);
}
+ mAm.enqueueOomAdjTargetLocked(app);
}
}
- mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2d803437beb9..a5d2011483bc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2103,17 +2103,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"meminfo", pw)) return;
PriorityDump.dump(mPriorityDumper, fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -2127,17 +2123,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"gfxinfo", pw)) return;
mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -2151,17 +2143,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"dbinfo", pw)) return;
mActivityManagerService.dumpDbInfo(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -2207,9 +2195,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"cacheinfo", pw)) {
@@ -2218,9 +2204,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mActivityManagerService.dumpBinderCacheContents(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -5686,8 +5670,8 @@ public class ActivityManagerService extends IActivityManager.Stub
"setProcessLimit()");
synchronized (this) {
mConstants.setOverrideMaxCachedProcesses(max);
+ trimApplicationsLocked(true, OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
}
- trimApplications(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
}
@Override
@@ -5778,9 +5762,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private boolean isAppBad(final String processName, final int uid) {
- synchronized (this) {
- return mAppErrors.isBadProcessLocked(processName, uid);
- }
+ return mAppErrors.isBadProcess(processName, uid);
}
// NOTE: this is an internal method used by the OnShellCommand implementation only and should
@@ -13995,7 +13977,8 @@ public class ActivityManagerService extends IActivityManager.Stub
r.resultAbort, false);
if (doNext) {
doTrim = true;
- r.queue.processNextBroadcast(false);
+ r.queue.processNextBroadcastLocked(/* frommsg */ false,
+ /* skipOomAdj */ true);
}
}
@@ -14008,13 +13991,13 @@ public class ActivityManagerService extends IActivityManager.Stub
rl.receiver.asBinder().unlinkToDeath(rl, 0);
}
}
- }
- // If we actually concluded any broadcasts, we might now be able
- // to trim the recipients' apps from our working set
- if (doTrim) {
- trimApplications(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
- return;
+ // If we actually concluded any broadcasts, we might now be able
+ // to trim the recipients' apps from our working set
+ if (doTrim) {
+ trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
+ return;
+ }
}
} finally {
@@ -15145,7 +15128,7 @@ public class ActivityManagerService extends IActivityManager.Stub
r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
}
// updateOomAdjLocked() will be done here
- trimApplicationsLocked(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
+ trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
}
} finally {
@@ -16155,6 +16138,32 @@ public class ActivityManagerService extends IActivityManager.Stub
return mOomAdjuster.updateOomAdjLocked(app, oomAdjAll, oomAdjReason);
}
+ /**
+ * Enqueue the given process into a todo list, and the caller should
+ * call {@link #updateOomAdjPendingTargetsLocked} to kick off a pass of the oom adj update.
+ */
+ @GuardedBy("this")
+ void enqueueOomAdjTargetLocked(ProcessRecord app) {
+ mOomAdjuster.enqueueOomAdjTargetLocked(app);
+ }
+
+ /**
+ * Remove the given process into a todo list.
+ */
+ @GuardedBy("this")
+ void removeOomAdjTargetLocked(ProcessRecord app, boolean procDied) {
+ mOomAdjuster.removeOomAdjTargetLocked(app, procDied);
+ }
+
+ /**
+ * Kick off an oom adj update pass for the pending targets which are enqueued via
+ * {@link #enqueueOomAdjTargetLocked}.
+ */
+ @GuardedBy("this")
+ void updateOomAdjPendingTargetsLocked(String oomAdjReason) {
+ mOomAdjuster.updateOomAdjPendingTargetsLocked(oomAdjReason);
+ }
+
static final class ProcStatsRunnable implements Runnable {
private final ActivityManagerService mService;
private final ProcessStatsService mProcessStats;
@@ -16563,16 +16572,17 @@ public class ActivityManagerService extends IActivityManager.Stub
mOomAdjuster.setUidTempWhitelistStateLocked(uid, onWhitelist);
}
- final void trimApplications(String oomAdjReason) {
+ private void trimApplications(boolean forceFullOomAdj, String oomAdjReason) {
synchronized (this) {
- trimApplicationsLocked(oomAdjReason);
+ trimApplicationsLocked(forceFullOomAdj, oomAdjReason);
}
}
@GuardedBy("this")
- final void trimApplicationsLocked(String oomAdjReason) {
+ private void trimApplicationsLocked(boolean forceFullOomAdj, String oomAdjReason) {
// First remove any unused application processes whose package
// has been removed.
+ boolean didSomething = false;
for (int i = mProcessList.mRemovedProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord app = mProcessList.mRemovedProcesses.get(i);
if (!app.hasActivitiesOrRecentTasks()
@@ -16594,6 +16604,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Ignore exceptions.
}
}
+ didSomething = true;
cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/);
mProcessList.mRemovedProcesses.remove(i);
@@ -16606,7 +16617,12 @@ public class ActivityManagerService extends IActivityManager.Stub
// Now update the oom adj for all processes. Don't skip this, since other callers
// might be depending on it.
- updateOomAdjLocked(oomAdjReason);
+ if (didSomething || forceFullOomAdj) {
+ updateOomAdjLocked(oomAdjReason);
+ } else {
+ // Process any pending oomAdj targets, it'll be a no-op if nothing is pending.
+ updateOomAdjPendingTargetsLocked(oomAdjReason);
+ }
}
/** This method sends the specified signal to each of the persistent apps */
@@ -16800,14 +16816,14 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- Process.enableFreezer(false);
+ mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
final RemoteCallback intermediateCallback = new RemoteCallback(
new RemoteCallback.OnResultListener() {
@Override
public void onResult(Bundle result) {
finishCallback.sendResult(result);
- Process.enableFreezer(true);
+ mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}, null);
@@ -17144,8 +17160,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int checkContentProviderUriPermission(Uri uri, int userId,
int callingUid, int modeFlags) {
- return mCpHelper.checkContentProviderUriPermission(uri,
- userId, callingUid, modeFlags);
+ return mCpHelper.checkContentProviderUriPermission(uri, userId, callingUid, modeFlags);
}
@Override
@@ -17412,7 +17427,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void trimApplications() {
- ActivityManagerService.this.trimApplications(OomAdjuster.OOM_ADJ_REASON_ACTIVITY);
+ ActivityManagerService.this.trimApplications(true, OomAdjuster.OOM_ADJ_REASON_ACTIVITY);
}
public void killProcessesForRemovedTask(ArrayList<Object> procsToKill) {
@@ -18738,4 +18753,16 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppErrors.resetStateLocked();
}
}
+
+ @Override
+ public boolean enableAppFreezer(boolean enable) {
+ int callerUid = Binder.getCallingUid();
+
+ // Only system can toggle the freezer state
+ if (callerUid == SYSTEM_UID) {
+ return mOomAdjuster.mCachedAppOptimizer.enableFreezer(enable);
+ } else {
+ throw new SecurityException("Caller uid " + callerUid + " cannot set freezer state ");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 5268359df327..5d429d3065f3 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -50,6 +50,7 @@ import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -96,7 +97,11 @@ class AppErrors {
* a minimum amount of time; they are removed from it when they are
* later restarted (hopefully due to some user action). The value is the
* time it was added to the list.
+ *
+ * Access is synchronized on the container object itself, and no other
+ * locks may be acquired while holding that one.
*/
+ @GuardedBy("mBadProcesses")
private final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<>();
@@ -114,76 +119,81 @@ class AppErrors {
mProcessCrashTimes.clear();
mProcessCrashTimesPersistent.clear();
mProcessCrashShowDialogTimes.clear();
- mBadProcesses.clear();
+ synchronized (mBadProcesses) {
+ mBadProcesses.clear();
+ }
}
void dumpDebug(ProtoOutputStream proto, long fieldId, String dumpPackage) {
- if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
- return;
- }
-
- final long token = proto.start(fieldId);
- final long now = SystemClock.uptimeMillis();
- proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
-
- if (!mProcessCrashTimes.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
- final int procCount = pmap.size();
- for (int ip = 0; ip < procCount; ip++) {
- final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<Long> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
+ synchronized (mBadProcesses) {
+ if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
+ return;
+ }
- proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null || !r.pkgList.containsKey(dumpPackage))) {
- continue;
+ final long token = proto.start(fieldId);
+ final long now = SystemClock.uptimeMillis();
+ proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
+
+ if (!mProcessCrashTimes.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+ final int procCount = pmap.size();
+ for (int ip = 0; ip < procCount; ip++) {
+ final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<Long> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
+
+ proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null
+ && (r == null || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
+ uids.valueAt(i));
+ proto.end(etoken);
}
- final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
- uids.valueAt(i));
- proto.end(etoken);
+ proto.end(ctoken);
}
- proto.end(ctoken);
- }
- }
+ }
- if (!mBadProcesses.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
- final int processCount = pmap.size();
- for (int ip = 0; ip < processCount; ip++) {
- final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
+ if (!mBadProcesses.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
+ final int processCount = pmap.size();
+ for (int ip = 0; ip < processCount; ip++) {
+ final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
- proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null
- || !r.pkgList.containsKey(dumpPackage))) {
- continue;
+ proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null && (r == null
+ || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ final BadProcessInfo info = uids.valueAt(i);
+ final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
+ proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
+ proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
+ proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
+ proto.end(etoken);
}
- final BadProcessInfo info = uids.valueAt(i);
- final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
- proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
- proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
- proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
- proto.end(etoken);
+ proto.end(btoken);
}
- proto.end(btoken);
}
- }
- proto.end(token);
+ proto.end(token);
+ }
}
boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) {
@@ -272,12 +282,16 @@ class AppErrors {
return needSep;
}
- boolean isBadProcessLocked(final String processName, final int uid) {
- return mBadProcesses.get(processName, uid) != null;
+ boolean isBadProcess(final String processName, final int uid) {
+ synchronized (mBadProcesses) {
+ return mBadProcesses.get(processName, uid) != null;
+ }
}
- void clearBadProcessLocked(final String processName, final int uid) {
- mBadProcesses.remove(processName, uid);
+ void clearBadProcess(final String processName, final int uid) {
+ synchronized (mBadProcesses) {
+ mBadProcesses.remove(processName, uid);
+ }
}
void resetProcessCrashTimeLocked(final String processName, final int uid) {
@@ -747,8 +761,10 @@ class AppErrors {
if (!app.isolated) {
// XXX We don't have a way to mark isolated processes
// as bad, since they don't have a peristent identity.
- mBadProcesses.put(app.processName, app.uid,
- new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+ synchronized (mBadProcesses) {
+ mBadProcesses.put(app.processName, app.uid,
+ new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+ }
mProcessCrashTimes.remove(app.processName, app.uid);
}
app.bad = true;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 960d26b5da34..6948f9061038 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -281,7 +281,7 @@ public final class BroadcastQueue {
}
private final void processCurBroadcastLocked(BroadcastRecord r,
- ProcessRecord app, boolean skipOomAdj) throws RemoteException {
+ ProcessRecord app) throws RemoteException {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " for app " + app);
if (app.thread == null) {
@@ -297,9 +297,11 @@ public final class BroadcastQueue {
app.curReceivers.add(r);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
mService.mProcessList.updateLruProcessLocked(app, false, null);
- if (!skipOomAdj) {
- mService.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
- }
+ // Make sure the oom adj score is updated before delivering the broadcast.
+ // Force an update, even if there are other pending requests, overall it still saves time,
+ // because time(updateOomAdj(N apps)) <= N * time(updateOomAdj(1 app)).
+ mService.enqueueOomAdjTargetLocked(app);
+ mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
// Tell the application to launch this receiver.
r.intent.setComponent(r.curComponent);
@@ -340,7 +342,7 @@ public final class BroadcastQueue {
}
try {
mPendingBroadcast = null;
- processCurBroadcastLocked(br, app, false);
+ processCurBroadcastLocked(br, app);
didSomething = true;
} catch (Exception e) {
Slog.w(TAG, "Exception in new application when starting receiver "
@@ -501,6 +503,7 @@ public final class BroadcastQueue {
r.intent.setComponent(null);
if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
r.curApp.curReceivers.remove(r);
+ mService.enqueueOomAdjTargetLocked(r.curApp);
}
if (r.curFilter != null) {
r.curFilter.receiverList.curBroadcast = null;
@@ -562,7 +565,7 @@ public final class BroadcastQueue {
Slog.i(TAG, "Resuming delayed broadcast");
br.curComponent = null;
br.state = BroadcastRecord.IDLE;
- processNextBroadcast(false);
+ processNextBroadcastLocked(false, false);
}
}
}
@@ -604,7 +607,7 @@ public final class BroadcastQueue {
}
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
- BroadcastFilter filter, boolean ordered, int index, boolean skipOomAdj) {
+ BroadcastFilter filter, boolean ordered, int index) {
boolean skip = false;
if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
filter.packageName, filter.owningUid)) {
@@ -790,10 +793,9 @@ public final class BroadcastQueue {
// are already core system stuff so don't matter for this.
r.curApp = filter.receiverList.app;
filter.receiverList.app.curReceivers.add(r);
- if (!skipOomAdj) {
- mService.updateOomAdjLocked(r.curApp, true,
- OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
- }
+ mService.enqueueOomAdjTargetLocked(r.curApp);
+ mService.updateOomAdjPendingTargetsLocked(
+ OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
}
}
try {
@@ -827,6 +829,8 @@ public final class BroadcastQueue {
filter.receiverList.app.removeAllowBackgroundActivityStartsToken(r);
if (ordered) {
filter.receiverList.app.curReceivers.remove(r);
+ // Something wrong, its oom adj could be downgraded, but not in a hurry.
+ mService.enqueueOomAdjTargetLocked(r.curApp);
}
}
// And BroadcastRecord state related to ordered delivery, if appropriate
@@ -946,7 +950,7 @@ public final class BroadcastQueue {
return true;
}
- final void processNextBroadcast(boolean fromMsg) {
+ private void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
@@ -990,7 +994,7 @@ public final class BroadcastQueue {
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r,
- (BroadcastFilter) target, false, i, skipOomAdj);
+ (BroadcastFilter) target, false, i);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
@@ -1046,7 +1050,8 @@ public final class BroadcastQueue {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
// adjustments.
- mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
+ mService.updateOomAdjPendingTargetsLocked(
+ OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
}
// when we have no more ordered broadcast on this queue, stop logging
@@ -1288,7 +1293,7 @@ public final class BroadcastQueue {
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
- deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx, skipOomAdj);
+ deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
@@ -1616,7 +1621,7 @@ public final class BroadcastQueue {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
maybeAddAllowBackgroundActivityStartsToken(app, r);
- processCurBroadcastLocked(r, app, skipOomAdj);
+ processCurBroadcastLocked(r, app);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when sending broadcast to "
@@ -1750,7 +1755,7 @@ public final class BroadcastQueue {
? r.curComponent.flattenToShortString() : "(null)"));
r.curComponent = null;
r.state = BroadcastRecord.IDLE;
- processNextBroadcast(false);
+ processNextBroadcastLocked(false, false);
return;
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index d9fde0f6728a..c5047e5eed03 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -208,6 +208,8 @@ public final class CachedAppOptimizer {
@GuardedBy("mPhenotypeFlagLock")
private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER;
+ @GuardedBy("this")
+ private int mFreezerDisableCount = 1; // Freezer is initially disabled, until enabled
private final Random mRandom = new Random();
@GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting volatile float mCompactStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
@@ -420,25 +422,82 @@ public final class CachedAppOptimizer {
}
/**
- * Determines whether the freezer is correctly supported by this system
+ * Enables or disabled the app freezer.
+ * @param enable Enables the freezer if true, disables it if false.
+ * @return true if the operation completed successfully, false otherwise.
+ */
+ public synchronized boolean enableFreezer(boolean enable) {
+ if (!mUseFreezer) {
+ return false;
+ }
+
+ if (enable) {
+ mFreezerDisableCount--;
+
+ if (mFreezerDisableCount > 0) {
+ return true;
+ } else if (mFreezerDisableCount < 0) {
+ Slog.e(TAG_AM, "unbalanced call to enableFreezer, ignoring");
+ mFreezerDisableCount = 0;
+ return false;
+ }
+ } else {
+ mFreezerDisableCount++;
+
+ if (mFreezerDisableCount > 1) {
+ return true;
+ }
+ }
+
+ try {
+ enableFreezerInternal(enable);
+ return true;
+ } catch (java.lang.RuntimeException e) {
+ if (enable) {
+ mFreezerDisableCount = 0;
+ } else {
+ mFreezerDisableCount = 1;
+ }
+
+ Slog.e(TAG_AM, "Exception handling freezer state (enable: " + enable + "): "
+ + e.toString());
+ }
+
+ return false;
+ }
+
+ /**
+ * Enable or disable the freezer. When enable == false all frozen processes are unfrozen,
+ * but aren't removed from the freezer. While in this state, processes can be added or removed
+ * by using Process.setProcessFrozen(), but they wouldn't be actually frozen until the freezer
+ * is enabled. If enable == true all processes in the freezer are frozen.
+ *
+ * @param enable Specify whether to enable (true) or disable (false) the freezer.
+ *
+ * @hide
+ */
+ private static native void enableFreezerInternal(boolean enable);
+
+ /**
+ * Determines whether the freezer is supported by this system
*/
public static boolean isFreezerSupported() {
boolean supported = false;
FileReader fr = null;
try {
- fr = new FileReader("/dev/freezer/frozen/freezer.killable");
- int i = fr.read();
+ fr = new FileReader("/sys/fs/cgroup/freezer/cgroup.freeze");
+ char state = (char) fr.read();
- if ((char) i == '1') {
+ if (state == '1' || state == '0') {
supported = true;
} else {
- Slog.w(TAG_AM, "Freezer killability is turned off, disabling freezer");
+ Slog.e(TAG_AM, "unexpected value in cgroup.freeze");
}
} catch (java.io.FileNotFoundException e) {
- Slog.d(TAG_AM, "Freezer.killable not present, disabling freezer");
+ Slog.d(TAG_AM, "cgroup.freeze not present");
} catch (Exception e) {
- Slog.d(TAG_AM, "Unable to read freezer.killable, disabling freezer: " + e.toString());
+ Slog.d(TAG_AM, "unable to read cgroup.freeze: " + e.toString());
}
if (fr != null) {
@@ -471,6 +530,8 @@ public final class CachedAppOptimizer {
if (mUseFreezer && mFreezeHandler == null) {
Slog.d(TAG_AM, "Freezer enabled");
+ enableFreezer(true);
+
if (!mCachedAppOptimizerThread.isAlive()) {
mCachedAppOptimizerThread.start();
}
@@ -479,6 +540,8 @@ public final class CachedAppOptimizer {
Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
Process.THREAD_GROUP_SYSTEM);
+ } else {
+ enableFreezer(false);
}
}
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index bfba4afcd4e4..1155569c6b36 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -198,22 +198,10 @@ public class ContentProviderHelper {
if (providerRunning) {
cpi = cpr.info;
- String msg;
if (r != null && cpr.canRunHere(r)) {
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup "
- + cpr.name.flattenToShortString()
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
+ checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
+ cpr.name.flattenToShortString(), startTime);
// This provider has been published or is in the process
// of being published... but it is also allowed to run
@@ -234,26 +222,14 @@ public class ContentProviderHelper {
} catch (RemoteException e) {
}
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException(
- "Content provider lookup " + cpr.name.flattenToShortString()
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
+ checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
+ cpr.name.flattenToShortString(), startTime);
final long origId = Binder.clearCallingIdentity();
checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
- // In this case the provider instance already exists, so we can
- // return it right away.
+ // In this case the provider instance already exists so we can return it right away.
conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
stable, true, startTime, mService.mProcessList);
@@ -328,19 +304,8 @@ public class ContentProviderHelper {
cpi.applicationInfo = mService.getAppInfoForUser(cpi.applicationInfo, userId);
checkTime(startTime, "getContentProviderImpl: got app info for user");
- String msg;
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup " + name
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
+ checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, !singleton,
+ name, startTime);
if (!mService.mProcessesReady && !cpi.processName.equals("system")) {
// If this content provider does not run in the system
@@ -352,10 +317,12 @@ public class ContentProviderHelper {
// If system providers are not installed yet we aggressively crash to avoid
// creating multiple instance of these providers and then bad things happen!
- if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
- && "system".equals(cpi.processName)) {
- throw new IllegalStateException("Cannot access system provider: '"
- + cpi.authority + "' before system providers are installed!");
+ synchronized (this) {
+ if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
+ && "system".equals(cpi.processName)) {
+ throw new IllegalStateException("Cannot access system provider: '"
+ + cpi.authority + "' before system providers are installed!");
+ }
}
// Make sure that the user who owns this provider is running. If not,
@@ -605,6 +572,23 @@ public class ContentProviderHelper {
return cpr.newHolder(conn, false);
}
+ private void checkAssociationAndPermissionLocked(ProcessRecord callingApp, ProviderInfo cpi,
+ int callingUid, int userId, boolean checkUser, String cprName, long startTime) {
+ String msg;
+ if ((msg = checkContentProviderAssociation(callingApp, callingUid, cpi)) != null) {
+ throw new SecurityException("Content provider lookup " + cprName
+ + " failed: association not allowed with package " + msg);
+ }
+ checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
+ if ((msg = checkContentProviderPermission(
+ cpi, Binder.getCallingPid(), Binder.getCallingUid(), userId, checkUser,
+ callingApp != null ? callingApp.toString() : null))
+ != null) {
+ throw new SecurityException(msg);
+ }
+ checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
+ }
+
void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
if (providers == null) {
return;
@@ -623,7 +607,7 @@ public class ContentProviderHelper {
}
final long origId = Binder.clearCallingIdentity();
-
+ boolean providersPublished = false;
for (int i = 0, size = providers.size(); i < size; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
@@ -636,6 +620,7 @@ public class ContentProviderHelper {
if (DEBUG_MU) {
Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
}
+ providersPublished = true;
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
mProviderMap.putProviderByClass(comp, dst);
@@ -673,8 +658,19 @@ public class ContentProviderHelper {
dst.onProviderPublishStatusLocked(true);
}
dst.mRestartCount = 0;
+ }
+
+ // update the app's oom adj value and each provider's usage stats
+ if (providersPublished) {
mService.updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
- maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority);
+ for (int i = 0, size = providers.size(); i < size; i++) {
+ ContentProviderHolder src = providers.get(i);
+ if (src == null || src.info == null || src.provider == null) {
+ continue;
+ }
+ maybeUpdateProviderUsageStatsLocked(r,
+ src.info.packageName, src.info.authority);
+ }
}
Binder.restoreCallingIdentity(origId);
@@ -702,7 +698,8 @@ public class ContentProviderHelper {
throw new NullPointerException("connection is null");
}
if (decProviderCountLocked(conn, null, null, stable)) {
- mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
+ mService.updateOomAdjLocked(conn.provider.proc,
+ OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
}
}
} finally {
@@ -738,7 +735,8 @@ public class ContentProviderHelper {
ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
if (localCpr.hasExternalProcessHandles()) {
if (localCpr.removeExternalProcessHandleLocked(token)) {
- mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
+ mService.updateOomAdjLocked(localCpr.proc,
+ OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
} else {
Slog.e(TAG, "Attempt to remove content provider " + localCpr
+ " with no external reference for token: " + token + ".");
@@ -997,17 +995,19 @@ public class ContentProviderHelper {
+ "; expected to find a valid ContentProvider for this authority";
}
+ final int callingPid = Binder.getCallingPid();
ProcessRecord r;
+ final String appName;
synchronized (mService.mPidsSelfLocked) {
- r = mService.mPidsSelfLocked.get(Binder.getCallingPid());
- }
- if (r == null) {
- return "Failed to find PID " + Binder.getCallingPid();
+ r = mService.mPidsSelfLocked.get(callingPid);
+ if (r == null) {
+ return "Failed to find PID " + callingPid;
+ }
+ appName = r.toString();
}
- synchronized (mService) {
- return checkContentProviderPermissionLocked(cpi, r, userId, true);
- }
+ return checkContentProviderPermission(cpi, callingPid, Binder.getCallingUid(),
+ userId, true, appName);
}
int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) {
@@ -1163,13 +1163,14 @@ public class ContentProviderHelper {
}
}
}
- if (providers != null) {
- mService.mSystemThread.installSystemProviders(providers);
- }
- synchronized (mService) {
+ synchronized (this) {
+ if (providers != null) {
+ mService.mSystemThread.installSystemProviders(providers);
+ }
mSystemProvidersInstalled = true;
}
+
mService.mConstants.start(mService.mContext.getContentResolver());
mService.mCoreSettingsObserver = new CoreSettingsObserver(mService);
mService.mActivityTaskManager.installSystemProviders();
@@ -1305,10 +1306,8 @@ public class ContentProviderHelper {
* given {@link ProviderInfo}. Final permission checking is always done
* in {@link ContentProvider}.
*/
- private String checkContentProviderPermissionLocked(ProviderInfo cpi, ProcessRecord r,
- int userId, boolean checkUser) {
- final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
- final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
+ private String checkContentProviderPermission(ProviderInfo cpi, int callingPid, int callingUid,
+ int userId, boolean checkUser, String appName) {
boolean checkedGrants = false;
if (checkUser) {
// Looking for cross-user grants before enforcing the typical cross-users permissions
@@ -1376,8 +1375,8 @@ public class ContentProviderHelper {
suffix = " requires " + cpi.readPermission + " or " + cpi.writePermission;
}
final String msg = "Permission Denial: opening provider " + cpi.name
- + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
- + ", uid=" + callingUid + ")" + suffix;
+ + " from " + (appName != null ? appName : "(null)")
+ + " (pid=" + callingPid + ", uid=" + callingUid + ")" + suffix;
Slog.w(TAG, msg);
return msg;
}
@@ -1398,18 +1397,17 @@ public class ContentProviderHelper {
}
ProviderInfo getProviderInfoLocked(String authority, @UserIdInt int userId, int pmFlags) {
- ProviderInfo pi = null;
ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
if (cpr != null) {
- pi = cpr.info;
+ return cpr.info;
} else {
try {
- pi = AppGlobals.getPackageManager().resolveContentProvider(
+ return AppGlobals.getPackageManager().resolveContentProvider(
authority, PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userId);
} catch (RemoteException ex) {
+ return null;
}
}
- return pi;
}
private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
@@ -1419,7 +1417,6 @@ public class ContentProviderHelper {
return;
}
-
UserState userState = mService.mUserController.getStartedUserState(app.userId);
if (userState == null) return;
final long now = SystemClock.elapsedRealtime();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index bad042cd3a68..fc330313373e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -81,6 +81,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.os.Debug;
import android.os.Handler;
@@ -94,6 +95,8 @@ import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.LongSparseArray;
+import android.util.Pair;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -103,10 +106,13 @@ import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.compat.IPlatformCompat;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
+import com.android.server.compat.CompatChange;
+import com.android.server.compat.PlatformCompat;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.WindowProcessController;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
@@ -209,12 +215,99 @@ public final class OomAdjuster {
private final ProcessList mProcessList;
private final int mNumSlots;
- private ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>();
- private ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>();
- private ActiveUids mTmpUidRecords;
- private ArrayDeque<ProcessRecord> mTmpQueue;
+ private final ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>();
+ private final ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>();
+ private final ActiveUids mTmpUidRecords;
+ private final ArrayDeque<ProcessRecord> mTmpQueue;
+ private final ArraySet<ProcessRecord> mPendingProcessSet = new ArraySet<>();
+
+ private final PlatformCompatCache mPlatformCompatCache;
+
+ private static class PlatformCompatCache {
+ private final PlatformCompat mPlatformCompat;
+ private final IPlatformCompat mIPlatformCompatProxy;
+ private final LongSparseArray<CacheItem> mCaches = new LongSparseArray<>();
+ private final boolean mCacheEnabled;
+
+ PlatformCompatCache(long[] compatChanges) {
+ IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+ if (b instanceof PlatformCompat) {
+ mPlatformCompat = (PlatformCompat) ServiceManager.getService(
+ Context.PLATFORM_COMPAT_SERVICE);
+ for (long changeId: compatChanges) {
+ mCaches.put(changeId, new CacheItem(mPlatformCompat, changeId));
+ }
+ mIPlatformCompatProxy = null;
+ mCacheEnabled = true;
+ } else {
+ // we are in UT where the platform_compat is not running within the same process
+ mIPlatformCompatProxy = IPlatformCompat.Stub.asInterface(b);
+ mPlatformCompat = null;
+ mCacheEnabled = false;
+ }
+ }
+
+ boolean isChangeEnabled(long changeId, ApplicationInfo app) throws RemoteException {
+ return mCacheEnabled ? mCaches.get(changeId).isChangeEnabled(app)
+ : mIPlatformCompatProxy.isChangeEnabled(changeId, app);
+ }
+
+ void invalidate(ApplicationInfo app) {
+ for (int i = mCaches.size() - 1; i >= 0; i--) {
+ mCaches.valueAt(i).invalidate(app);
+ }
+ }
+
+ static class CacheItem implements CompatChange.ChangeListener {
+ private final PlatformCompat mPlatformCompat;
+ private final long mChangeId;
+ private final Object mLock = new Object();
+
+ private final ArrayMap<String, Pair<Boolean, WeakReference<ApplicationInfo>>> mCache =
+ new ArrayMap<>();
+
+ CacheItem(PlatformCompat platformCompat, long changeId) {
+ mPlatformCompat = platformCompat;
+ mChangeId = changeId;
+ mPlatformCompat.registerListener(changeId, this);
+ }
+
+ boolean isChangeEnabled(ApplicationInfo app) {
+ synchronized (mLock) {
+ final int index = mCache.indexOfKey(app.packageName);
+ Pair<Boolean, WeakReference<ApplicationInfo>> p;
+ if (index < 0) {
+ p = new Pair<>(mPlatformCompat.isChangeEnabled(mChangeId, app),
+ new WeakReference<>(app));
+ mCache.put(app.packageName, p);
+ return p.first;
+ }
+ p = mCache.valueAt(index);
+ if (p.second.get() == app) {
+ return p.first;
+ }
+ // Cache is invalid, regenerate it
+ p = new Pair<>(mPlatformCompat.isChangeEnabled(mChangeId, app),
+ new WeakReference<>(app));
+ mCache.setValueAt(index, p);
+ return p.first;
+ }
+ }
- private final IPlatformCompat mPlatformCompat;
+ void invalidate(ApplicationInfo app) {
+ synchronized (mLock) {
+ mCache.remove(app.packageName);
+ }
+ }
+
+ @Override
+ public void onCompatChange(String packageName) {
+ synchronized (mLock) {
+ mCache.remove(packageName);
+ }
+ }
+ }
+ }
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
this(service, processList, activeUids, createAdjusterThread());
@@ -263,8 +356,9 @@ public final class OomAdjuster {
mTmpQueue = new ArrayDeque<ProcessRecord>(mConstants.CUR_MAX_CACHED_PROCESSES << 1);
mNumSlots = ((ProcessList.CACHED_APP_MAX_ADJ - ProcessList.CACHED_APP_MIN_ADJ + 1) >> 1)
/ ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
- IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
- mPlatformCompat = IPlatformCompat.Stub.asInterface(b);
+ mPlatformCompatCache = new PlatformCompatCache(new long[] {
+ PROCESS_CAPABILITY_CHANGE_ID, CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID
+ });
}
void initSettings() {
@@ -333,6 +427,8 @@ public final class OomAdjuster {
// need to do a complete oom adj.
final int cachedAdj = app.getCurRawAdj() >= ProcessList.CACHED_APP_MIN_ADJ
? app.getCurRawAdj() : ProcessList.UNKNOWN_ADJ;
+ // Check if this process is in the pending list too, remove from pending list if so.
+ mPendingProcessSet.remove(app);
boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
SystemClock.uptimeMillis());
if (oomAdjAll
@@ -360,6 +456,9 @@ public final class OomAdjuster {
uidRec.reset();
}
+ // Check if this process is in the pending list too, remove from pending list if so.
+ mPendingProcessSet.remove(app);
+
computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false, true);
boolean success = applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
@@ -401,6 +500,8 @@ public final class OomAdjuster {
@GuardedBy("mService")
void updateOomAdjLocked(String oomAdjReason) {
final ProcessRecord topApp = mService.getTopAppLocked();
+ // Clear any pending ones because we are doing a full update now.
+ mPendingProcessSet.clear();
updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true, true);
}
@@ -434,6 +535,8 @@ public final class OomAdjuster {
app.containsCycle = false;
app.procStateChanged = false;
app.resetCachedInfo();
+ // Check if this process is in the pending list too, remove from pending list if so.
+ mPendingProcessSet.remove(app);
boolean success = updateOomAdjLocked(app, cachedAdj, topApp, false,
SystemClock.uptimeMillis());
if (!success || (wasCached == app.isCached() && oldAdj != ProcessList.INVALID_ADJ
@@ -486,6 +589,10 @@ public final class OomAdjuster {
}
queue.offer(service);
service.mReachable = true;
+ // During scanning the reachable dependants, remove them from the pending oomadj
+ // targets list if it's possible, as they've been added into the immediate
+ // oomadj targets list 'processes' above.
+ mPendingProcessSet.remove(service);
}
for (int i = pr.conProviders.size() - 1; i >= 0; i--) {
ContentProviderConnection cpc = pr.conProviders.get(i);
@@ -499,6 +606,10 @@ public final class OomAdjuster {
}
queue.offer(provider);
provider.mReachable = true;
+ // During scanning the reachable dependants, remove them from the pending oomadj
+ // targets list if it's possible, as they've been added into the immediate
+ // oomadj targets list 'processes' above.
+ mPendingProcessSet.remove(provider);
}
}
@@ -523,12 +634,67 @@ public final class OomAdjuster {
applyOomAdjLocked(app, false, SystemClock.uptimeMillis(),
SystemClock.elapsedRealtime());
}
+ mTmpProcessList.clear();
mService.mOomAdjProfiler.oomAdjEnded();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return true;
}
/**
+ * Enqueue the given process for a later oom adj update
+ */
+ @GuardedBy("mService")
+ void enqueueOomAdjTargetLocked(ProcessRecord app) {
+ if (app != null) {
+ mPendingProcessSet.add(app);
+ }
+ }
+
+ @GuardedBy("mService")
+ void removeOomAdjTargetLocked(ProcessRecord app, boolean procDied) {
+ if (app != null) {
+ mPendingProcessSet.remove(app);
+ if (procDied) {
+ mPlatformCompatCache.invalidate(app.info);
+ }
+ }
+ }
+
+ /**
+ * Kick off an oom adj update pass for the pending targets which are enqueued via
+ * {@link #enqueueOomAdjTargetLocked}.
+ */
+ @GuardedBy("mService")
+ void updateOomAdjPendingTargetsLocked(String oomAdjReason) {
+ if (mPendingProcessSet.isEmpty()) {
+ return;
+ }
+ final ProcessRecord topApp = mService.getTopAppLocked();
+
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);
+ mService.mOomAdjProfiler.oomAdjStarted();
+
+ final ArrayList<ProcessRecord> processes = mTmpProcessList;
+ final ActiveUids uids = mTmpUidRecords;
+ uids.clear();
+ processes.clear();
+ for (int i = mPendingProcessSet.size() - 1; i >= 0; i--) {
+ final ProcessRecord app = mPendingProcessSet.valueAt(i);
+ if (app.uidRecord != null) {
+ uids.put(app.uidRecord.uid, app.uidRecord);
+ }
+ processes.add(app);
+ }
+
+ updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, true, false);
+ processes.clear();
+ mPendingProcessSet.clear();
+
+ mService.mOomAdjProfiler.oomAdjEnded();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ /**
* Update OomAdj for all processes within the given list (could be partial), or the whole LRU
* list if the given list is null; when it's partial update, each process's client proc won't
* get evaluated recursively here.
@@ -1555,7 +1721,7 @@ public final class OomAdjuster {
boolean enabled = false;
try {
- enabled = mPlatformCompat.isChangeEnabled(
+ enabled = mPlatformCompatCache.isChangeEnabled(
CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo);
} catch (RemoteException e) {
}
@@ -1742,7 +1908,7 @@ public final class OomAdjuster {
clientProcState = PROCESS_STATE_BOUND_TOP;
boolean enabled = false;
try {
- enabled = mPlatformCompat.isChangeEnabled(
+ enabled = mPlatformCompatCache.isChangeEnabled(
PROCESS_CAPABILITY_CHANGE_ID, client.info);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 76089f8fba01..87898d80bd46 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1528,15 +1528,18 @@ public final class ProcessList {
&& proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY
&& proc.lastCachedPss >= 4000) {
// Turn this condition on to cause killing to happen regularly, for testing.
- if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
- FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
- proc.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
- proc.lastCachedPss, holder.appVersion);
+ synchronized (mService.mProcessStats.mLock) {
+ if (proc.baseProcessTracker != null) {
+ proc.baseProcessTracker.reportCachedKill(
+ proc.pkgList.mPkgList, proc.lastCachedPss);
+ for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+ FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
+ proc.info.uid,
+ holder.state.getName(),
+ holder.state.getPackage(),
+ proc.lastCachedPss, holder.appVersion);
+ }
}
}
proc.kill(Long.toString(proc.lastCachedPss) + "k from cached",
@@ -1549,16 +1552,18 @@ public final class ProcessList {
if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc
.lastCachedPss);
if (proc.lastCachedPss >= getCachedRestoreThresholdKb()) {
- if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList,
- proc.lastCachedPss);
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
- FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
- proc.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
- proc.lastCachedPss, holder.appVersion);
+ synchronized (mService.mProcessStats.mLock) {
+ if (proc.baseProcessTracker != null) {
+ proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList,
+ proc.lastCachedPss);
+ for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+ FrameworkStatsLog.write(FrameworkStatsLog.CACHED_KILL_REPORTED,
+ proc.info.uid,
+ holder.state.getName(),
+ holder.state.getPackage(),
+ proc.lastCachedPss, holder.appVersion);
+ }
}
}
proc.kill(Long.toString(proc.lastCachedPss) + "k from cached",
@@ -2360,7 +2365,7 @@ public final class ProcessList {
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
- if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
+ if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ "/" + processName);
return null;
@@ -2373,11 +2378,11 @@ public final class ProcessList {
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + processName);
mService.mAppErrors.resetProcessCrashTimeLocked(processName, info.uid);
- if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
+ if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
- mService.mAppErrors.clearBadProcessLocked(processName, info.uid);
+ mService.mAppErrors.clearBadProcess(processName, info.uid);
if (app != null) {
app.bad = false;
}
@@ -2636,6 +2641,7 @@ public final class ProcessList {
mLruProcessServiceStart--;
}
mLruProcesses.remove(lrui);
+ mService.removeOomAdjTargetLocked(app, true);
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 06ef58f8cc61..5447605a36d1 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -500,8 +500,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
}
- /*package*/ void postSetModeOwnerPid(int pid) {
- sendIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid);
+ /*package*/ void postSetModeOwnerPid(int pid, int mode) {
+ sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode);
}
/*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
@@ -977,7 +977,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
synchronized (mDeviceStateLock) {
if (mModeOwnerPid != msg.arg1) {
mModeOwnerPid = msg.arg1;
- updateSpeakerphoneOn("setNewModeOwner");
+ if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
+ updateSpeakerphoneOn("setNewModeOwner");
+ }
if (mModeOwnerPid != 0) {
mBtHelper.disconnectBluetoothSco(mModeOwnerPid);
}
diff --git a/services/core/java/com/android/server/audio/AudioEventLogger.java b/services/core/java/com/android/server/audio/AudioEventLogger.java
index 9ebd75bd0f64..af0e978726e3 100644
--- a/services/core/java/com/android/server/audio/AudioEventLogger.java
+++ b/services/core/java/com/android/server/audio/AudioEventLogger.java
@@ -60,7 +60,36 @@ public class AudioEventLogger {
* @return the same instance of the event
*/
public Event printLog(String tag) {
- Log.i(tag, eventToString());
+ return printLog(ALOGI, tag);
+ }
+
+ public static final int ALOGI = 0;
+ public static final int ALOGE = 1;
+ public static final int ALOGW = 2;
+ public static final int ALOGV = 3;
+
+ /**
+ * Same as {@link #printLog(String)} with a log type
+ * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV}
+ * @param tag
+ * @return
+ */
+ public Event printLog(int type, String tag) {
+ switch (type) {
+ case ALOGI:
+ Log.i(tag, eventToString());
+ break;
+ case ALOGE:
+ Log.e(tag, eventToString());
+ break;
+ case ALOGW:
+ Log.w(tag, eventToString());
+ break;
+ case ALOGV:
+ default:
+ Log.v(tag, eventToString());
+ break;
+ }
return this;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 673ca1f3da86..4378490d19c5 100755..100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -26,6 +26,10 @@ import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
+import static com.android.server.audio.AudioEventLogger.Event.ALOGE;
+import static com.android.server.audio.AudioEventLogger.Event.ALOGI;
+import static com.android.server.audio.AudioEventLogger.Event.ALOGW;
+
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -287,6 +291,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_CHECK_MODE_FOR_UID = 31;
private static final int MSG_STREAM_DEVICES_CHANGED = 32;
private static final int MSG_UPDATE_VOLUME_STATES_FOR_DEVICE = 33;
+ private static final int MSG_REINIT_VOLUMES = 34;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -669,6 +674,7 @@ public class AudioService extends IAudioService.Stub
public AudioService(Context context, AudioSystemAdapter audioSystem,
SystemServerAdapter systemServer) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent("AudioService()"));
mContext = context;
mContentResolver = context.getContentResolver();
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
@@ -888,6 +894,9 @@ public class AudioService extends IAudioService.Stub
mPrescaleAbsoluteVolume[i] = preScale[i];
}
}
+
+ // check on volume initialization
+ checkVolumeRangeInitialization("AudioService()");
}
public void systemReady() {
@@ -1015,11 +1024,15 @@ public class AudioService extends IAudioService.Stub
if (!mSystemReady ||
(AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Log.e(TAG, "Audioserver died.");
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ "onAudioServerDied() audioserver died"));
sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
null, 500);
return;
}
- Log.e(TAG, "Audioserver started.");
+ Log.i(TAG, "Audioserver started.");
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ "onAudioServerDied() audioserver started"));
updateAudioHalPids();
@@ -1054,14 +1067,7 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker.setForceUse_Async(AudioSystem.FOR_SYSTEM, forSys, "onAudioServerDied");
// Restore stream volumes
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- VolumeStreamState streamState = mStreamStates[streamType];
- AudioSystem.initStreamVolume(
- streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
-
- streamState.applyAllVolumes();
- }
+ onReinitVolumes("after audioserver restart");
// Restore audio volume groups
restoreVolumeGroups();
@@ -1159,6 +1165,72 @@ public class AudioService extends IAudioService.Stub
setMicMuteFromSwitchInput();
}
+ private void onReinitVolumes(@NonNull String caller) {
+ final int numStreamTypes = AudioSystem.getNumStreamTypes();
+ // keep track of any error during stream volume initialization
+ int status = AudioSystem.AUDIO_STATUS_OK;
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ VolumeStreamState streamState = mStreamStates[streamType];
+ final int res = AudioSystem.initStreamVolume(
+ streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
+ if (res != AudioSystem.AUDIO_STATUS_OK) {
+ status = res;
+ Log.e(TAG, "Failed to initStreamVolume (" + res + ") for stream " + streamType);
+ // stream volume initialization failed, no need to try the others, it will be
+ // attempted again when MSG_REINIT_VOLUMES is handled
+ break;
+ }
+ streamState.applyAllVolumes();
+ }
+
+ // did it work? check based on status
+ if (status != AudioSystem.AUDIO_STATUS_OK) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ caller + ": initStreamVolume failed with " + status + " will retry")
+ .printLog(ALOGE, TAG));
+ sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
+ caller /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
+ return;
+ }
+
+ // did it work? check based on min/max values of some basic streams
+ if (!checkVolumeRangeInitialization(caller)) {
+ return;
+ }
+
+ // success
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ caller + ": initStreamVolume succeeded").printLog(ALOGI, TAG));
+ }
+
+ /**
+ * Check volume ranges were properly initialized
+ * @return true if volume ranges were successfully initialized
+ */
+ private boolean checkVolumeRangeInitialization(String caller) {
+ boolean success = true;
+ final int[] basicStreams = { AudioSystem.STREAM_ALARM, AudioSystem.STREAM_RING,
+ AudioSystem.STREAM_MUSIC, AudioSystem.STREAM_VOICE_CALL,
+ AudioSystem.STREAM_ACCESSIBILITY };
+ for (int streamType : basicStreams) {
+ final AudioAttributes aa = new AudioAttributes.Builder()
+ .setInternalLegacyStreamType(streamType).build();
+ if (AudioSystem.getMaxVolumeIndexForAttributes(aa) < 0
+ || AudioSystem.getMinVolumeIndexForAttributes(aa) < 0) {
+ success = false;
+ break;
+ }
+ }
+ if (!success) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ caller + ": initStreamVolume succeeded but invalid mix/max levels, will retry")
+ .printLog(ALOGW, TAG));
+ sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
+ caller /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
+ }
+ return success;
+ }
+
private void onDispatchAudioServerStateChange(boolean state) {
synchronized (mAudioServerStateListeners) {
for (AsdProxy asdp : mAudioServerStateListeners.values()) {
@@ -3747,13 +3819,15 @@ public class AudioService extends IAudioService.Stub
private final IBinder mCb; // To be notified of client's death
private final int mPid;
private final int mUid;
- private String mPackage;
+ private final boolean mIsPrivileged;
+ private final String mPackage;
private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
- SetModeDeathHandler(IBinder cb, int pid, int uid, String caller) {
+ SetModeDeathHandler(IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
mCb = cb;
mPid = pid;
mUid = uid;
+ mIsPrivileged = isPrivileged;
mPackage = caller;
}
@@ -3765,12 +3839,13 @@ public class AudioService extends IAudioService.Stub
if (index < 0) {
Log.w(TAG, "unregistered setMode() client died");
} else {
- newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, mUid, TAG);
+ newModeOwnerPid = setModeInt(
+ AudioSystem.MODE_NORMAL, mCb, mPid, mUid, mIsPrivileged, TAG);
}
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
+ mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, AudioService.this.getMode());
}
public int getPid() {
@@ -3796,6 +3871,10 @@ public class AudioService extends IAudioService.Stub
public String getPackage() {
return mPackage;
}
+
+ public boolean isPrivileged() {
+ return mIsPrivileged;
+ }
}
/** @see AudioManager#setMode(int) */
@@ -3847,18 +3926,19 @@ public class AudioService extends IAudioService.Stub
+ " without permission or being mode owner");
return;
}
- newModeOwnerPid = setModeInt(
- mode, cb, callingPid, Binder.getCallingUid(), callingPackage);
+ newModeOwnerPid = setModeInt(mode, cb, callingPid, Binder.getCallingUid(),
+ hasModifyPhoneStatePermission, callingPackage);
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
+ mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, getMode());
}
// setModeInt() returns a valid PID if the audio mode was successfully set to
// any mode other than NORMAL.
@GuardedBy("mDeviceBroker.mSetModeLock")
- private int setModeInt(int mode, IBinder cb, int pid, int uid, String caller) {
+ private int setModeInt(
+ int mode, IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
if (DEBUG_MODE) {
Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid
+ ", uid=" + uid + ", caller=" + caller + ")");
@@ -3910,7 +3990,7 @@ public class AudioService extends IAudioService.Stub
}
} else {
if (hdlr == null) {
- hdlr = new SetModeDeathHandler(cb, pid, uid, caller);
+ hdlr = new SetModeDeathHandler(cb, pid, uid, isPrivileged, caller);
}
// Register for client death notification
try {
@@ -3969,7 +4049,8 @@ public class AudioService extends IAudioService.Stub
// change of mode may require volume to be re-applied on some devices
updateAbsVolumeMultiModeDevices(oldMode, actualMode);
- if (actualMode == AudioSystem.MODE_IN_COMMUNICATION) {
+ if (actualMode == AudioSystem.MODE_IN_COMMUNICATION
+ && !hdlr.isPrivileged()) {
sendMsg(mAudioHandler,
MSG_CHECK_MODE_FOR_UID,
SENDMSG_QUEUE,
@@ -5663,7 +5744,15 @@ public class AudioService extends IAudioService.Stub
mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
mIndexMinNoPerm = mIndexMin; // may be overwritten later in updateNoPermMinIndex()
mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
- AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
+ final int status = AudioSystem.initStreamVolume(
+ streamType, mIndexMin / 10, mIndexMax / 10);
+ if (status != AudioSystem.AUDIO_STATUS_OK) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ "VSS() stream:" + streamType + " initStreamVolume=" + status)
+ .printLog(ALOGE, TAG));
+ sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
+ "VSS()" /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
+ }
readSettings();
mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
@@ -6519,8 +6608,8 @@ public class AudioService extends IAudioService.Stub
CHECK_MODE_FOR_UID_PERIOD_MS);
break;
}
- // For now just log the fact that an app is hogging the audio mode.
- // TODO(b/160260850): remove abusive app from audio mode stack.
+ setModeInt(AudioSystem.MODE_NORMAL, h.getBinder(), h.getPid(), h.getUid(),
+ h.isPrivileged(), "MSG_CHECK_MODE_FOR_UID");
mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid()));
}
break;
@@ -6534,6 +6623,10 @@ public class AudioService extends IAudioService.Stub
case MSG_UPDATE_VOLUME_STATES_FOR_DEVICE:
onUpdateVolumeStatesForAudioDevice(msg.arg1, (String) msg.obj);
break;
+
+ case MSG_REINIT_VOLUMES:
+ onReinitVolumes((String) msg.obj);
+ break;
}
}
}
@@ -7463,12 +7556,16 @@ public class AudioService extends IAudioService.Stub
//==========================================================================================
// AudioService logging and dumpsys
//==========================================================================================
+ static final int LOG_NB_EVENTS_LIFECYCLE = 20;
static final int LOG_NB_EVENTS_PHONE_STATE = 20;
static final int LOG_NB_EVENTS_DEVICE_CONNECTION = 30;
static final int LOG_NB_EVENTS_FORCE_USE = 20;
static final int LOG_NB_EVENTS_VOLUME = 40;
static final int LOG_NB_EVENTS_DYN_POLICY = 10;
+ static final AudioEventLogger sLifecycleLogger = new AudioEventLogger(LOG_NB_EVENTS_LIFECYCLE,
+ "audio services lifecycle");
+
final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE,
"phone state (logged after successful call to AudioSystem.setPhoneState(int, int))");
@@ -7545,6 +7642,7 @@ public class AudioService extends IAudioService.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ sLifecycleLogger.dump(pw);
if (mAudioHandler != null) {
pw.println("\nMessage handler (watch for unhandled messages):");
mAudioHandler.dump(new PrintWriterPrinter(pw), " ");
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index bbc29b0bf89b..bbc29b0bf89b 100755..100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 9128359250df..4be596de3af1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -195,6 +195,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
if (listener != null) {
listener.onAuthenticationFailed(getSensorId());
}
+ } else {
+ mAlreadyDone = true;
}
}
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
index dec40e39fb29..e585b48d49b6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
@@ -176,6 +176,11 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
// TODO(b/157790417): Move this to the scheduler
void binderDiedInternal(boolean clearListener) {
+ if (isAlreadyDone()) {
+ Slog.w(TAG, "Binder died but client is finished, ignoring");
+ return;
+ }
+
// If the current client dies we should cancel the current operation.
if (this instanceof Interruptable) {
Slog.e(TAG, "Binder died, cancelling client");
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
index 32bb2db77ddc..c134a3faca4f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
@@ -25,13 +25,14 @@ import android.app.UserSwitchObserver;
import android.content.Context;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
import android.hardware.face.Face;
-import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.IFaceServiceReceiver;
+import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -110,6 +111,9 @@ class Face10 implements IHwBinder.DeathRecipient {
@Override
public void onUserSwitching(int newUserId) {
scheduleInternalCleanup(newUserId);
+ scheduleGetFeature(new Binder(), newUserId,
+ BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION,
+ null, mContext.getOpPackageName());
}
};
@@ -361,6 +365,9 @@ class Face10 implements IHwBinder.DeathRecipient {
if (halId != 0) {
scheduleLoadAuthenticatorIds();
scheduleInternalCleanup(ActivityManager.getCurrentUser());
+ scheduleGetFeature(new Binder(), ActivityManager.getCurrentUser(),
+ BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION,
+ null, mContext.getOpPackageName());
} else {
Slog.e(TAG, "Unable to set callback");
mDaemon = null;
@@ -383,7 +390,7 @@ class Face10 implements IHwBinder.DeathRecipient {
// is safe because authenticatorIds only change when A) new template has been enrolled,
// or B) all templates are removed.
mHandler.post(() -> {
- for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
+ for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
final int targetUserId = user.id;
if (!mAuthenticatorIds.containsKey(targetUserId)) {
scheduleUpdateActiveUserWithoutHandler(targetUserId);
@@ -451,7 +458,7 @@ class Face10 implements IHwBinder.DeathRecipient {
}
void scheduleGetFeature(@NonNull IBinder token, int userId, int feature,
- @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+ @Nullable ClientMonitorCallbackConverter listener, @NonNull String opPackageName) {
mHandler.post(() -> {
final List<Face> faces = getEnrolledFaces(userId);
if (faces.isEmpty()) {
@@ -462,10 +469,22 @@ class Face10 implements IHwBinder.DeathRecipient {
scheduleUpdateActiveUserWithoutHandler(userId);
final int faceId = faces.get(0).getBiometricId();
- final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext,
- mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
- opPackageName, mSensorId, feature, faceId);
- mScheduler.scheduleClientMonitor(client);
+ final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext, mLazyDaemon,
+ token, listener, userId, opPackageName, mSensorId, feature, faceId);
+ mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
+ @Override
+ public void onClientFinished(
+ @NonNull ClientMonitor<?> clientMonitor, boolean success) {
+ if (success && feature == BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION) {
+ final int settingsValue = client.getValue() ? 1 : 0;
+ Slog.d(TAG, "Updating attention value for user: " + userId
+ + " to value: " + settingsValue);
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED,
+ settingsValue, userId);
+ }
+ }
+ });
});
}
@@ -480,7 +499,8 @@ class Face10 implements IHwBinder.DeathRecipient {
* notifying the previous caller that the interrupting operation is complete (e.g. the
* interrupting client's challenge has been revoked, so that the interrupted client can
* start retry logic if necessary). See
- * {@link FaceManager.GenerateChallengeCallback#onChallengeInterruptFinished(int)}
+ * {@link
+ *android.hardware.face.FaceManager.GenerateChallengeCallback#onChallengeInterruptFinished(int)}
* The only case of conflicting challenges is currently resetLockout --> enroll. So, the second
* option seems better as it prioritizes the new operation, which is user-facing.
*/
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java
index 8c7b99d6eb52..33b2b6ada24c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java
@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
@@ -39,9 +40,10 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
private final int mFeature;
private final int mFaceId;
+ private boolean mValue;
FaceGetFeatureClient(@NonNull Context context, @NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
- @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
+ @NonNull IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int sensorId, int feature, int faceId) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
@@ -54,7 +56,9 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
@Override
public void unableToStart() {
try {
- getListener().onFeatureGet(false /* success */, mFeature, false /* value */);
+ if (getListener() != null) {
+ getListener().onFeatureGet(false /* success */, mFeature, false /* value */);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Unable to send error", e);
}
@@ -70,11 +74,18 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
protected void startHalOperation() {
try {
final OptionalBool result = getFreshDaemon().getFeature(mFeature, mFaceId);
- getListener().onFeatureGet(result.status == Status.OK, mFeature, result.value);
+ mValue = result.value;
+ if (getListener() != null) {
+ getListener().onFeatureGet(result.status == Status.OK, mFeature, mValue);
+ }
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to getFeature", e);
mCallback.onClientFinished(this, false /* success */);
}
}
+
+ boolean getValue() {
+ return mValue;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index b689106bbc44..c6664f4d96ff 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -25,9 +25,9 @@ import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.Face;
+import android.hardware.face.FaceSensorProperties;
import android.hardware.face.IFaceService;
import android.hardware.face.IFaceServiceReceiver;
-import android.hardware.face.FaceSensorProperties;
import android.os.Binder;
import android.os.IBinder;
import android.os.NativeHandle;
@@ -303,7 +303,8 @@ public class FaceService extends SystemService {
public void getFeature(final IBinder token, int userId, int feature,
IFaceServiceReceiver receiver, final String opPackageName) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- mFace10.scheduleGetFeature(token, userId, feature, receiver, opPackageName);
+ mFace10.scheduleGetFeature(token, userId, feature,
+ new ClientMonitorCallbackConverter(receiver), opPackageName);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
index c5c28227fd24..3754bd748781 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
@@ -440,7 +440,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
// is safe because authenticatorIds only change when A) new template has been enrolled,
// or B) all templates are removed.
mHandler.post(() -> {
- for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
+ for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
final int targetUserId = user.id;
if (!mAuthenticatorIds.containsKey(targetUserId)) {
scheduleUpdateActiveUserWithoutHandler(targetUserId);
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index a0bc7d8954fb..5d2f51230c12 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -57,10 +57,12 @@ import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.view.autofill.AutofillManagerInternal;
+import android.widget.Toast;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
+import com.android.server.UiThread;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -391,7 +393,9 @@ public class ClipboardService extends SystemService {
return null;
}
addActiveOwnerLocked(intendingUid, pkg);
- return getClipboard(intendingUserId).primaryClip;
+ PerUserClipboard clipboard = getClipboard(intendingUserId);
+ maybeNotify(pkg, intendingUid, intendingUserId, clipboard);
+ return clipboard.primaryClip;
}
}
@@ -821,4 +825,65 @@ public class ClipboardService extends SystemService {
return appOpsResult == AppOpsManager.MODE_ALLOWED;
}
+
+ /**
+ * Potentially notifies the user (via a toast) about an app accessing the clipboard.
+ * TODO(b/167676460): STOPSHIP as we don't want this code as-is to launch. Just an experiment.
+ */
+ private void maybeNotify(String callingPackage, int uid, @UserIdInt int userId,
+ PerUserClipboard clipboard) {
+ if (clipboard.primaryClip == null) {
+ return;
+ }
+ if (Settings.Global.getInt(getContext().getContentResolver(),
+ "clipboard_access_toast_enabled", 0) == 0) {
+ return;
+ }
+ // Don't notify if the app accessing the clipboard is the same as the current owner.
+ if (UserHandle.isSameApp(uid, clipboard.primaryClipUid)) {
+ return;
+ }
+ // Exclude some special cases. It's a bit wasteful to check these again here, but for now
+ // beneficial to have all the logic contained in this single (probably temporary) method.
+ String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, userId);
+ if (!TextUtils.isEmpty(defaultIme)) {
+ final String imePkg = ComponentName.unflattenFromString(defaultIme).getPackageName();
+ if (imePkg.equals(callingPackage)) {
+ return;
+ }
+ }
+ if (mContentCaptureInternal != null
+ && mContentCaptureInternal.isContentCaptureServiceForUser(uid, userId)) {
+ return;
+ }
+ if (mAutofillInternal != null
+ && mAutofillInternal.isAugmentedAutofillServiceForUser(uid, userId)) {
+ return;
+ }
+ // Load the labels for the calling app and the app that set the clipboard content.
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ String message;
+ final CharSequence callingLabel = mPm.getApplicationLabel(
+ pm.getApplicationInfo(callingPackage, 0, userId));
+ final String[] packagesForUid = pm.getPackagesForUid(clipboard.primaryClipUid);
+ if (packagesForUid != null && packagesForUid.length > 0) {
+ final CharSequence clipLabel = mPm.getApplicationLabel(
+ pm.getApplicationInfo(packagesForUid[0], 0,
+ UserHandle.getUserId(clipboard.primaryClipUid)));
+ message = callingLabel + " pasted from " + clipLabel;
+ } else {
+ message = callingLabel + " pasted from clipboard";
+ }
+ Slog.i(TAG, message);
+ Toast.makeText(getContext(), UiThread.get().getLooper(), message, Toast.LENGTH_SHORT)
+ .show();
+ } catch (RemoteException e) {
+ /* ignore */
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 7c8fb5aefd1e..1f0066a43538 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -29,6 +29,7 @@ import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.ERROR_STOP_REASON_UNINITIALIZED;
import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
@@ -152,6 +153,7 @@ public class KeepaliveTracker {
private static final int STARTED = 3;
private static final int STOPPING = 4;
private int mStartedState = NOT_STARTED;
+ private int mStopReason = ERROR_STOP_REASON_UNINITIALIZED;
KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
@NonNull NetworkAgentInfo nai,
@@ -365,6 +367,11 @@ public class KeepaliveTracker {
Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
}
}
+ // Store the reason of stopping, and report it after the keepalive is fully stopped.
+ if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) {
+ throw new IllegalStateException("Unexpected stop reason: " + mStopReason);
+ }
+ mStopReason = reason;
Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.toShortString()
+ ": " + reason);
switch (mStartedState) {
@@ -403,24 +410,6 @@ public class KeepaliveTracker {
Log.wtf(TAG, "Error closing fd for keepalive " + mSlot + ": " + e);
}
}
-
- if (reason == SUCCESS) {
- try {
- mCallback.onStopped();
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onStop callback: " + reason);
- }
- } else if (reason == DATA_RECEIVED) {
- try {
- mCallback.onDataReceived();
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onDataReceived callback: " + reason);
- }
- } else {
- notifyErrorCallback(mCallback, reason);
- }
-
- unlinkDeathRecipient();
}
void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) {
@@ -505,12 +494,37 @@ public class KeepaliveTracker {
Log.e(TAG, "Attempt to remove nonexistent keepalive " + slot + " on " + networkName);
return;
}
+
+ // Remove the keepalive from hash table so the slot can be considered available when reusing
+ // it.
networkKeepalives.remove(slot);
Log.d(TAG, "Remove keepalive " + slot + " on " + networkName + ", "
+ networkKeepalives.size() + " remains.");
if (networkKeepalives.isEmpty()) {
mKeepalives.remove(nai);
}
+
+ // Notify app that the keepalive is stopped.
+ final int reason = ki.mStopReason;
+ if (reason == SUCCESS) {
+ try {
+ ki.mCallback.onStopped();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Discarded onStop callback: " + reason);
+ }
+ } else if (reason == DATA_RECEIVED) {
+ try {
+ ki.mCallback.onDataReceived();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Discarded onDataReceived callback: " + reason);
+ }
+ } else if (reason == ERROR_STOP_REASON_UNINITIALIZED) {
+ throw new IllegalStateException("Unexpected stop reason: " + reason);
+ } else {
+ notifyErrorCallback(ki.mCallback, reason);
+ }
+
+ ki.unlinkDeathRecipient();
}
public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index a75a80a606eb..4c63eb488118 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -174,7 +174,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
- List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
+ List<UserInfo> users = mUserManager.getAliveUsers();
if (users != null) {
for (UserInfo user : users) {
mUsers.add(user.id);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 5484bfca5851..7175489614ea 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1463,7 +1463,7 @@ public class Vpn {
final long token = Binder.clearCallingIdentity();
List<UserInfo> users;
try {
- users = UserManager.get(mContext).getUsers(true);
+ users = UserManager.get(mContext).getAliveUsers();
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index ec12a971e445..b33aa0a6fad3 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -367,7 +367,7 @@ public class SyncManager {
}
private void removeStaleAccounts() {
- for (UserInfo user : mUserManager.getUsers(true)) {
+ for (UserInfo user : mUserManager.getAliveUsers()) {
// Skip any partially created/removed users
if (user.partial) continue;
Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(
@@ -777,7 +777,7 @@ public class SyncManager {
if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
return;
}
- List<UserInfo> users = mUserManager.getUsers(true);
+ List<UserInfo> users = mUserManager.getAliveUsers();
final int userCount = users.size();
for (int i = 0; i < userCount; i++) {
UserHandle userHandle = users.get(i).getUserHandle();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2c632d96e738..4a12ee71adbe 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -83,6 +83,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
@@ -283,6 +284,7 @@ public final class DisplayManagerService extends SystemService {
// Temporary display info, used for comparing display configurations.
private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
+ private final DisplayInfo mTempNonOverrideDisplayInfo = new DisplayInfo();
// Temporary viewports, used when sending new viewport information to the
// input system. May be used outside of the lock but only on the handler thread.
@@ -507,7 +509,8 @@ public final class DisplayManagerService extends SystemService {
mDisplayTransactionListeners.remove(listener);
}
- private void setDisplayInfoOverrideFromWindowManagerInternal(
+ @VisibleForTesting
+ void setDisplayInfoOverrideFromWindowManagerInternal(
int displayId, DisplayInfo info) {
synchronized (mSyncRoot) {
LogicalDisplay display = mLogicalDisplays.get(displayId);
@@ -935,7 +938,8 @@ public final class DisplayManagerService extends SystemService {
adapter.registerLocked();
}
- private void handleDisplayDeviceAdded(DisplayDevice device) {
+ @VisibleForTesting
+ void handleDisplayDeviceAdded(DisplayDevice device) {
synchronized (mSyncRoot) {
handleDisplayDeviceAddedLocked(device);
}
@@ -947,7 +951,6 @@ public final class DisplayManagerService extends SystemService {
Slog.w(TAG, "Attempted to add already added display device: " + info);
return;
}
-
Slog.i(TAG, "Display device added: " + info);
device.mDebugLastLoggedDeviceInfo = info;
@@ -960,7 +963,8 @@ public final class DisplayManagerService extends SystemService {
scheduleTraversalLocked(false);
}
- private void handleDisplayDeviceChanged(DisplayDevice device) {
+ @VisibleForTesting
+ void handleDisplayDeviceChanged(DisplayDevice device) {
synchronized (mSyncRoot) {
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if (!mDisplayDevices.contains(device)) {
@@ -1234,6 +1238,7 @@ public final class DisplayManagerService extends SystemService {
LogicalDisplay display = mLogicalDisplays.valueAt(i);
mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
+ display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);
display.updateLocked(mDisplayDevices);
if (!display.isValidLocked()) {
mLogicalDisplays.removeAt(i);
@@ -1242,6 +1247,15 @@ public final class DisplayManagerService extends SystemService {
} else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
handleLogicalDisplayChanged(displayId, display);
changed = true;
+ } else {
+ // While applications shouldn't know nor care about the non-overridden info, we
+ // still need to let WindowManager know so it can update its own internal state for
+ // things like display cutouts.
+ display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo);
+ if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) {
+ handleLogicalDisplayChanged(displayId, display);
+ changed = true;
+ }
}
}
return changed;
@@ -2176,6 +2190,8 @@ public final class DisplayManagerService extends SystemService {
if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
+ EventLog.writeEvent(0x534e4554, "162627132", callingUid,
+ "Attempt to create a trusted display without holding permission!");
throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
+ "create a trusted virtual display.");
}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
index c90f297e1485..179602737985 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
@@ -51,7 +51,7 @@ public class ActiveSourceAction extends HdmiCecFeatureAction {
Constants.MENU_STATE_ACTIVATED));
}
- source().setActiveSource(logicalAddress, physicalAddress);
+ source().setActiveSource(logicalAddress, physicalAddress, "ActiveSourceAction");
mState = STATE_FINISHED;
finish();
return true;
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 01547c16e9b5..8405bbe38b12 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -17,9 +17,9 @@
package com.android.server.hdmi;
import android.annotation.Nullable;
-import android.hardware.hdmi.IHdmiControlCallback;
-import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
import android.os.RemoteException;
import android.util.Slog;
@@ -69,7 +69,7 @@ final class ActiveSourceHandler {
if (!tv.isProhibitMode()) {
ActiveSource old = ActiveSource.of(tv.getActiveSource());
- tv.updateActiveSource(newActive);
+ tv.updateActiveSource(newActive, "ActiveSourceHandler");
boolean notifyInputChange = (mCallback == null);
if (!old.equals(newActive)) {
tv.setPrevPortId(tv.getActivePortId());
@@ -85,7 +85,7 @@ final class ActiveSourceHandler {
HdmiCecMessage activeSourceCommand = HdmiCecMessageBuilder.buildActiveSource(
current.logicalAddress, current.physicalAddress);
mService.sendCecCommand(activeSourceCommand);
- tv.updateActiveSource(current);
+ tv.updateActiveSource(current, "ActiveSourceHandler");
invokeCallback(HdmiControlManager.RESULT_SUCCESS);
} else {
tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress, true,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 66652ca26e54..7dc4d6e8efcf 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -688,16 +688,24 @@ final class HdmiCecController {
}
void dump(final IndentingPrintWriter pw) {
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
for (int i = 0; i < mLocalDevices.size(); ++i) {
pw.println("HdmiCecLocalDevice #" + mLocalDevices.keyAt(i) + ":");
pw.increaseIndent();
mLocalDevices.valueAt(i).dump(pw);
+
+ pw.println("Active Source history:");
+ pw.increaseIndent();
+ for (Dumpable activeSourceEvent : mLocalDevices.valueAt(i).getActiveSourceHistory()) {
+ activeSourceEvent.dump(pw, sdf);
+ }
+ pw.decreaseIndent();
pw.decreaseIndent();
}
pw.println("CEC message history:");
pw.increaseIndent();
- final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (Dumpable record : mMessageHistory) {
record.dump(pw, sdf);
}
@@ -885,7 +893,7 @@ final class HdmiCecController {
@Override
public void serviceDied(long cookie) {
if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) {
- HdmiLogger.error(TAG, "Service died cokkie : " + cookie + "; reconnecting");
+ HdmiLogger.error("Service died cookie : " + cookie + "; reconnecting");
connectToHal();
}
}
@@ -917,7 +925,7 @@ final class HdmiCecController {
}
}
- private abstract static class Dumpable {
+ public abstract static class Dumpable {
protected final long mTime;
Dumpable() {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 86e6a3220507..b88a37e7b8b4 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -38,10 +38,13 @@ import com.android.server.hdmi.Constants.LocalActivePort;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
/**
* Class that models a logical CEC device hosted in this system. Handles initialization, CEC
@@ -50,6 +53,7 @@ import java.util.List;
abstract class HdmiCecLocalDevice {
private static final String TAG = "HdmiCecLocalDevice";
+ private static final int MAX_HDMI_ACTIVE_SOURCE_HISTORY = 10;
private static final int MSG_DISABLE_DEVICE_TIMEOUT = 1;
private static final int MSG_USER_CONTROL_RELEASE_TIMEOUT = 2;
// Timeout in millisecond for device clean up (5s).
@@ -68,6 +72,10 @@ abstract class HdmiCecLocalDevice {
protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
protected int mLastKeyRepeatCount = 0;
+ // Stores recent changes to the active source in the CEC network.
+ private final ArrayBlockingQueue<HdmiCecController.Dumpable> mActiveSourceHistory =
+ new ArrayBlockingQueue<>(MAX_HDMI_ACTIVE_SOURCE_HISTORY);
+
static class ActiveSource {
int logicalAddress;
int physicalAddress;
@@ -893,16 +901,16 @@ abstract class HdmiCecLocalDevice {
return mService.getLocalActiveSource();
}
- void setActiveSource(ActiveSource newActive) {
- setActiveSource(newActive.logicalAddress, newActive.physicalAddress);
+ void setActiveSource(ActiveSource newActive, String caller) {
+ setActiveSource(newActive.logicalAddress, newActive.physicalAddress, caller);
}
- void setActiveSource(HdmiDeviceInfo info) {
- setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
+ void setActiveSource(HdmiDeviceInfo info, String caller) {
+ setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress(), caller);
}
- void setActiveSource(int logicalAddress, int physicalAddress) {
- mService.setActiveSource(logicalAddress, physicalAddress);
+ void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
+ mService.setActiveSource(logicalAddress, physicalAddress, caller);
mService.setLastInputForMhl(Constants.INVALID_PORT_ID);
}
@@ -1120,6 +1128,20 @@ abstract class HdmiCecLocalDevice {
HdmiCecMessageBuilder.buildUserControlReleased(mAddress, targetAddress));
}
+ void addActiveSourceHistoryItem(ActiveSource activeSource, boolean isActiveSource,
+ String caller) {
+ ActiveSourceHistoryRecord record = new ActiveSourceHistoryRecord(activeSource,
+ isActiveSource, caller);
+ if (!mActiveSourceHistory.offer(record)) {
+ mActiveSourceHistory.poll();
+ mActiveSourceHistory.offer(record);
+ }
+ }
+
+ public ArrayBlockingQueue<HdmiCecController.Dumpable> getActiveSourceHistory() {
+ return this.mActiveSourceHistory;
+ }
+
/** Dump internal status of HdmiCecLocalDevice object. */
protected void dump(final IndentingPrintWriter pw) {
pw.println("mDeviceType: " + mDeviceType);
@@ -1152,4 +1174,29 @@ abstract class HdmiCecLocalDevice {
}
return finalMask | myPhysicalAddress;
}
+
+ private static final class ActiveSourceHistoryRecord extends HdmiCecController.Dumpable {
+ private final ActiveSource mActiveSource;
+ private final boolean mIsActiveSource;
+ private final String mCaller;
+
+ private ActiveSourceHistoryRecord(ActiveSource mActiveSource, boolean mIsActiveSource,
+ String caller) {
+ this.mActiveSource = mActiveSource;
+ this.mIsActiveSource = mIsActiveSource;
+ this.mCaller = caller;
+ }
+
+ @Override
+ void dump(final IndentingPrintWriter pw, SimpleDateFormat sdf) {
+ pw.print("time=");
+ pw.print(sdf.format(new Date(mTime)));
+ pw.print(" active source=");
+ pw.print(mActiveSource);
+ pw.print(" isActiveSource=");
+ pw.print(mIsActiveSource);
+ pw.print(" from=");
+ pw.println(mCaller);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index af815973d3c3..68473c1830ae 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -361,7 +361,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
assertRunOnServiceThread();
// Invalidate the internal active source record when goes to standby
// This set will also update mIsActiveSource
- mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
+ mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
+ "HdmiCecLocalDeviceAudioSystem#onStandby()");
mTvSystemAudioModeSupport = null;
// Record the last state of System Audio Control before going to standby
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index d675b81629a4..f2f6dbe9bde5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -190,7 +190,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
boolean wasActiveSource = mIsActiveSource;
// Invalidate the internal active source record when goes to standby
// This set will also update mIsActiveSource
- mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
+ mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
+ "HdmiCecLocalDevicePlayback#onStandby()");
if (initiatedByCec || !mAutoTvOff || !wasActiveSource) {
return;
}
@@ -399,7 +400,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
assertRunOnServiceThread();
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress,
+ "HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation()");
return;
}
switch (mPlaybackDeviceActionOnRoutingControl) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 44ad8eea65ca..4ff36c4b65db 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -119,11 +119,11 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
}
@ServiceThreadOnly
- protected void setActiveSource(int physicalAddress) {
+ protected void setActiveSource(int physicalAddress, String caller) {
assertRunOnServiceThread();
// Invalidate the internal active source record. This will also update mIsActiveSource.
ActiveSource activeSource = ActiveSource.of(Constants.ADDR_INVALID, physicalAddress);
- setActiveSource(activeSource);
+ setActiveSource(activeSource, caller);
}
@ServiceThreadOnly
@@ -133,7 +133,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
if (!getActiveSource().equals(activeSource)) {
- setActiveSource(activeSource);
+ setActiveSource(activeSource, "HdmiCecLocalDeviceSource#handleActiveSource()");
}
setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON);
@@ -162,7 +162,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
setAndBroadcastActiveSource(message, physicalAddress);
}
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleSetStreamPath()");
}
switchInputOnReceivingNewActivePath(physicalAddress);
return true;
@@ -174,7 +174,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams(), 2);
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingChange()");
}
if (!isRoutingControlFeatureEnabled()) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
@@ -196,7 +196,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingInformation()");
}
if (!isRoutingControlFeatureEnabled()) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 804cc92cca08..0325ad929849 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -288,13 +288,14 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (targetAddress == Constants.ADDR_INTERNAL) {
handleSelectInternalSource();
// Switching to internal source is always successful even when CEC control is disabled.
- setActiveSource(targetAddress, mService.getPhysicalAddress());
+ setActiveSource(targetAddress, mService.getPhysicalAddress(),
+ "HdmiCecLocalDeviceTv#deviceSelect()");
setActivePath(mService.getPhysicalAddress());
invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
return;
}
if (!mService.isControlEnabled()) {
- setActiveSource(targetDevice);
+ setActiveSource(targetDevice, "HdmiCecLocalDeviceTv#deviceSelect()");
invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
return;
}
@@ -307,7 +308,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
assertRunOnServiceThread();
// Seq #18
if (mService.isControlEnabled() && getActiveSource().logicalAddress != mAddress) {
- updateActiveSource(mAddress, mService.getPhysicalAddress());
+ updateActiveSource(mAddress, mService.getPhysicalAddress(),
+ "HdmiCecLocalDeviceTv#handleSelectInternalSource()");
if (mSkipRoutingControl) {
mSkipRoutingControl = false;
return;
@@ -319,19 +321,19 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
@ServiceThreadOnly
- void updateActiveSource(int logicalAddress, int physicalAddress) {
+ void updateActiveSource(int logicalAddress, int physicalAddress, String caller) {
assertRunOnServiceThread();
- updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress));
+ updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress), caller);
}
@ServiceThreadOnly
- void updateActiveSource(ActiveSource newActive) {
+ void updateActiveSource(ActiveSource newActive, String caller) {
assertRunOnServiceThread();
// Seq #14
if (getActiveSource().equals(newActive)) {
return;
}
- setActiveSource(newActive);
+ setActiveSource(newActive, caller);
int logicalAddress = newActive.logicalAddress;
if (getCecDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) {
if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 4ad51de2e25b..0b4f31d365d3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -293,6 +293,11 @@ public class HdmiCecMessageValidator {
return success ? OK : ERROR_PARAMETER;
}
+ private boolean isWithinRange(int value, int min, int max) {
+ value = value & 0xFF;
+ return (value >= min && value <= max);
+ }
+
private class PhysicalAddressValidator implements ParameterValidator {
@Override
public int isValid(byte[] params) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 0576e91b79eb..44b6a63faea1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1970,7 +1970,21 @@ public class HdmiControlService extends SystemService {
@Override
public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
- // TODO(amyjojo): implement the method
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ Slog.i(TAG, "Device "
+ + logicalAddress + " power status is " + powerStatus
+ + " before power on command sent out");
+ if (getSwitchDevice() != null) {
+ getSwitchDevice().sendUserControlPressedAndReleased(
+ logicalAddress, HdmiCecKeycode.CEC_KEYCODE_POWER_ON_FUNCTION);
+ } else {
+ Slog.e(TAG, "Can't get the correct local device to handle routing.");
+ }
+ }
+ });
}
@Override
@@ -3214,7 +3228,7 @@ public class HdmiControlService extends SystemService {
}
}
- void setActiveSource(int logicalAddress, int physicalAddress) {
+ void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
synchronized (mLock) {
mActiveSource.logicalAddress = logicalAddress;
mActiveSource.physicalAddress = physicalAddress;
@@ -3225,14 +3239,17 @@ public class HdmiControlService extends SystemService {
// mIsActiveSource only exists in source device, ignore this setting if the current
// device is not an HdmiCecLocalDeviceSource.
if (!(device instanceof HdmiCecLocalDeviceSource)) {
+ device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
+ false, caller);
continue;
}
- if (logicalAddress == device.getDeviceInfo().getLogicalAddress()
- && physicalAddress == getPhysicalAddress()) {
- ((HdmiCecLocalDeviceSource) device).setIsActiveSource(true);
- } else {
- ((HdmiCecLocalDeviceSource) device).setIsActiveSource(false);
- }
+ boolean deviceIsActiveSource =
+ logicalAddress == device.getDeviceInfo().getLogicalAddress()
+ && physicalAddress == getPhysicalAddress();
+
+ ((HdmiCecLocalDeviceSource) device).setIsActiveSource(deviceIsActiveSource);
+ device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
+ deviceIsActiveSource, caller);
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3fddd5ab91ee..3235b20fb75e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3274,6 +3274,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
+ if (mCurClient == null || mCurClient.curSession == null) {
+ return false;
+ }
if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
&& (mShowExplicitlyRequested || mShowForced)) {
if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
@@ -3458,7 +3461,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// pre-rendering not supported on low-ram devices.
cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
- if (mCurFocusedWindow == windowToken) {
+ final boolean sameWindowFocused = mCurFocusedWindow == windowToken;
+ final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
+ if (sameWindowFocused && isTextEditor) {
if (DEBUG) {
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+ " attribute=" + attribute + ", token = " + windowToken
@@ -3473,6 +3478,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
null, null, null, -1, null);
}
+
mCurFocusedWindow = windowToken;
mCurFocusedWindowSoftInputMode = softInputMode;
mCurFocusedWindowClient = cs;
@@ -3490,7 +3496,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
== LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|| mRes.getConfiguration().isLayoutSizeAtLeast(
Configuration.SCREENLAYOUT_SIZE_LARGE);
- final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
// We want to start input before showing the IME, but after closing
// it. We want to do this after closing it to help the IME disappear
@@ -3550,9 +3555,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
break;
case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
- if (DEBUG) Slog.v(TAG, "Window asks to hide input");
- hideCurrentInputLocked(mCurFocusedWindow, 0, null,
- SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
+ if (isImeVisible()) {
+ if (DEBUG) Slog.v(TAG, "Window asks to hide input");
+ hideCurrentInputLocked(mCurFocusedWindow, 0, null,
+ SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
+ }
break;
case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
@@ -3577,13 +3584,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.v(TAG, "Window asks to always show input");
if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
unverifiedTargetSdkVersion, startInputFlags)) {
- if (attribute != null) {
- res = startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, startInputFlags, startInputReason);
- didStart = true;
+ if (!isImeVisible()) {
+ if (attribute != null) {
+ res = startInputUncheckedLocked(cs, inputContext, missingMethods,
+ attribute, startInputFlags, startInputReason);
+ didStart = true;
+ }
+ showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
+ SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
}
- showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
- SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
} else {
Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
+ " there is no focused view that also returns true from"
@@ -3601,6 +3610,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} else {
res = InputBindResult.NO_EDITOR;
}
+ } else if (sameWindowFocused) {
+ return new InputBindResult(
+ InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
+ null, null, null, -1, null);
} else {
res = InputBindResult.NULL_EDITOR_INFO;
}
@@ -3608,6 +3621,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return res;
}
+ private boolean isImeVisible() {
+ return (mImeWindowVis & InputMethodService.IME_VISIBLE) != 0;
+ }
+
private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
// TODO(yukawa): multi-display support.
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/inputmethod/TEST_MAPPING b/services/core/java/com/android/server/inputmethod/TEST_MAPPING
new file mode 100644
index 000000000000..0ccd75dcbdce
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/view/inputmethod"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 817902d9d566..b61c6a7ca569 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -205,8 +205,13 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
}
if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(TAG, String.format("Successfully pushed rule set: %s", version));
+ Slog.i(
+ TAG,
+ String.format(
+ "Successfully pushed rule set to version '%s' from '%s'",
+ version, ruleProvider));
}
+
FrameworkStatsLog.write(
FrameworkStatsLog.INTEGRITY_RULES_PUSHED,
success,
@@ -324,13 +329,12 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
+ getAllowedInstallers(packageInfo));
}
IntegrityCheckResult result = mEvaluationEngine.evaluate(appInstallMetadata);
- if (DEBUG_INTEGRITY_COMPONENT) {
+ if (!result.getMatchedRules().isEmpty() || DEBUG_INTEGRITY_COMPONENT) {
Slog.i(
TAG,
- "Integrity check result: "
- + result.getEffect()
- + " due to "
- + result.getMatchedRules());
+ String.format(
+ "Integrity check of %s result: %s due to %s",
+ packageName, result.getEffect(), result.getMatchedRules()));
}
FrameworkStatsLog.write(
@@ -673,8 +677,10 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
// Obtain the system apps that are whitelisted in config_integrityRuleProviderPackages.
List<String> allowedRuleProviders = getAllowedRuleProviderSystemApps();
if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(TAG, String.format(
- "Rule provider system app list contains: %s", allowedRuleProviders));
+ Slog.i(
+ TAG,
+ String.format(
+ "Rule provider system app list contains: %s", allowedRuleProviders));
}
// Identify the package names in the caller list.
@@ -730,9 +736,9 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
private boolean integrityCheckIncludesRuleProvider() {
return Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
- 0)
+ mContext.getContentResolver(),
+ Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
+ 0)
== 1;
}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 71f1833854ce..f4d0a6254318 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -697,7 +697,8 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
- Location location = manager.getLastLocation(request, identity, permissionLevel);
+ Location location = manager.getLastLocation(identity, permissionLevel,
+ request.isLocationSettingsIgnored());
// lastly - note app ops
if (!mInjector.getAppOpsHelper().noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
@@ -740,13 +741,9 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
- // create a location request that works in almost all circumstances
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(GPS_PROVIDER, 0,
- 0, true);
-
- // use our own identity rather than the caller
- CallerIdentity identity = CallerIdentity.fromContext(mContext);
- Location location = gpsManager.getLastLocation(request, identity, PERMISSION_FINE);
+ // use fine permission level to avoid creating unnecessary coarse locations
+ Location location = gpsManager.getLastLocationUnsafe(UserHandle.USER_ALL,
+ PERMISSION_FINE, false);
if (location == null) {
return null;
}
@@ -1133,9 +1130,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return;
}
- String dumpFilter = args.length == 0 ? null : args[0];
-
- ipw.println("Location Manager State:");
+ ipw.print("Location Manager State:");
ipw.increaseIndent();
ipw.println("Elapsed Realtime: " + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
@@ -1166,34 +1161,28 @@ public class LocationManagerService extends ILocationManager.Stub {
ipw.println(
"Location Controller Extra Package: " + mExtraLocationControllerPackage
+ (mExtraLocationControllerPackageEnabled ? " [enabled]"
- : "[disabled]"));
+ : " [disabled]"));
}
}
ipw.println("Location Providers:");
ipw.increaseIndent();
for (LocationProviderManager manager : mProviderManagers) {
- if (dumpFilter == null || manager.getName().equals(dumpFilter)) {
- manager.dump(fd, ipw, args);
- }
+ manager.dump(fd, ipw, args);
}
ipw.decreaseIndent();
- if (dumpFilter == null || GPS_PROVIDER.equals(dumpFilter)) {
- if (mGnssManagerService != null) {
- ipw.println("GNSS Manager:");
- ipw.increaseIndent();
- mGnssManagerService.dump(fd, ipw, args);
- ipw.decreaseIndent();
- }
- }
-
- if (dumpFilter == null || "geofence".equals(dumpFilter)) {
- ipw.println("Geofence Manager:");
+ if (mGnssManagerService != null) {
+ ipw.println("GNSS Manager:");
ipw.increaseIndent();
- mGeofenceManager.dump(fd, ipw, args);
+ mGnssManagerService.dump(fd, ipw, args);
ipw.decreaseIndent();
}
+
+ ipw.println("Geofence Manager:");
+ ipw.increaseIndent();
+ mGeofenceManager.dump(fd, ipw, args);
+ ipw.decreaseIndent();
}
private class LocalService extends LocationManagerInternal {
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 06105bfcc0f3..1815a8554705 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -84,7 +84,7 @@ import com.android.server.LocalServices;
import com.android.server.PendingIntentUtils;
import com.android.server.location.LocationPermissions.PermissionLevel;
import com.android.server.location.listeners.ListenerMultiplexer;
-import com.android.server.location.listeners.RemovableListenerRegistration;
+import com.android.server.location.listeners.RemoteListenerRegistration;
import com.android.server.location.util.AppForegroundHelper;
import com.android.server.location.util.AppForegroundHelper.AppForegroundListener;
import com.android.server.location.util.AppOpsHelper;
@@ -154,15 +154,8 @@ class LocationProviderManager extends
@Override
public void deliverOnLocationChanged(Location location,
- @Nullable Runnable onCompleteCallback)
- throws RemoteException {
- mListener.onLocationChanged(location,
- onCompleteCallback == null ? null : new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) {
- onCompleteCallback.run();
- }
- });
+ @Nullable Runnable onCompleteCallback) throws RemoteException {
+ mListener.onLocationChanged(location, SingleUseCallback.wrap(onCompleteCallback));
}
@Override
@@ -221,7 +214,7 @@ class LocationProviderManager extends
}
protected abstract class Registration extends
- RemovableListenerRegistration<LocationRequest, LocationTransport> {
+ RemoteListenerRegistration<LocationRequest, LocationTransport> {
@PermissionLevel protected final int mPermissionLevel;
private final WorkSource mWorkSource;
@@ -306,11 +299,12 @@ class LocationProviderManager extends
}
@Override
- protected final void onInactive() {
+ protected final ListenerOperation<LocationTransport> onInactive() {
onHighPowerUsageChanged();
if (!getRequest().getHideFromAppOps()) {
mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
}
+ return null;
}
@Override
@@ -440,18 +434,17 @@ class LocationProviderManager extends
}
LocationRequest newRequest = calculateProviderLocationRequest();
- if (!mProviderLocationRequest.equals(newRequest)) {
- LocationRequest oldRequest = mProviderLocationRequest;
- mProviderLocationRequest = newRequest;
- onHighPowerUsageChanged();
- updateService();
-
- // if location settings ignored has changed then the active state may have changed
- return oldRequest.isLocationSettingsIgnored()
- != newRequest.isLocationSettingsIgnored();
+ if (mProviderLocationRequest.equals(newRequest)) {
+ return false;
}
- return false;
+ LocationRequest oldRequest = mProviderLocationRequest;
+ mProviderLocationRequest = newRequest;
+ onHighPowerUsageChanged();
+ updateService();
+
+ // if location settings ignored has changed then the active state may have changed
+ return oldRequest.isLocationSettingsIgnored() != newRequest.isLocationSettingsIgnored();
}
private LocationRequest calculateProviderLocationRequest() {
@@ -826,6 +819,12 @@ class LocationProviderManager extends
@GuardedBy("mLock")
@Override
protected void onProviderListenerRegister() {
+ try {
+ ((IBinder) getKey()).linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ remove();
+ }
+
mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
SystemClock.elapsedRealtime());
@@ -837,12 +836,6 @@ class LocationProviderManager extends
0, this, FgThread.getHandler(), getWorkSource());
}
- try {
- ((IBinder) getKey()).linkToDeath(this, 0);
- } catch (RemoteException e) {
- remove();
- }
-
// start listening for provider enabled/disabled events
addEnabledListener(this);
@@ -1066,8 +1059,13 @@ class LocationProviderManager extends
mUserInfoHelper.addListener(mUserChangedListener);
mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
- // initialize enabled state
- onUserStarted(UserHandle.USER_ALL);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // initialize enabled state
+ onUserStarted(UserHandle.USER_ALL);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1077,10 +1075,15 @@ class LocationProviderManager extends
mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
// notify and remove all listeners
- onUserStopped(UserHandle.USER_ALL);
- removeRegistrationIf(key -> true);
- mEnabledListeners.clear();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ onUserStopped(UserHandle.USER_ALL);
+ removeRegistrationIf(key -> true);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ mEnabledListeners.clear();
mStarted = false;
}
}
@@ -1141,14 +1144,26 @@ class LocationProviderManager extends
public void setRealProvider(AbstractLocationProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mStarted);
- mProvider.setRealProvider(provider);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.setRealProvider(provider);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
public void setMockProvider(@Nullable MockProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mStarted);
- mProvider.setMockProvider(provider);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.setMockProvider(provider);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
// when removing a mock provider, also clear any mock last locations and reset the
// location fudger. the mock provider could have been used to infer the current
@@ -1170,7 +1185,12 @@ class LocationProviderManager extends
throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- mProvider.setMockProviderAllowed(enabled);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.setMockProviderAllowed(enabled);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1180,15 +1200,20 @@ class LocationProviderManager extends
throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- String locationProvider = location.getProvider();
- if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
- // The location has an explicit provider that is different from the mock
- // provider name. The caller may be trying to fool us via b/33091107.
- EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
- mName + "!=" + locationProvider);
- }
+ long identity = Binder.clearCallingIdentity();
+ try {
+ String locationProvider = location.getProvider();
+ if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
+ // The location has an explicit provider that is different from the mock
+ // provider name. The caller may be trying to fool us via b/33091107.
+ EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
+ mName + "!=" + locationProvider);
+ }
- mProvider.setMockProviderLocation(location);
+ mProvider.setMockProviderLocation(location);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1203,10 +1228,8 @@ class LocationProviderManager extends
}
@Nullable
- public Location getLastLocation(LocationRequest request, CallerIdentity identity,
- @PermissionLevel int permissionLevel) {
- Preconditions.checkArgument(mName.equals(request.getProvider()));
-
+ public Location getLastLocation(CallerIdentity identity, @PermissionLevel int permissionLevel,
+ boolean ignoreLocationSettings) {
if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
identity.getPackageName())) {
return null;
@@ -1214,12 +1237,12 @@ class LocationProviderManager extends
if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
return null;
}
- if (!request.isLocationSettingsIgnored() && !isEnabled(identity.getUserId())) {
+ if (!ignoreLocationSettings && !isEnabled(identity.getUserId())) {
return null;
}
- Location location = getLastLocation(identity.getUserId(), permissionLevel,
- request.isLocationSettingsIgnored());
+ Location location = getLastLocationUnsafe(identity.getUserId(), permissionLevel,
+ ignoreLocationSettings);
// we don't note op here because we don't know what the client intends to do with the
// location, the client is responsible for noting if necessary
@@ -1233,9 +1256,30 @@ class LocationProviderManager extends
}
}
+ /**
+ * This function does not perform any permissions or safety checks, by calling it you are
+ * committing to performing all applicable checks yourself. Prefer
+ * {@link #getLastLocation(CallerIdentity, int, boolean)} where possible.
+ */
@Nullable
- private Location getLastLocation(int userId, @PermissionLevel int permissionLevel,
+ public Location getLastLocationUnsafe(int userId, @PermissionLevel int permissionLevel,
boolean ignoreLocationSettings) {
+ if (userId == UserHandle.USER_ALL) {
+ Location lastLocation = null;
+ final int[] runningUserIds = mUserInfoHelper.getRunningUserIds();
+ for (int i = 0; i < runningUserIds.length; i++) {
+ Location next = getLastLocationUnsafe(runningUserIds[i], permissionLevel,
+ ignoreLocationSettings);
+ if (lastLocation == null || (next != null && next.getElapsedRealtimeNanos()
+ > lastLocation.getElapsedRealtimeNanos())) {
+ lastLocation = next;
+ }
+ }
+ return lastLocation;
+ }
+
+ Preconditions.checkArgument(userId >= 0);
+
synchronized (mLock) {
LastLocation lastLocation = mLastLocations.get(userId);
if (lastLocation == null) {
@@ -1247,7 +1291,7 @@ class LocationProviderManager extends
public void injectLastLocation(Location location, int userId) {
synchronized (mLock) {
- if (getLastLocation(userId, PERMISSION_FINE, false) == null) {
+ if (getLastLocationUnsafe(userId, PERMISSION_FINE, false) == null) {
setLastLocation(location, userId);
}
}
@@ -1279,7 +1323,7 @@ class LocationProviderManager extends
}
}
- public void getCurrentLocation(LocationRequest request, CallerIdentity identity,
+ public void getCurrentLocation(LocationRequest request, CallerIdentity callerIdentity,
int permissionLevel, ICancellationSignal cancellationTransport,
ILocationCallback callback) {
Preconditions.checkArgument(mName.equals(request.getProvider()));
@@ -1291,12 +1335,27 @@ class LocationProviderManager extends
GetCurrentLocationListenerRegistration registration =
new GetCurrentLocationListenerRegistration(
request,
- identity,
+ callerIdentity,
new GetCurrentLocationTransport(callback),
permissionLevel);
synchronized (mLock) {
- Location lastLocation = getLastLocation(request, identity, permissionLevel);
+ if (mSettingsHelper.isLocationPackageBlacklisted(callerIdentity.getUserId(),
+ callerIdentity.getPackageName())) {
+ registration.deliverLocation(null);
+ return;
+ }
+ if (!mUserInfoHelper.isCurrentUserId(callerIdentity.getUserId())) {
+ registration.deliverLocation(null);
+ return;
+ }
+ if (!request.isLocationSettingsIgnored() && !isEnabled(callerIdentity.getUserId())) {
+ registration.deliverLocation(null);
+ return;
+ }
+
+ Location lastLocation = getLastLocationUnsafe(callerIdentity.getUserId(),
+ permissionLevel, request.isLocationSettingsIgnored());
if (lastLocation != null) {
long locationAgeMs = NANOSECONDS.toMillis(
SystemClock.elapsedRealtimeNanos()
@@ -1314,63 +1373,94 @@ class LocationProviderManager extends
}
// if last location isn't good enough then we add a location request
- addRegistration(callback.asBinder(), registration);
- CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
- cancellationTransport);
- if (cancellationSignal != null) {
- cancellationSignal.setOnCancelListener(
- () -> {
- synchronized (mLock) {
- removeRegistration(callback.asBinder(), registration);
- }
- });
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(callback.asBinder(), registration);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
+
+ CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
+ cancellationTransport);
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(SingleUseCallback.wrap(
+ () -> {
+ synchronized (mLock) {
+ removeRegistration(callback.asBinder(), registration);
+ }
+ }));
+ }
}
public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
- mProvider.sendExtraCommand(uid, pid, command, extras);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mProvider.sendExtraCommand(uid, pid, command, extras);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
- public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, ILocationListener listener) {
Preconditions.checkArgument(mName.equals(request.getProvider()));
synchronized (mLock) {
- addRegistration(
- listener.asBinder(),
- new LocationListenerRegistration(
- request,
- identity,
- new LocationListenerTransport(listener),
- permissionLevel));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(
+ listener.asBinder(),
+ new LocationListenerRegistration(
+ request,
+ callerIdentity,
+ new LocationListenerTransport(listener),
+ permissionLevel));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
- public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
Preconditions.checkArgument(mName.equals(request.getProvider()));
synchronized (mLock) {
- addRegistration(
- pendingIntent,
- new LocationPendingIntentRegistration(
- request,
- identity,
- new LocationPendingIntentTransport(mContext, pendingIntent),
- permissionLevel));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(
+ pendingIntent,
+ new LocationPendingIntentRegistration(
+ request,
+ callerIdentity,
+ new LocationPendingIntentTransport(mContext, pendingIntent),
+ permissionLevel));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
public void unregisterLocationRequest(ILocationListener listener) {
synchronized (mLock) {
- removeRegistration(listener.asBinder());
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(listener.asBinder());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
public void unregisterLocationRequest(PendingIntent pendingIntent) {
synchronized (mLock) {
- removeRegistration(pendingIntent);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(pendingIntent);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -1877,7 +1967,8 @@ class LocationProviderManager extends
ipw.println("user " + userId + ":");
ipw.increaseIndent();
}
- ipw.println("last location=" + getLastLocation(userId, PERMISSION_FINE, false));
+ ipw.println(
+ "last location=" + getLastLocationUnsafe(userId, PERMISSION_FINE, false));
ipw.println("enabled=" + isEnabled(userId));
if (userIds.length != 1) {
ipw.decreaseIndent();
@@ -1950,7 +2041,7 @@ class LocationProviderManager extends
}
// update last coarse interval only if enough time has passed
long timeDeltaMs = NANOSECONDS.toMillis(newCoarse.getElapsedRealtimeNanos())
- - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos());
+ - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos());
if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) {
return newCoarse;
} else {
@@ -1958,4 +2049,61 @@ class LocationProviderManager extends
}
}
}
+
+ private static class SingleUseCallback extends IRemoteCallback.Stub implements Runnable,
+ CancellationSignal.OnCancelListener {
+
+ @Nullable
+ public static SingleUseCallback wrap(@Nullable Runnable callback) {
+ return callback == null ? null : new SingleUseCallback(callback);
+ }
+
+ @GuardedBy("this")
+ @Nullable private Runnable mCallback;
+
+ private SingleUseCallback(Runnable callback) {
+ mCallback = Objects.requireNonNull(callback);
+ }
+
+ @Override
+ public void sendResult(Bundle data) {
+ run();
+ }
+
+ @Override
+ public void onCancel() {
+ run();
+ }
+
+ @Override
+ public void run() {
+ Runnable callback;
+ synchronized (this) {
+ callback = mCallback;
+ mCallback = null;
+ }
+
+ // prevent this callback from being run more than once - otherwise this could provide an
+ // attack vector for a malicious app to break assumptions on how many times a callback
+ // may be invoked, and thus crash system server.
+ if (callback == null) {
+ return;
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ callback.run();
+ } catch (RuntimeException e) {
+ // since this is within a oneway binder transaction there is nowhere
+ // for exceptions to go - move onto another thread to crash system
+ // server so we find out about it
+ FgThread.getExecutor().execute(() -> {
+ throw new AssertionError(e);
+ });
+ throw e;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index 2d9734ef0553..2d7f02873b8f 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -32,6 +32,7 @@ import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationRequest;
import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.WorkSource;
@@ -291,17 +292,28 @@ public class GeofenceManager extends
@Nullable String attributionTag) {
LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE);
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
- AppOpsManager.toReceiverId(pendingIntent));
- addRegistration(new GeofenceKey(pendingIntent, geofence),
- new GeofenceRegistration(geofence, identity, pendingIntent));
+ CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName,
+ attributionTag, AppOpsManager.toReceiverId(pendingIntent));
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(new GeofenceKey(pendingIntent, geofence),
+ new GeofenceRegistration(geofence, callerIdentity, pendingIntent));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Removes the geofence associated with the PendingIntent.
*/
public void removeGeofence(PendingIntent pendingIntent) {
- removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent));
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 1b599b026c38..a9fdacca9a06 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.location.LocationManagerInternal;
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Process;
@@ -218,16 +219,27 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
/**
* Adds a listener with the given identity and request.
*/
- protected void addListener(TRequest request, CallerIdentity identity, TListener listener) {
- addRegistration(listener.asBinder(),
- new GnssListenerRegistration(request, identity, listener));
+ protected void addListener(TRequest request, CallerIdentity callerIdentity,
+ TListener listener) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ addRegistration(listener.asBinder(),
+ new GnssListenerRegistration(request, callerIdentity, listener));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Removes the given listener.
*/
public void removeListener(TListener listener) {
- removeRegistration(listener.asBinder());
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(listener.asBinder());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 850cf7f4b7ce..a4486d7b5898 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -85,7 +85,9 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* A GNSS implementation of LocationProvider used by LocationManager.
@@ -181,7 +183,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static final int INJECT_NTP_TIME = 5;
// PSDS stands for Predicted Satellite Data Service
private static final int DOWNLOAD_PSDS_DATA = 6;
- private static final int DOWNLOAD_PSDS_DATA_FINISHED = 11;
private static final int INITIALIZE_HANDLER = 13;
private static final int REQUEST_LOCATION = 16;
private static final int REPORT_LOCATION = 17; // HAL reports location
@@ -288,6 +289,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static final long DOWNLOAD_PSDS_DATA_TIMEOUT_MS = 60 * 1000;
private static final long WAKELOCK_TIMEOUT_MILLIS = 30 * 1000;
+ @GuardedBy("mLock")
private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL,
MAX_RETRY_INTERVAL);
@@ -297,14 +299,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private boolean mShutdown;
- // states for injecting ntp and downloading psds data
- private static final int STATE_PENDING_NETWORK = 0;
- private static final int STATE_DOWNLOADING = 1;
- private static final int STATE_IDLE = 2;
-
- // flags to trigger NTP or PSDS data download when network becomes available
- // initialized to true so we do NTP and PSDS when the network comes up after booting
- private int mDownloadPsdsDataPending = STATE_PENDING_NETWORK;
+ @GuardedBy("mLock")
+ private Set<Integer> mPendingDownloadPsdsTypes = new HashSet<>();
// true if GPS is navigating
private boolean mNavigating;
@@ -610,6 +606,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mNIHandler = new GpsNetInitiatedHandler(context,
mNetInitiatedListener,
mSuplEsEnabled);
+ // Trigger PSDS data download when the network comes up after booting.
+ mPendingDownloadPsdsTypes.add(GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX);
mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
GnssLocationProvider.this::onNetworkAvailable, mLooper, mNIHandler);
@@ -670,10 +668,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
*/
private void onNetworkAvailable() {
mNtpTimeHelper.onNetworkAvailable();
- if (mDownloadPsdsDataPending == STATE_PENDING_NETWORK) {
- if (mSupportsPsds) {
- // Download only if supported, (prevents an unnecessary on-boot download)
- psdsDownloadRequest(/* psdsType= */ GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX);
+ // Download only if supported, (prevents an unnecessary on-boot download)
+ if (mSupportsPsds) {
+ synchronized (mLock) {
+ for (int psdsType : mPendingDownloadPsdsTypes) {
+ downloadPsdsData(psdsType);
+ }
+ mPendingDownloadPsdsTypes.clear();
}
}
}
@@ -799,17 +800,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
Log.d(TAG, "handleDownloadPsdsData() called when PSDS not supported");
return;
}
- if (mDownloadPsdsDataPending == STATE_DOWNLOADING) {
- // already downloading data
- return;
- }
if (!mNetworkConnectivityHandler.isDataNetworkConnected()) {
// try again when network is up
- mDownloadPsdsDataPending = STATE_PENDING_NETWORK;
+ synchronized (mLock) {
+ mPendingDownloadPsdsTypes.add(psdsType);
+ }
return;
}
- mDownloadPsdsDataPending = STATE_DOWNLOADING;
-
synchronized (mLock) {
// hold wake lock while task runs
mDownloadPsdsWakeLock.acquire(DOWNLOAD_PSDS_DATA_TIMEOUT_MS);
@@ -820,20 +817,24 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mGnssConfiguration.getProperties());
byte[] data = psdsDownloader.downloadPsdsData(psdsType);
if (data != null) {
- if (DEBUG) Log.d(TAG, "calling native_inject_psds_data");
- native_inject_psds_data(data, data.length);
- mPsdsBackOff.reset();
- }
-
- sendMessage(DOWNLOAD_PSDS_DATA_FINISHED, 0, null);
-
- if (data == null) {
- // try again later
- // since this is delayed and not urgent we do not hold a wake lock here
- // the arg2 below should not be 1 otherwise the wakelock will be under-locked.
+ mHandler.post(() -> {
+ if (DEBUG) Log.d(TAG, "calling native_inject_psds_data");
+ native_inject_psds_data(data, data.length, psdsType);
+ synchronized (mLock) {
+ mPsdsBackOff.reset();
+ }
+ });
+ } else {
+ // Try download PSDS data again later according to backoff time.
+ // Since this is delayed and not urgent, we do not hold a wake lock here.
+ // The arg2 below should not be 1 otherwise the wakelock will be under-locked.
+ long backoffMillis;
+ synchronized (mLock) {
+ backoffMillis = mPsdsBackOff.nextBackoffMillis();
+ }
mHandler.sendMessageDelayed(
mHandler.obtainMessage(DOWNLOAD_PSDS_DATA, psdsType, 0, null),
- mPsdsBackOff.nextBackoffMillis());
+ backoffMillis);
}
// Release wake lock held by task, synchronize on mLock in case multiple
@@ -1128,7 +1129,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
requestUtcTime();
} else if ("force_psds_injection".equals(command)) {
if (mSupportsPsds) {
- psdsDownloadRequest(/* psdsType= */
+ downloadPsdsData(/* psdsType= */
GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX);
}
} else {
@@ -1581,8 +1582,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
reportLocation(locations);
}
- void psdsDownloadRequest(int psdsType) {
- if (DEBUG) Log.d(TAG, "psdsDownloadRequest. psdsType: " + psdsType);
+ void downloadPsdsData(int psdsType) {
+ if (DEBUG) Log.d(TAG, "downloadPsdsData. psdsType: " + psdsType);
sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null);
}
@@ -1896,9 +1897,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
case DOWNLOAD_PSDS_DATA:
handleDownloadPsdsData(msg.arg1);
break;
- case DOWNLOAD_PSDS_DATA_FINISHED:
- mDownloadPsdsDataPending = STATE_IDLE;
- break;
case INITIALIZE_HANDLER:
handleInitialize();
break;
@@ -2007,8 +2005,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
return "REQUEST_LOCATION";
case DOWNLOAD_PSDS_DATA:
return "DOWNLOAD_PSDS_DATA";
- case DOWNLOAD_PSDS_DATA_FINISHED:
- return "DOWNLOAD_PSDS_DATA_FINISHED";
case INITIALIZE_HANDLER:
return "INITIALIZE_HANDLER";
case REPORT_LOCATION:
@@ -2022,6 +2018,21 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ boolean dumpAll = false;
+
+ int opti = 0;
+ while (opti < args.length) {
+ String opt = args[opti];
+ if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
+ break;
+ }
+ opti++;
+ if ("-a".equals(opt)) {
+ dumpAll = true;
+ break;
+ }
+ }
+
StringBuilder s = new StringBuilder();
s.append("mStarted=").append(mStarted).append(" (changed ");
TimeUtils.formatDuration(SystemClock.elapsedRealtime()
@@ -2053,9 +2064,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
s.append("]\n");
}
s.append(mGnssMetrics.dumpGnssMetricsAsText());
- s.append("native internal state: \n");
- s.append(" ").append(native_get_internal_state());
- s.append("\n");
+ if (dumpAll) {
+ s.append("native internal state: \n");
+ s.append(" ").append(native_get_internal_state());
+ s.append("\n");
+ }
pw.append(s);
}
@@ -2094,7 +2107,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private native boolean native_supports_psds();
- private native void native_inject_psds_data(byte[] data, int length);
+ private native void native_inject_psds_data(byte[] data, int length, int psdsType);
// DEBUG Support
private native String native_get_internal_state();
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 8e81f29550d6..2bf6af25422a 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -519,7 +519,7 @@ public class GnssManagerService implements GnssNative.Callbacks {
@Override
public void psdsDownloadRequest(int psdsType) {
- mGnssLocationProvider.psdsDownloadRequest(psdsType);
+ mGnssLocationProvider.downloadPsdsData(psdsType);
}
@Override
diff --git a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
index bd8bce8f6d52..58aabdad056f 100644
--- a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
@@ -32,10 +32,10 @@ import android.util.Log;
* @param <TListener> listener type
*/
public abstract class BinderListenerRegistration<TRequest, TListener> extends
- RemovableListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient {
+ RemoteListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient {
/**
- * Interface to allowed binder retrieval when keys are not themselves IBinder.
+ * Interface to allow binder retrieval when keys are not themselves IBinders.
*/
public interface BinderKey {
/**
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index f94de9be0cfe..8a6b8aa1e463 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -18,12 +18,9 @@ package com.android.server.location.listeners;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Binder;
import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.IndentingPrintWriter;
-import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.listeners.ListenerExecutor.ListenerOperation;
@@ -31,8 +28,10 @@ import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -42,7 +41,7 @@ import java.util.function.Predicate;
* divided into two categories, active registrations and inactive registrations, as defined by
* {@link #isActive(ListenerRegistration)}. If a registration's active state changes,
* {@link #updateRegistrations(Predicate)} must be invoked and return true for any registration
- * whose active state may have changed.
+ * whose active state may have changed. Listeners will only be invoked for active registrations.
*
* Callbacks invoked for various changes will always be ordered according to this lifecycle list:
*
@@ -64,14 +63,6 @@ import java.util.function.Predicate;
* {@link #removeRegistration(Object, ListenerRegistration)}, not via any other removal method. This
* ensures re-entrant removal does not accidentally remove the incorrect registration.
*
- * All callbacks will be invoked with a cleared binder identity.
- *
- * Listeners owned by other processes will be run on a direct executor (and thus while holding a
- * lock). Listeners owned by the same process this multiplexer is in will be run asynchronously (and
- * thus without holding a lock). The underlying assumption is that listeners owned by other
- * processes will simply be forwarding the call to those other processes and perhaps performing
- * simple bookkeeping, with no potential for deadlock.
- *
* @param <TKey> key type
* @param <TRequest> request type
* @param <TListener> listener type
@@ -149,46 +140,51 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
}
/**
- * Invoked before the first registration occurs. This is a convenient entry point for
- * registering listeners, etc, which only need to be present while there are any registrations.
+ * Invoked when the multiplexer goes from having no registrations to having some registrations.
+ * This is a convenient entry point for registering listeners, etc, which only need to be
+ * present while there are any registrations. Invoked while holding the multiplexer's internal
+ * lock.
*/
protected void onRegister() {}
/**
- * Invoked after the last unregistration occurs. This is a convenient entry point for
- * unregistering listeners, etc, which only need to be present while there are any
- * registrations.
+ * Invoked when the multiplexer goes from having some registrations to having no registrations.
+ * This is a convenient entry point for unregistering listeners, etc, which only need to be
+ * present while there are any registrations. Invoked while holding the multiplexer's internal
+ * lock.
*/
protected void onUnregister() {}
/**
- * Invoked when a registration is added.
+ * Invoked when a registration is added. Invoked while holding the multiplexer's internal lock.
*/
protected void onRegistrationAdded(@NonNull TKey key, @NonNull TRegistration registration) {}
/**
- * Invoked when a registration is removed.
+ * Invoked when a registration is removed. Invoked while holding the multiplexer's internal
+ * lock.
*/
protected void onRegistrationRemoved(@NonNull TKey key, @NonNull TRegistration registration) {}
/**
- * Invoked when the manager goes from having no active registrations to having some active
+ * Invoked when the multiplexer goes from having no active registrations to having some active
* registrations. This is a convenient entry point for registering listeners, etc, which only
- * need to be present while there are active registrations.
+ * need to be present while there are active registrations. Invoked while holding the
+ * multiplexer's internal lock.
*/
protected void onActive() {}
/**
- * Invoked when the manager goes from having some active registrations to having no active
+ * Invoked when the multiplexer goes from having some active registrations to having no active
* registrations. This is a convenient entry point for unregistering listeners, etc, which only
- * need to be present while there are active registrations.
+ * need to be present while there are active registrations. Invoked while holding the
+ * multiplexer's internal lock.
*/
protected void onInactive() {}
/**
- * Adds a new registration with the given key. Registration may fail if
- * {@link ListenerRegistration#onRegister(Object)} returns false, in which case the registration
- * will not be added. This method cannot be called to add a registration re-entrantly.
+ * Adds a new registration with the given key. This method cannot be called to add a
+ * registration re-entrantly.
*/
protected final void addRegistration(@NonNull TKey key, @NonNull TRegistration registration) {
Objects.requireNonNull(key);
@@ -204,7 +200,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
// involve removing a prior registration. note that try-with-resources ordering is
// meaningful here as well. we want to close the reentrancy guard first, as this may
// generate additional service updates, then close the update service buffer.
- long identity = Binder.clearCallingIdentity();
try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
@@ -224,16 +219,13 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
registration.onRegister(key);
onRegistrationAdded(key, registration);
onRegistrationActiveChanged(registration);
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
/**
- * Removes the registration with the given key. If unregistration occurs,
- * {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This method
- * cannot be called to remove a registration re-entrantly.
+ * Removes the registration with the given key. This method cannot be called to remove a
+ * registration re-entrantly.
*/
protected final void removeRegistration(@NonNull Object key) {
synchronized (mRegistrations) {
@@ -250,9 +242,8 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
}
/**
- * Removes all registrations with keys that satisfy the given predicate. If unregistration
- * occurs, {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This
- * method cannot be called to remove a registration re-entrantly.
+ * Removes all registrations with keys that satisfy the given predicate. This method cannot be
+ * called to remove a registration re-entrantly.
*/
protected final void removeRegistrationIf(@NonNull Predicate<TKey> predicate) {
synchronized (mRegistrations) {
@@ -281,11 +272,8 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
/**
* Removes the given registration with the given key. If the given key has a different
- * registration at the time this method is called, nothing happens. If unregistration occurs,
- * {@link #onRegistrationRemoved(Object, ListenerRegistration)} will be called. This method
- * allows for re-entrancy, and may be called to remove a registration re-entrantly. In this case
- * the registration will immediately be marked inactive and unregistered, and will be removed
- * completely at some later time.
+ * registration at the time this method is called, nothing happens. This method allows for
+ * re-entrancy, and may be called to remove a registration re-entrantly.
*/
protected final void removeRegistration(@NonNull Object key,
@NonNull ListenerRegistration<?, ?> registration) {
@@ -324,7 +312,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
// in multiple service updates. note that try-with-resources ordering is meaningful here as
// well. we want to close the reentrancy guard first, as this may generate additional
// service updates, then close the update service buffer.
- long identity = Binder.clearCallingIdentity();
try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
@@ -337,8 +324,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
onUnregister();
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
@@ -362,38 +347,46 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
}
}
- long identity = Binder.clearCallingIdentity();
- try {
- if (actives.isEmpty()) {
+ if (actives.isEmpty()) {
+ mCurrentRequest = null;
+ if (mServiceRegistered) {
+ mServiceRegistered = false;
mCurrentRequest = null;
- if (mServiceRegistered) {
- mServiceRegistered = false;
- mCurrentRequest = null;
- unregisterWithService();
- }
- return;
+ unregisterWithService();
}
+ return;
+ }
- TMergedRequest merged = mergeRequests(actives);
- if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) {
- if (mServiceRegistered) {
- mServiceRegistered = reregisterWithService(mCurrentRequest, merged);
- } else {
- mServiceRegistered = registerWithService(merged);
- }
- if (mServiceRegistered) {
- mCurrentRequest = merged;
- } else {
- mCurrentRequest = null;
- }
+ TMergedRequest merged = mergeRequests(actives);
+ if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) {
+ if (mServiceRegistered) {
+ mServiceRegistered = reregisterWithService(mCurrentRequest, merged);
+ } else {
+ mServiceRegistered = registerWithService(merged);
+ }
+ if (mServiceRegistered) {
+ mCurrentRequest = merged;
+ } else {
+ mCurrentRequest = null;
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
/**
+ * Clears currently stored service state, and invokes {@link #updateService()} to force a new
+ * call to {@link #registerWithService(Object)} if necessary. This is useful, for instance, if
+ * the backing service has crashed or otherwise lost state, and needs to be re-initialized.
+ */
+ protected final void resetService() {
+ synchronized (mRegistrations) {
+ mServiceRegistered = false;
+ mCurrentRequest = null;
+ updateService();
+ }
+ }
+
+ /**
* Begins buffering calls to {@link #updateService()} until {@link UpdateServiceLock#close()}
* is called. This is useful to prevent extra work when combining multiple calls (for example,
* buffering {@code updateService()} until after multiple adds/removes/updates occur.
@@ -404,9 +397,9 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
/**
* Evaluates the predicate on all registrations. The predicate should return true if the active
- * state of the registration may have changed as a result. Any {@link #updateService()}
- * invocations made while this method is executing will be deferred until after the method is
- * complete so as to avoid redundant work.
+ * state of the registration may have changed as a result. If the active state of any
+ * registration has changed, {@link #updateService()} will automatically be invoked to handle
+ * the resulting changes.
*/
protected final void updateRegistrations(@NonNull Predicate<TRegistration> predicate) {
synchronized (mRegistrations) {
@@ -415,7 +408,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
// callbacks. note that try-with-resources ordering is meaningful here as well. we want
// to close the reentrancy guard first, as this may generate additional service updates,
// then close the update service buffer.
- long identity = Binder.clearCallingIdentity();
try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
@@ -426,8 +418,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
onRegistrationActiveChanged(registration);
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
@@ -450,7 +440,10 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
execute(registration, operation);
}
} else {
- registration.onInactive();
+ ListenerOperation<TListener> operation = registration.onInactive();
+ if (operation != null) {
+ execute(registration, operation);
+ }
if (--mActiveRegistrationsCount == 0) {
onInactive();
}
@@ -468,7 +461,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
protected final void deliverToListeners(
@NonNull Function<TRegistration, ListenerOperation<TListener>> function) {
synchronized (mRegistrations) {
- long identity = Binder.clearCallingIdentity();
try (ReentrancyGuard ignored = mReentrancyGuard.acquire()) {
final int size = mRegistrations.size();
for (int i = 0; i < size; i++) {
@@ -480,8 +472,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
}
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
@@ -495,7 +485,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
*/
protected final void deliverToListeners(@NonNull ListenerOperation<TListener> operation) {
synchronized (mRegistrations) {
- long identity = Binder.clearCallingIdentity();
try (ReentrancyGuard ignored = mReentrancyGuard.acquire()) {
final int size = mRegistrations.size();
for (int i = 0; i < size; i++) {
@@ -504,8 +493,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
execute(registration, operation);
}
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
}
}
@@ -522,27 +509,26 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
/**
* Dumps debug information.
*/
- public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mRegistrations) {
- ipw.print("service: ");
- dumpServiceState(ipw);
- ipw.println();
+ pw.print("service: ");
+ dumpServiceState(pw);
+ pw.println();
if (!mRegistrations.isEmpty()) {
- ipw.println("listeners:");
+ pw.println("listeners:");
- ipw.increaseIndent();
final int size = mRegistrations.size();
for (int i = 0; i < size; i++) {
TRegistration registration = mRegistrations.valueAt(i);
- ipw.print(registration);
+ pw.print(" ");
+ pw.print(registration);
if (!registration.isActive()) {
- ipw.println(" (inactive)");
+ pw.println(" (inactive)");
} else {
- ipw.println();
+ pw.println();
}
}
- ipw.decreaseIndent();
}
}
}
@@ -577,7 +563,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
@GuardedBy("mRegistrations")
private int mGuardCount;
@GuardedBy("mRegistrations")
- private @Nullable ArraySet<Pair<Object, ListenerRegistration<?, ?>>> mScheduledRemovals;
+ private @Nullable ArraySet<Entry<Object, ListenerRegistration<?, ?>>> mScheduledRemovals;
ReentrancyGuard() {
mGuardCount = 0;
@@ -602,7 +588,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
if (mScheduledRemovals == null) {
mScheduledRemovals = new ArraySet<>(mRegistrations.size());
}
- mScheduledRemovals.add(new Pair<>(key, registration));
+ mScheduledRemovals.add(new AbstractMap.SimpleImmutableEntry<>(key, registration));
}
ReentrancyGuard acquire() {
@@ -612,7 +598,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
@Override
public void close() {
- ArraySet<Pair<Object, ListenerRegistration<?, ?>>> scheduledRemovals = null;
+ ArraySet<Entry<Object, ListenerRegistration<?, ?>>> scheduledRemovals = null;
Preconditions.checkState(mGuardCount > 0);
if (--mGuardCount == 0) {
@@ -620,14 +606,15 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
mScheduledRemovals = null;
}
- if (scheduledRemovals != null) {
- try (UpdateServiceBuffer ignored = mUpdateServiceBuffer.acquire()) {
- final int size = scheduledRemovals.size();
- for (int i = 0; i < size; i++) {
- Pair<Object, ListenerRegistration<?, ?>> pair = scheduledRemovals.valueAt(
- i);
- removeRegistration(pair.first, pair.second);
- }
+ if (scheduledRemovals == null) {
+ return;
+ }
+
+ try (UpdateServiceBuffer ignored = mUpdateServiceBuffer.acquire()) {
+ final int size = scheduledRemovals.size();
+ for (int i = 0; i < size; i++) {
+ Entry<Object, ListenerRegistration<?, ?>> entry = scheduledRemovals.valueAt(i);
+ removeRegistration(entry.getKey(), entry.getValue());
}
}
}
diff --git a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
index ac56c51568be..deb9660a1c82 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
@@ -17,55 +17,34 @@
package com.android.server.location.listeners;
-import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.location.util.identity.CallerIdentity;
-import android.os.Process;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.listeners.ListenerExecutor;
-import com.android.server.FgThread;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
* A listener registration object which holds data associated with the listener, such as an optional
- * request, and the identity of the listener owner.
+ * request, and an executor responsible for listener invocations.
*
* @param <TRequest> request type
* @param <TListener> listener type
*/
public class ListenerRegistration<TRequest, TListener> implements ListenerExecutor {
- @VisibleForTesting
- public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor();
-
private final Executor mExecutor;
private final @Nullable TRequest mRequest;
- private final CallerIdentity mIdentity;
private boolean mActive;
private volatile @Nullable TListener mListener;
- protected ListenerRegistration(@Nullable TRequest request, CallerIdentity identity,
+ protected ListenerRegistration(Executor executor, @Nullable TRequest request,
TListener listener) {
- // if a client is in the same process as us, binder calls will execute synchronously and
- // we shouldn't run callbacks directly since they might be run under lock and deadlock
- if (identity.getPid() == Process.myPid()) {
- // there's a slight loophole here for pending intents - pending intent callbacks can
- // always be run on the direct executor since they're always asynchronous, but honestly
- // you shouldn't be using pending intent callbacks within the same process anyways
- mExecutor = IN_PROCESS_EXECUTOR;
- } else {
- mExecutor = DIRECT_EXECUTOR;
- }
-
+ mExecutor = Objects.requireNonNull(executor);
mRequest = request;
- mIdentity = Objects.requireNonNull(identity);
mActive = false;
mListener = Objects.requireNonNull(listener);
}
@@ -82,34 +61,34 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut
}
/**
- * Returns the listener identity.
- */
- public final CallerIdentity getIdentity() {
- return mIdentity;
- }
-
- /**
- * May be overridden by subclasses. Invoked when registration occurs.
+ * May be overridden by subclasses. Invoked when registration occurs. Invoked while holding the
+ * owning multiplexer's internal lock.
*/
protected void onRegister(Object key) {}
/**
- * May be overridden by subclasses. Invoked when unregistration occurs.
+ * May be overridden by subclasses. Invoked when unregistration occurs. Invoked while holding
+ * the owning multiplexer's internal lock.
*/
protected void onUnregister() {}
/**
* May be overridden by subclasses. Invoked when this registration becomes active. If this
- * returns a non-null operation, that operation will be invoked for the listener.
+ * returns a non-null operation, that operation will be invoked for the listener. Invoked
+ * while holding the owning multiplexer's internal lock.
*/
protected @Nullable ListenerOperation<TListener> onActive() {
return null;
}
/**
- * May be overridden by subclasses. Invoked when registration becomes inactive.
+ * May be overridden by subclasses. Invoked when registration becomes inactive. If this returns
+ * a non-null operation, that operation will be invoked for the listener. Invoked while holding
+ * the owning multiplexer's internal lock.
*/
- protected void onInactive() {}
+ protected @Nullable ListenerOperation<TListener> onInactive() {
+ return null;
+ }
public final boolean isActive() {
return mActive;
@@ -136,8 +115,7 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut
/**
* May be overridden by subclasses, however should rarely be needed. Invoked when the listener
* associated with this registration is unregistered, which may occur before the registration
- * itself is unregistered. This immediately prevents the listener from being further invoked
- * even if the various bookkeeping associated with unregistration has not occurred yet.
+ * itself is unregistered. This immediately prevents the listener from being further invoked.
*/
protected void onListenerUnregister() {};
diff --git a/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java b/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java
index b5d2ef6a72ec..7b6154eb0d00 100644
--- a/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/PendingIntentListenerRegistration.java
@@ -30,7 +30,7 @@ import android.util.Log;
* @param <TListener> listener type
*/
public abstract class PendingIntentListenerRegistration<TRequest, TListener> extends
- RemovableListenerRegistration<TRequest, TListener> implements PendingIntent.CancelListener {
+ RemoteListenerRegistration<TRequest, TListener> implements PendingIntent.CancelListener {
/**
* Interface to allowed pending intent retrieval when keys are not themselves PendingIntents.
diff --git a/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java
new file mode 100644
index 000000000000..e4b0b190d34c
--- /dev/null
+++ b/services/core/java/com/android/server/location/listeners/RemoteListenerRegistration.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.listeners;
+
+
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
+import android.annotation.Nullable;
+import android.location.util.identity.CallerIdentity;
+import android.os.Process;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.FgThread;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * A listener registration representing a remote (possibly from a different process) listener.
+ * Listeners from a different process will be run on a direct executor, since the x-process listener
+ * invocation should already be asynchronous. Listeners from the same process will be run on a
+ * normal executor, since in-process listener invocation may be synchronous.
+ *
+ * @param <TRequest> request type
+ * @param <TListener> listener type
+ */
+public abstract class RemoteListenerRegistration<TRequest, TListener> extends
+ RemovableListenerRegistration<TRequest, TListener> {
+
+ @VisibleForTesting
+ public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor();
+
+ private static Executor chooseExecutor(CallerIdentity identity) {
+ // if a client is in the same process as us, binder calls will execute synchronously and
+ // we shouldn't run callbacks directly since they might be run under lock and deadlock
+ if (identity.getPid() == Process.myPid()) {
+ // there's a slight loophole here for pending intents - pending intent callbacks can
+ // always be run on the direct executor since they're always asynchronous, but honestly
+ // you shouldn't be using pending intent callbacks within the same process anyways
+ return IN_PROCESS_EXECUTOR;
+ } else {
+ return DIRECT_EXECUTOR;
+ }
+ }
+
+ private final CallerIdentity mIdentity;
+
+ protected RemoteListenerRegistration(String tag, @Nullable TRequest request,
+ CallerIdentity identity, TListener listener) {
+ super(tag, chooseExecutor(identity), request, listener);
+ mIdentity = Objects.requireNonNull(identity);
+ }
+
+ /**
+ * Returns the listener identity.
+ */
+ public final CallerIdentity getIdentity() {
+ return mIdentity;
+ }
+}
+
diff --git a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
index 0698cca903f0..2383bece4e0a 100644
--- a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
@@ -17,10 +17,10 @@
package com.android.server.location.listeners;
import android.annotation.Nullable;
-import android.location.util.identity.CallerIdentity;
import android.util.Log;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* A listener registration that stores its own key, and thus can remove itself. By default it will
@@ -36,9 +36,9 @@ public abstract class RemovableListenerRegistration<TRequest, TListener> extends
private volatile @Nullable Object mKey;
- protected RemovableListenerRegistration(String tag, @Nullable TRequest request,
- CallerIdentity callerIdentity, TListener listener) {
- super(request, callerIdentity, listener);
+ protected RemovableListenerRegistration(String tag, Executor executor,
+ @Nullable TRequest request, TListener listener) {
+ super(executor, request, listener);
mTag = Objects.requireNonNull(tag);
}
@@ -70,7 +70,7 @@ public abstract class RemovableListenerRegistration<TRequest, TListener> extends
@Override
public <Listener> void onOperationFailure(ListenerOperation<Listener> operation, Exception e) {
- Log.w(mTag, "registration " + getIdentity() + " removed due to unexpected exception", e);
+ Log.w(mTag, "registration " + this + " removed due to unexpected exception", e);
remove();
}
diff --git a/services/core/java/com/android/server/location/util/SystemSettingsHelper.java b/services/core/java/com/android/server/location/util/SystemSettingsHelper.java
index ff4ba914cb9c..39aeaba16579 100644
--- a/services/core/java/com/android/server/location/util/SystemSettingsHelper.java
+++ b/services/core/java/com/android/server/location/util/SystemSettingsHelper.java
@@ -29,6 +29,7 @@ import static com.android.server.location.LocationManagerService.D;
import static com.android.server.location.LocationManagerService.TAG;
import android.app.ActivityManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
@@ -330,11 +331,13 @@ public class SystemSettingsHelper extends SettingsHelper {
@Override
public float getCoarseLocationAccuracyM() {
long identity = Binder.clearCallingIdentity();
+ final ContentResolver cr = mContext.getContentResolver();
try {
- return Settings.Secure.getFloat(
- mContext.getContentResolver(),
+ return Settings.Secure.getFloatForUser(
+ cr,
LOCATION_COARSE_ACCURACY_M,
- DEFAULT_COARSE_LOCATION_ACCURACY_M);
+ DEFAULT_COARSE_LOCATION_ACCURACY_M,
+ cr.getUserId());
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 26c3132167d3..dbc725ea93e8 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -837,7 +837,7 @@ public class LockSettingsService extends ILockSettings.Stub {
if (getString("migrated", null, 0) == null) {
final ContentResolver cr = mContext.getContentResolver();
for (String validSetting : VALID_SETTINGS) {
- String value = Settings.Secure.getString(cr, validSetting);
+ String value = Settings.Secure.getStringForUser(cr, validSetting, cr.getUserId());
if (value != null) {
setString(validSetting, value, 0);
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index e9a05a8aa16c..715e41c62a05 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -746,7 +746,7 @@ class LockSettingsStorage {
public void dump(IndentingPrintWriter pw) {
final UserManager um = UserManager.get(mContext);
- for (UserInfo user : um.getUsers(false)) {
+ for (UserInfo user : um.getUsers()) {
File userPath = getSyntheticPasswordDirectoryForUser(user.id);
pw.println(String.format("User %d [%s]:", user.id, userPath.getAbsolutePath()));
pw.increaseIndent();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 29ee8eb13564..ded77b394066 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -518,8 +518,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final SparseBooleanArray mRestrictBackgroundAllowlistRevokedUids =
new SparseBooleanArray();
+ final Object mMeteredIfacesLock = new Object();
/** Set of ifaces that are metered. */
- @GuardedBy("mNetworkPoliciesSecondLock")
+ @GuardedBy("mMeteredIfacesLock")
private ArraySet<String> mMeteredIfaces = new ArraySet<>();
/** Set of over-limit templates that have been notified. */
@GuardedBy("mNetworkPoliciesSecondLock")
@@ -1972,13 +1973,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
// Remove quota from any interfaces that are no longer metered.
- for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
- final String iface = mMeteredIfaces.valueAt(i);
- if (!newMeteredIfaces.contains(iface)) {
- removeInterfaceQuotaAsync(iface);
+ synchronized (mMeteredIfacesLock) {
+ for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
+ final String iface = mMeteredIfaces.valueAt(i);
+ if (!newMeteredIfaces.contains(iface)) {
+ removeInterfaceQuotaAsync(iface);
+ }
}
+ mMeteredIfaces = newMeteredIfaces;
}
- mMeteredIfaces = newMeteredIfaces;
final ContentResolver cr = mContext.getContentResolver();
final boolean quotaEnabled = Settings.Global.getInt(cr,
@@ -2030,7 +2033,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mSubscriptionOpportunisticQuota.put(subId, quotaBytes);
}
- final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+ final String[] meteredIfaces;
+ synchronized (mMeteredIfacesLock) {
+ meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+ }
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
@@ -3436,7 +3442,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.print("Restrict background: "); fout.println(mRestrictBackground);
fout.print("Restrict power: "); fout.println(mRestrictPower);
fout.print("Device idle: "); fout.println(mDeviceIdleMode);
- fout.print("Metered ifaces: "); fout.println(mMeteredIfaces);
+ synchronized (mMeteredIfacesLock) {
+ fout.print("Metered ifaces: ");
+ fout.println(mMeteredIfaces);
+ }
fout.println();
fout.print("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
@@ -4632,7 +4641,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
case MSG_LIMIT_REACHED: {
final String iface = (String) msg.obj;
- synchronized (mNetworkPoliciesSecondLock) {
+ synchronized (mMeteredIfacesLock) {
// fast return if not needed.
if (!mMeteredIfaces.contains(iface)) {
return true;
@@ -5274,7 +5283,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
isBackgroundRestricted = mRestrictBackground;
}
final boolean isNetworkMetered;
- synchronized (mNetworkPoliciesSecondLock) {
+ synchronized (mMeteredIfacesLock) {
isNetworkMetered = mMeteredIfaces.contains(ifname);
}
final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index a604625460a7..74b7bd76b047 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1554,7 +1554,7 @@ abstract public class ManagedServices {
if (!isEnabledForCurrentProfiles()) {
return false;
}
- return this.userid == userId;
+ return userId == USER_ALL || userId == this.userid;
}
public boolean enabledAndUserMatches(int nid) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 04658555f22b..5bc6e237ef37 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -262,7 +262,6 @@ import com.android.server.EventLogTags;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.UiThread;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
@@ -966,8 +965,7 @@ public class NotificationManagerService extends SystemService {
nv.recycle();
}
reportUserInteraction(r);
- mAssistants.notifyAssistantActionClicked(
- r.getSbn(), actionIndex, action, generatedByAssistant);
+ mAssistants.notifyAssistantActionClicked(r.getSbn(), action, generatedByAssistant);
}
}
@@ -6261,6 +6259,8 @@ public class NotificationManagerService extends SystemService {
for (NotificationRecord r : enqueued) {
if (r.mUpdateTimeMs > mWhen) {
// At least one enqueue was posted after the cancel, so we're invalid
+ Slog.i(TAG, "notification cancel ignored due to newer enqueued entry"
+ + "key=" + r.getSbn().getKey());
return;
}
}
@@ -8629,12 +8629,25 @@ public class NotificationManagerService extends SystemService {
ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
}
- private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
+ @VisibleForTesting
+ boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
if (!listener.enabledAndUserMatches(sbn.getUserId())) {
return false;
}
- // TODO: remove this for older listeners.
- return true;
+ return isInteractionVisibleToListener(listener, sbn.getUserId());
+ }
+
+ /**
+ * Returns whether the given assistant should be informed about interactions on the given user.
+ *
+ * Normally an assistant would be able to see all interactions on the current user and any
+ * associated profiles because they are notification listeners, but since NASes have one
+ * instance per user, we want to filter out interactions that are not for the user that the
+ * given NAS is bound in.
+ */
+ private boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) {
+ boolean isAssistantService = mAssistants.isServiceTokenValidLocked(info.service);
+ return !isAssistantService || info.isSameUser(userId);
}
private boolean isPackageSuspendedForUser(String pkg, int uid) {
@@ -8856,8 +8869,6 @@ public class NotificationManagerService extends SystemService {
}
protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
- // There should be only one, but it's a list, so while we enforce
- // singularity elsewhere, we keep it general here, to avoid surprises.
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
ArrayList<String> keys = new ArrayList<>(records.size());
for (NotificationRecord r : records) {
@@ -8875,6 +8886,8 @@ public class NotificationManagerService extends SystemService {
}
protected void onPanelRevealed(int items) {
+ // send to all currently bounds NASes since notifications from both users will appear in
+ // the panel
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
mHandler.post(() -> {
final INotificationListener assistant = (INotificationListener) info.service;
@@ -8888,6 +8901,8 @@ public class NotificationManagerService extends SystemService {
}
protected void onPanelHidden() {
+ // send to all currently bounds NASes since notifications from both users will appear in
+ // the panel
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
mHandler.post(() -> {
final INotificationListener assistant = (INotificationListener) info.service;
@@ -8976,7 +8991,7 @@ public class NotificationManagerService extends SystemService {
}
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onNotificationVisibilityChanged(key, isVisible);
@@ -8994,7 +9009,7 @@ public class NotificationManagerService extends SystemService {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
@@ -9010,7 +9025,7 @@ public class NotificationManagerService extends SystemService {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onNotificationDirectReply(key);
@@ -9026,7 +9041,7 @@ public class NotificationManagerService extends SystemService {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onSuggestedReplySent(
@@ -9043,12 +9058,12 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
void notifyAssistantActionClicked(
- final StatusBarNotification sbn, int actionIndex, Notification.Action action,
+ final StatusBarNotification sbn, Notification.Action action,
boolean generatedByAssistant) {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onActionClicked(
@@ -9072,7 +9087,7 @@ public class NotificationManagerService extends SystemService {
final StatusBarNotification sbn, final String snoozeCriterionId) {
notifyAssistantLocked(
sbn,
- false /* sameUserOnly */,
+ true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
assistant.onNotificationSnoozedUntilContext(
@@ -9129,7 +9144,7 @@ public class NotificationManagerService extends SystemService {
}
protected void resetDefaultAssistantsIfNecessary() {
- final List<UserInfo> activeUsers = mUm.getUsers(true);
+ final List<UserInfo> activeUsers = mUm.getAliveUsers();
for (UserInfo userInfo : activeUsers) {
int userId = userInfo.getUserHandle().getIdentifier();
if (!hasUserSet(userId)) {
@@ -9293,10 +9308,12 @@ public class NotificationManagerService extends SystemService {
}
public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+ // send to all currently bounds NASes since notifications from both users will appear in
+ // the status bar
for (final ManagedServiceInfo info : getServices()) {
mHandler.post(() -> {
final INotificationListener listener = (INotificationListener) info.service;
- try {
+ try {
listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener "
@@ -9470,7 +9487,8 @@ public class NotificationManagerService extends SystemService {
&& changedHiddenNotifications.size() > 0;
for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.isEnabledForCurrentProfiles()) {
+ if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
+ serviceInfo, ActivityManager.getCurrentUser())) {
continue;
}
@@ -9489,12 +9507,7 @@ public class NotificationManagerService extends SystemService {
final NotificationRankingUpdate update = makeRankingUpdateLocked(
serviceInfo);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- notifyRankingUpdate(serviceInfo, update);
- }
- });
+ mHandler.post(() -> notifyRankingUpdate(serviceInfo, update));
}
}
}
@@ -9502,15 +9515,11 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
public void notifyListenerHintsChangedLocked(final int hints) {
for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.isEnabledForCurrentProfiles()) {
+ if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
+ serviceInfo, ActivityManager.getCurrentUser())) {
continue;
}
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- notifyListenerHintsChanged(serviceInfo, hints);
- }
- });
+ mHandler.post(() -> notifyListenerHintsChanged(serviceInfo, hints));
}
}
@@ -9562,15 +9571,12 @@ public class NotificationManagerService extends SystemService {
public void notifyInterruptionFilterChanged(final int interruptionFilter) {
for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.isEnabledForCurrentProfiles()) {
+ if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
+ serviceInfo, ActivityManager.getCurrentUser())) {
continue;
}
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
- }
- });
+ mHandler.post(
+ () -> notifyInterruptionFilterChanged(serviceInfo, interruptionFilter));
}
}
@@ -9579,15 +9585,16 @@ public class NotificationManagerService extends SystemService {
if (channel == null) {
return;
}
- for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
+ for (final ManagedServiceInfo info : getServices()) {
+ if (!info.enabledAndUserMatches(UserHandle.getCallingUserId())
+ || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) {
continue;
}
BackgroundThread.getHandler().post(() -> {
- if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) {
+ if (info.isSystem || hasCompanionDevice(info)) {
notifyNotificationChannelChanged(
- serviceInfo, pkg, user, channel, modificationType);
+ info, pkg, user, channel, modificationType);
}
});
}
@@ -9599,15 +9606,16 @@ public class NotificationManagerService extends SystemService {
if (group == null) {
return;
}
- for (final ManagedServiceInfo serviceInfo : getServices()) {
- if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
+ for (final ManagedServiceInfo info : getServices()) {
+ if (!info.enabledAndUserMatches(UserHandle.getCallingUserId())
+ || !isInteractionVisibleToListener(info, UserHandle.getCallingUserId())) {
continue;
}
BackgroundThread.getHandler().post(() -> {
- if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) {
+ if (info.isSystem || hasCompanionDevice(info)) {
notifyNotificationChannelGroupChanged(
- serviceInfo, pkg, user, group, modificationType);
+ info, pkg, user, group, modificationType);
}
});
}
@@ -9626,9 +9634,6 @@ public class NotificationManagerService extends SystemService {
private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
- if (!info.enabledAndUserMatches(sbn.getUserId())) {
- return;
- }
final INotificationListener listener = (INotificationListener) info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index a4debc16493a..d7a1ba2a93d4 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -288,7 +288,7 @@ public final class OverlayManagerService extends SystemService {
private void initIfNeeded() {
final UserManager um = getContext().getSystemService(UserManager.class);
- final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
+ final List<UserInfo> users = um.getAliveUsers();
synchronized (mLock) {
final int userCount = users.size();
for (int i = 0; i < userCount; i++) {
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
new file mode 100644
index 000000000000..0338ed802436
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.EXTRA_CHECKSUMS;
+import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA256;
+import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA512;
+import static android.content.pm.PackageManager.WHOLE_MD5;
+import static android.content.pm.PackageManager.WHOLE_MERKLE_ROOT_4K_SHA256;
+import static android.content.pm.PackageManager.WHOLE_SHA1;
+import static android.content.pm.PackageManager.WHOLE_SHA256;
+import static android.content.pm.PackageManager.WHOLE_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.FileChecksum;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalStorage;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.apk.ApkSignatureSchemeV2Verifier;
+import android.util.apk.ApkSignatureSchemeV3Verifier;
+import android.util.apk.ApkSignatureSchemeV4Verifier;
+import android.util.apk.ApkSignatureVerifier;
+import android.util.apk.ApkSigningBlockUtils;
+import android.util.apk.ByteBufferFactory;
+import android.util.apk.SignatureInfo;
+import android.util.apk.SignatureNotFoundException;
+import android.util.apk.VerityBuilder;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.security.VerityUtils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides checksums for APK.
+ */
+public class ApkChecksums {
+ static final String TAG = "ApkChecksums";
+
+ // MessageDigest algorithms.
+ static final String ALGO_MD5 = "MD5";
+ static final String ALGO_SHA1 = "SHA1";
+ static final String ALGO_SHA256 = "SHA256";
+ static final String ALGO_SHA512 = "SHA512";
+
+ /**
+ * Check back in 1 second after we detected we needed to wait for the APK to be fully available.
+ */
+ private static final long PROCESS_REQUIRED_CHECKSUMS_DELAY_MILLIS = 1000;
+
+ /**
+ * 24 hours timeout to wait till all files are loaded.
+ */
+ private static final long PROCESS_REQUIRED_CHECKSUMS_TIMEOUT_MILLIS = 1000 * 3600 * 24;
+
+ /**
+ * Unit tests will instantiate, extend and/or mock to mock dependencies / behaviors.
+ *
+ * NOTE: All getters should return the same instance for every call.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ static class Injector {
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ interface Producer<T> {
+ /** Produce an instance of type {@link T} */
+ T produce();
+ }
+
+ private final Producer<Context> mContext;
+ private final Producer<Handler> mHandlerProducer;
+ private final Producer<IncrementalManager> mIncrementalManagerProducer;
+
+ Injector(Producer<Context> context, Producer<Handler> handlerProducer,
+ Producer<IncrementalManager> incrementalManagerProducer) {
+ mContext = context;
+ mHandlerProducer = handlerProducer;
+ mIncrementalManagerProducer = incrementalManagerProducer;
+ }
+
+ public Context getContext() {
+ return mContext.produce();
+ }
+
+ public Handler getHandler() {
+ return mHandlerProducer.produce();
+ }
+
+ public IncrementalManager getIncrementalManager() {
+ return mIncrementalManagerProducer.produce();
+ }
+ }
+
+ /**
+ * Fetch or calculate checksums for the collection of files.
+ *
+ * @param filesToChecksum split name, null for base and File to fetch checksums for
+ * @param optional mask to fetch readily available checksums
+ * @param required mask to forcefully calculate if not available
+ * @param trustedInstallers array of certificate to trust, two specific cases:
+ * null - trust anybody,
+ * [] - trust nobody.
+ * @param statusReceiver to receive the resulting checksums
+ */
+ public static void getChecksums(List<Pair<String, File>> filesToChecksum,
+ @PackageManager.FileChecksumKind int optional,
+ @PackageManager.FileChecksumKind int required,
+ @Nullable Certificate[] trustedInstallers,
+ @NonNull IntentSender statusReceiver,
+ @NonNull Injector injector) {
+ List<Map<Integer, FileChecksum>> result = new ArrayList<>(filesToChecksum.size());
+ for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
+ final String split = filesToChecksum.get(i).first;
+ final File file = filesToChecksum.get(i).second;
+ Map<Integer, FileChecksum> checksums = new ArrayMap<>();
+ result.add(checksums);
+
+ try {
+ getAvailableFileChecksums(split, file, optional | required, trustedInstallers,
+ checksums);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Preferred checksum calculation error", e);
+ }
+ }
+
+ long startTime = SystemClock.uptimeMillis();
+ processRequiredChecksums(filesToChecksum, result, required, statusReceiver, injector,
+ startTime);
+ }
+
+ private static void processRequiredChecksums(List<Pair<String, File>> filesToChecksum,
+ List<Map<Integer, FileChecksum>> result,
+ @PackageManager.FileChecksumKind int required,
+ @NonNull IntentSender statusReceiver,
+ @NonNull Injector injector,
+ long startTime) {
+ final boolean timeout =
+ SystemClock.uptimeMillis() - startTime >= PROCESS_REQUIRED_CHECKSUMS_TIMEOUT_MILLIS;
+ List<FileChecksum> allChecksums = new ArrayList<>();
+ for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
+ final String split = filesToChecksum.get(i).first;
+ final File file = filesToChecksum.get(i).second;
+ Map<Integer, FileChecksum> checksums = result.get(i);
+
+ try {
+ if (!timeout || required != 0) {
+ if (needToWait(file, required, checksums, injector)) {
+ // Not ready, come back later.
+ injector.getHandler().postDelayed(() -> {
+ processRequiredChecksums(filesToChecksum, result, required,
+ statusReceiver, injector, startTime);
+ }, PROCESS_REQUIRED_CHECKSUMS_DELAY_MILLIS);
+ return;
+ }
+
+ getRequiredFileChecksums(split, file, required, checksums);
+ }
+ allChecksums.addAll(checksums.values());
+ } catch (Throwable e) {
+ Slog.e(TAG, "Required checksum calculation error", e);
+ }
+ }
+
+ final Intent intent = new Intent();
+ intent.putExtra(EXTRA_CHECKSUMS,
+ allChecksums.toArray(new FileChecksum[allChecksums.size()]));
+
+ try {
+ statusReceiver.sendIntent(injector.getContext(), 1, intent, null, null);
+ } catch (IntentSender.SendIntentException e) {
+ Slog.w(TAG, e);
+ }
+ }
+
+ /**
+ * Fetch readily available checksums - enforced by kernel or provided by Installer.
+ *
+ * @param split split name, null for base
+ * @param file to fetch checksums for
+ * @param kinds mask to fetch checksums
+ * @param trustedInstallers array of certificate to trust, two specific cases:
+ * null - trust anybody,
+ * [] - trust nobody.
+ * @param checksums resulting checksums
+ */
+ private static void getAvailableFileChecksums(String split, File file,
+ @PackageManager.FileChecksumKind int kinds,
+ @Nullable Certificate[] trustedInstallers,
+ Map<Integer, FileChecksum> checksums) {
+ final String filePath = file.getAbsolutePath();
+
+ // Always available: FSI or IncFs.
+ if (isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums)) {
+ // Hashes in fs-verity and IncFS are always verified.
+ FileChecksum checksum = extractHashFromFS(split, filePath);
+ if (checksum != null) {
+ checksums.put(checksum.getKind(), checksum);
+ }
+ }
+
+ // System enforced: v2/v3.
+ if (isRequired(PARTIAL_MERKLE_ROOT_1M_SHA256, kinds, checksums) || isRequired(
+ PARTIAL_MERKLE_ROOT_1M_SHA512, kinds, checksums)) {
+ Map<Integer, FileChecksum> v2v3checksums = extractHashFromV2V3Signature(
+ split, filePath, kinds);
+ if (v2v3checksums != null) {
+ checksums.putAll(v2v3checksums);
+ }
+ }
+
+ // TODO(b/160605420): Installer provided.
+ }
+
+ /**
+ * Whether the file is available for checksumming or we need to wait.
+ */
+ private static boolean needToWait(File file,
+ @PackageManager.FileChecksumKind int kinds,
+ Map<Integer, FileChecksum> checksums,
+ @NonNull Injector injector) throws IOException {
+ if (!isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums)
+ && !isRequired(WHOLE_MD5, kinds, checksums)
+ && !isRequired(WHOLE_SHA1, kinds, checksums)
+ && !isRequired(WHOLE_SHA256, kinds, checksums)
+ && !isRequired(WHOLE_SHA512, kinds, checksums)
+ && !isRequired(PARTIAL_MERKLE_ROOT_1M_SHA256, kinds, checksums)
+ && !isRequired(PARTIAL_MERKLE_ROOT_1M_SHA512, kinds, checksums)) {
+ return false;
+ }
+
+ final String filePath = file.getAbsolutePath();
+ if (!IncrementalManager.isIncrementalPath(filePath)) {
+ return false;
+ }
+
+ IncrementalManager manager = injector.getIncrementalManager();
+ if (manager == null) {
+ throw new IllegalStateException("IncrementalManager is missing.");
+ }
+ IncrementalStorage storage = manager.openStorage(filePath);
+ if (storage == null) {
+ throw new IllegalStateException(
+ "IncrementalStorage is missing for a path on IncFs: " + filePath);
+ }
+
+ return !storage.isFileFullyLoaded(filePath);
+ }
+
+ /**
+ * Fetch or calculate checksums for the specific file.
+ *
+ * @param split split name, null for base
+ * @param file to fetch checksums for
+ * @param kinds mask to forcefully calculate if not available
+ * @param checksums resulting checksums
+ */
+ private static void getRequiredFileChecksums(String split, File file,
+ @PackageManager.FileChecksumKind int kinds,
+ Map<Integer, FileChecksum> checksums) {
+ final String filePath = file.getAbsolutePath();
+
+ // Manually calculating required checksums if not readily available.
+ if (isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums)) {
+ try {
+ byte[] generatedRootHash = VerityBuilder.generateFsVerityRootHash(
+ filePath, /*salt=*/null,
+ new ByteBufferFactory() {
+ @Override
+ public ByteBuffer create(int capacity) {
+ return ByteBuffer.allocate(capacity);
+ }
+ });
+ checksums.put(WHOLE_MERKLE_ROOT_4K_SHA256,
+ new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, generatedRootHash));
+ } catch (IOException | NoSuchAlgorithmException | DigestException e) {
+ Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e);
+ }
+ }
+
+ calculateChecksumIfRequested(checksums, split, file, kinds, WHOLE_MD5);
+ calculateChecksumIfRequested(checksums, split, file, kinds, WHOLE_SHA1);
+ calculateChecksumIfRequested(checksums, split, file, kinds, WHOLE_SHA256);
+ calculateChecksumIfRequested(checksums, split, file, kinds, WHOLE_SHA512);
+
+ calculatePartialChecksumsIfRequested(checksums, split, file, kinds);
+ }
+
+ private static boolean isRequired(@PackageManager.FileChecksumKind int kind,
+ @PackageManager.FileChecksumKind int kinds, Map<Integer, FileChecksum> checksums) {
+ if ((kinds & kind) == 0) {
+ return false;
+ }
+ if (checksums.containsKey(kind)) {
+ return false;
+ }
+ return true;
+ }
+
+ private static FileChecksum extractHashFromFS(String split, String filePath) {
+ // verity first
+ {
+ byte[] hash = VerityUtils.getFsverityRootHash(filePath);
+ if (hash != null) {
+ return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+ }
+ }
+ // v4 next
+ try {
+ ApkSignatureSchemeV4Verifier.VerifiedSigner signer =
+ ApkSignatureSchemeV4Verifier.extractCertificates(filePath);
+ byte[] hash = signer.contentDigests.getOrDefault(CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
+ null);
+ if (hash != null) {
+ return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash);
+ }
+ } catch (SignatureNotFoundException e) {
+ // Nothing
+ } catch (SecurityException e) {
+ Slog.e(TAG, "V4 signature error", e);
+ }
+ return null;
+ }
+
+ private static Map<Integer, FileChecksum> extractHashFromV2V3Signature(
+ String split, String filePath, int kinds) {
+ Map<Integer, byte[]> contentDigests = null;
+ try {
+ contentDigests = ApkSignatureVerifier.verifySignaturesInternal(filePath,
+ PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2,
+ false).contentDigests;
+ } catch (PackageParser.PackageParserException e) {
+ if (!(e.getCause() instanceof SignatureNotFoundException)) {
+ Slog.e(TAG, "Signature verification error", e);
+ }
+ }
+
+ if (contentDigests == null) {
+ return null;
+ }
+
+ Map<Integer, FileChecksum> checksums = new ArrayMap<>();
+ if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0) {
+ byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA256, null);
+ if (hash != null) {
+ checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA256,
+ new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA256, hash));
+ }
+ }
+ if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA512) != 0) {
+ byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA512, null);
+ if (hash != null) {
+ checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA512,
+ new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA512, hash));
+ }
+ }
+ return checksums;
+ }
+
+ private static String getMessageDigestAlgoForChecksumKind(int kind)
+ throws NoSuchAlgorithmException {
+ switch (kind) {
+ case WHOLE_MD5:
+ return ALGO_MD5;
+ case WHOLE_SHA1:
+ return ALGO_SHA1;
+ case WHOLE_SHA256:
+ return ALGO_SHA256;
+ case WHOLE_SHA512:
+ return ALGO_SHA512;
+ default:
+ throw new NoSuchAlgorithmException("Invalid checksum kind: " + kind);
+ }
+ }
+
+ private static void calculateChecksumIfRequested(Map<Integer, FileChecksum> checksums,
+ String split, File file, int required, int kind) {
+ if ((required & kind) != 0 && !checksums.containsKey(kind)) {
+ final byte[] checksum = getFileChecksum(file, kind);
+ if (checksum != null) {
+ checksums.put(kind, new FileChecksum(split, kind, checksum));
+ }
+ }
+ }
+
+ private static byte[] getFileChecksum(File file, int kind) {
+ try (FileInputStream fis = new FileInputStream(file);
+ BufferedInputStream bis = new BufferedInputStream(fis)) {
+ byte[] dataBytes = new byte[512 * 1024];
+ int nread = 0;
+
+ final String algo = getMessageDigestAlgoForChecksumKind(kind);
+ MessageDigest md = MessageDigest.getInstance(algo);
+ while ((nread = bis.read(dataBytes)) != -1) {
+ md.update(dataBytes, 0, nread);
+ }
+
+ return md.digest();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading " + file.getAbsolutePath() + " to compute hash.", e);
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ Slog.e(TAG, "Device does not support MessageDigest algorithm", e);
+ return null;
+ }
+ }
+
+ private static int[] getContentDigestAlgos(boolean needSignatureSha256,
+ boolean needSignatureSha512) {
+ if (needSignatureSha256 && needSignatureSha512) {
+ // Signature block present, but no digests???
+ return new int[]{CONTENT_DIGEST_CHUNKED_SHA256, CONTENT_DIGEST_CHUNKED_SHA512};
+ } else if (needSignatureSha256) {
+ return new int[]{CONTENT_DIGEST_CHUNKED_SHA256};
+ } else {
+ return new int[]{CONTENT_DIGEST_CHUNKED_SHA512};
+ }
+ }
+
+ private static int getChecksumKindForContentDigestAlgo(int contentDigestAlgo) {
+ switch (contentDigestAlgo) {
+ case CONTENT_DIGEST_CHUNKED_SHA256:
+ return PARTIAL_MERKLE_ROOT_1M_SHA256;
+ case CONTENT_DIGEST_CHUNKED_SHA512:
+ return PARTIAL_MERKLE_ROOT_1M_SHA512;
+ default:
+ return -1;
+ }
+ }
+
+ private static void calculatePartialChecksumsIfRequested(Map<Integer, FileChecksum> checksums,
+ String split, File file, int required) {
+ boolean needSignatureSha256 =
+ (required & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0 && !checksums.containsKey(
+ PARTIAL_MERKLE_ROOT_1M_SHA256);
+ boolean needSignatureSha512 =
+ (required & PARTIAL_MERKLE_ROOT_1M_SHA512) != 0 && !checksums.containsKey(
+ PARTIAL_MERKLE_ROOT_1M_SHA512);
+ if (!needSignatureSha256 && !needSignatureSha512) {
+ return;
+ }
+
+ try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
+ SignatureInfo signatureInfo = null;
+ try {
+ signatureInfo = ApkSignatureSchemeV3Verifier.findSignature(raf);
+ } catch (SignatureNotFoundException e) {
+ try {
+ signatureInfo = ApkSignatureSchemeV2Verifier.findSignature(raf);
+ } catch (SignatureNotFoundException ee) {
+ }
+ }
+ if (signatureInfo == null) {
+ Slog.e(TAG, "V2/V3 signatures not found in " + file.getAbsolutePath());
+ return;
+ }
+
+ final int[] digestAlgos = getContentDigestAlgos(needSignatureSha256,
+ needSignatureSha512);
+ byte[][] digests = ApkSigningBlockUtils.computeContentDigestsPer1MbChunk(digestAlgos,
+ raf.getFD(), signatureInfo);
+ for (int i = 0, size = digestAlgos.length; i < size; ++i) {
+ int checksumKind = getChecksumKindForContentDigestAlgo(digestAlgos[i]);
+ if (checksumKind != -1) {
+ checksums.put(checksumKind, new FileChecksum(split, checksumKind, digests[i]));
+ }
+ }
+ } catch (IOException | DigestException e) {
+ Slog.e(TAG, "Error computing hash.", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 3d7c978ca625..f168ac70dda8 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -560,9 +560,9 @@ public class AppsFilter {
final boolean newIsForceQueryable =
mForceQueryable.contains(newPkgSetting.appId)
/* shared user that is already force queryable */
- || newPkg.isForceQueryable()
- || newPkgSetting.forceQueryableOverride
+ || newPkgSetting.forceQueryableOverride /* adb override */
|| (newPkgSetting.isSystem() && (mSystemAppsQueryable
+ || newPkg.isForceQueryable()
|| ArrayUtils.contains(mForceQueryableByDevicePackageNames,
newPkg.getPackageName())));
if (newIsForceQueryable
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 3f6b8e92ef74..d25ddad174f9 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -890,54 +890,55 @@ public class ComponentResolver {
return;
}
- if (systemActivities == null) {
- // the system package is not disabled; we're parsing the system partition
- if (isProtectedAction(intent)) {
- if (mDeferProtectedFilters) {
- // We can't deal with these just yet. No component should ever obtain a
- // >0 priority for a protected actions, with ONE exception -- the setup
- // wizard. The setup wizard, however, cannot be known until we're able to
- // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
- // until all intent filters have been processed. Chicken, meet egg.
- // Let the filter temporarily have a high priority and rectify the
- // priorities after all system packages have been scanned.
- if (mProtectedFilters == null) {
- mProtectedFilters = new ArrayList<>();
- }
- mProtectedFilters.add(Pair.create(activity, intent));
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Protected action; save for later;"
- + " package: " + packageName
- + " activity: " + className
- + " origPrio: " + intent.getPriority());
- }
- return;
- } else {
- if (DEBUG_FILTERS && setupWizardPackage == null) {
- Slog.i(TAG, "No setup wizard;"
- + " All protected intents capped to priority 0");
- }
- if (packageName.equals(setupWizardPackage)) {
- if (DEBUG_FILTERS) {
- Slog.i(TAG, "Found setup wizard;"
- + " allow priority " + intent.getPriority() + ";"
- + " package: " + packageName
- + " activity: " + className
- + " priority: " + intent.getPriority());
- }
- // setup wizard gets whatever it wants
- return;
- }
+ if (isProtectedAction(intent)) {
+ if (mDeferProtectedFilters) {
+ // We can't deal with these just yet. No component should ever obtain a
+ // >0 priority for a protected actions, with ONE exception -- the setup
+ // wizard. The setup wizard, however, cannot be known until we're able to
+ // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
+ // until all intent filters have been processed. Chicken, meet egg.
+ // Let the filter temporarily have a high priority and rectify the
+ // priorities after all system packages have been scanned.
+ if (mProtectedFilters == null) {
+ mProtectedFilters = new ArrayList<>();
+ }
+ mProtectedFilters.add(Pair.create(activity, intent));
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Protected action; save for later;"
+ + " package: " + packageName
+ + " activity: " + className
+ + " origPrio: " + intent.getPriority());
+ }
+ } else {
+ if (DEBUG_FILTERS && setupWizardPackage == null) {
+ Slog.i(TAG, "No setup wizard;"
+ + " All protected intents capped to priority 0");
+ }
+ if (packageName.equals(setupWizardPackage)) {
if (DEBUG_FILTERS) {
- Slog.i(TAG, "Protected action; cap priority to 0;"
+ Slog.i(TAG, "Found setup wizard;"
+ + " allow priority " + intent.getPriority() + ";"
+ " package: " + packageName
+ " activity: " + className
- + " origPrio: " + intent.getPriority());
+ + " priority: " + intent.getPriority());
}
- intent.setPriority(0);
+ // setup wizard gets whatever it wants
return;
}
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Protected action; cap priority to 0;"
+ + " package: " + packageName
+ + " activity: " + className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
}
+ return;
+ }
+
+ if (systemActivities == null) {
+ // the system package is not disabled; we're parsing the system partition
+
// privileged apps on the system image get whatever priority they request
return;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 4b246c3b330c..155af82289d4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -656,7 +656,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
throw new IllegalArgumentException("Invalid install mode: " + params.mode);
}
- // If caller requested explicit location, sanity check it, otherwise
+ // If caller requested explicit location, validity check it, otherwise
// resolve the best internal or adopted location.
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
if (!PackageHelper.fitsOnInternal(mContext, params)) {
@@ -688,7 +688,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
final int sessionId;
final PackageInstallerSession session;
synchronized (mSessions) {
- // Sanity check that installer isn't going crazy
+ // Check that the installer does not have too many active sessions.
final int activeCount = getSessionCount(mSessions, callingUid);
if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
== PackageManager.PERMISSION_GRANTED) {
@@ -743,9 +743,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mStagingManager.createSession(session);
}
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionCreated(session.sessionId, session.userId);
- }
+ mCallbacks.notifySessionCreated(session.sessionId, session.userId);
+
writeSessionsAsync();
return sessionId;
}
@@ -1355,25 +1354,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
class InternalCallback {
public void onSessionBadgingChanged(PackageInstallerSession session) {
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
- }
-
+ mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId);
writeSessionsAsync();
}
public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId,
- active);
- }
+ mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId,
+ active);
}
public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId,
- progress);
- }
+ mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId,
+ progress);
}
public void onStagedSessionChanged(PackageInstallerSession session) {
@@ -1389,17 +1381,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
public void onSessionFinished(final PackageInstallerSession session, boolean success) {
- if ((session.params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
- }
+ mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
mInstallHandler.post(new Runnable() {
@Override
public void run() {
- if (session.isStaged()) {
- if (!success) {
- mStagingManager.abortSession(session);
- }
+ if (session.isStaged() && !success) {
+ mStagingManager.abortSession(session);
}
synchronized (mSessions) {
if (!session.isStaged() || !success) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ed62362b04fb..ca125320bbf2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -249,6 +249,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private final PackageManagerService mPm;
private final Handler mHandler;
private final PackageSessionProvider mSessionProvider;
+ /**
+ * Note all calls must be done outside {@link #mLock} to prevent lock inversion.
+ */
private final StagingManager mStagingManager;
final int sessionId;
@@ -389,6 +392,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private String mStagedSessionErrorMessage;
/**
+ * The callback to run when pre-reboot verification has ended. Used by {@link #abandonStaged()}
+ * to delay session clean-up until it is safe to do so.
+ */
+ @GuardedBy("mLock")
+ @Nullable
+ private Runnable mPendingAbandonCallback;
+ /**
+ * {@code true} if pre-reboot verification is ongoing which means it is not safe for
+ * {@link #abandon()} to clean up staging directories.
+ */
+ @GuardedBy("mLock")
+ private boolean mInPreRebootVerification;
+
+ /**
* Path to the validated base APK for this session, which may point at an
* APK inside the session (when the session defines the base), or it may
* point at the existing base APK (when adding splits to an existing app).
@@ -978,7 +995,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
ParcelFileDescriptor incomingFd) throws IOException {
- // Quick sanity check of state, and allocate a pipe for ourselves. We
+ // Quick validity check of state, and allocate a pipe for ourselves. We
// then do heavy disk allocation outside the lock, but this open pipe
// will block any attempted install transitions.
final RevocableFileDescriptor fd;
@@ -1454,26 +1471,54 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// TODO(patb): since the work done here for a parent session in a multi-package install is
// mostly superficial, consider splitting this method for the parent and
// single / child sessions.
- synchronized (mLock) {
- if (mCommitted) {
- return true;
+ try {
+ synchronized (mLock) {
+ if (mCommitted) {
+ return true;
+ }
+ // Read transfers from the original owner stay open, but as the session's data
+ // cannot be modified anymore, there is no leak of information. For staged sessions,
+ // further validation is performed by the staging manager.
+ if (!params.isMultiPackage) {
+ if (!prepareDataLoaderLocked()) {
+ return false;
+ }
+
+ if (isApexInstallation()) {
+ validateApexInstallLocked();
+ } else {
+ validateApkInstallLocked();
+ }
+ }
}
- if (!streamAndValidateLocked()) {
- return false;
+ if (params.isStaged) {
+ mStagingManager.checkNonOverlappingWithStagedSessions(this);
}
- // Client staging is fully done at this point
- mClientProgress = 1f;
- computeProgressLocked(true);
+ synchronized (mLock) {
+ if (mDestroyed) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Session destroyed");
+ }
+ // Client staging is fully done at this point
+ mClientProgress = 1f;
+ computeProgressLocked(true);
- // This ongoing commit should keep session active, even though client
- // will probably close their end.
- mActiveCount.incrementAndGet();
+ // This ongoing commit should keep session active, even though client
+ // will probably close their end.
+ mActiveCount.incrementAndGet();
- mCommitted = true;
+ mCommitted = true;
+ }
+ return true;
+ } catch (PackageManagerException e) {
+ throw onSessionValidationFailure(e);
+ } catch (Throwable e) {
+ // Convert all exceptions into package manager exceptions as only those are handled
+ // in the code above.
+ throw onSessionValidationFailure(new PackageManagerException(e));
}
- return true;
}
@GuardedBy("mLock")
@@ -1511,44 +1556,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- /**
- * Prepare DataLoader and stream content for DataLoader sessions.
- * Validate the contents of all session.
- *
- * @return false if the data loader could not be prepared.
- * @throws PackageManagerException when an unrecoverable exception is encountered
- */
- @GuardedBy("mLock")
- private boolean streamAndValidateLocked() throws PackageManagerException {
- try {
- // Read transfers from the original owner stay open, but as the session's data cannot
- // be modified anymore, there is no leak of information. For staged sessions, further
- // validation is performed by the staging manager.
- if (!params.isMultiPackage) {
- if (!prepareDataLoaderLocked()) {
- return false;
- }
-
- if (isApexInstallation()) {
- validateApexInstallLocked();
- } else {
- validateApkInstallLocked();
- }
- }
-
- if (params.isStaged) {
- mStagingManager.checkNonOverlappingWithStagedSessions(this);
- }
- return true;
- } catch (PackageManagerException e) {
- throw onSessionValidationFailure(e);
- } catch (Throwable e) {
- // Convert all exceptions into package manager exceptions as only those are handled
- // in the code above.
- throw onSessionValidationFailure(new PackageManagerException(e));
- }
- }
-
private PackageManagerException onSessionValidationFailure(PackageManagerException e) {
onSessionValidationFailure(e.error, ExceptionUtils.getCompleteMessage(e));
return e;
@@ -1561,19 +1568,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
dispatchSessionFinished(error, detailMessage, null);
}
- private void onSessionVerificationFailure(int error, String detailMessage) {
- Slog.e(TAG, "Failed to verify session " + sessionId + " [" + detailMessage + "]");
+ private void onSessionVerificationFailure(int error, String msg) {
+ final String msgWithErrorCode = PackageManager.installStatusToString(error, msg);
+ Slog.e(TAG, "Failed to verify session " + sessionId + " [" + msgWithErrorCode + "]");
// Session is sealed and committed but could not be verified, we need to destroy it.
destroyInternal();
if (isStaged()) {
setStagedSessionFailed(
- SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, detailMessage);
+ SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, msgWithErrorCode);
// TODO(b/136257624): Remove this once all verification logic has been transferred out
// of StagingManager.
- mStagingManager.notifyVerificationComplete(sessionId);
+ mStagingManager.notifyVerificationComplete(this);
} else {
// Dispatch message to remove session from PackageInstallerService.
- dispatchSessionFinished(error, detailMessage, null);
+ dispatchSessionFinished(error, msg, null);
}
}
@@ -1836,21 +1844,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throws PackageManagerException {
assertNotLocked("makeSessionActive");
- synchronized (mLock) {
- if (mRelinquished) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Session relinquished");
- }
- if (mDestroyed) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Session destroyed");
- }
- if (!mSealed) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Session not sealed");
- }
- }
-
// TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
if (!params.isMultiPackage && needToAskForPermissions()) {
// User needs to confirm installation;
@@ -1880,6 +1873,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private PackageManagerService.VerificationParams makeVerificationParamsLocked()
throws PackageManagerException {
+ if (mRelinquished) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Session relinquished");
+ }
+ if (mDestroyed) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Session destroyed");
+ }
+ if (!mSealed) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Session not sealed");
+ }
+
// TODO(b/136257624): Some logic in this if block probably belongs in
// makeInstallParams().
if (!params.isMultiPackage && !isApexInstallation()) {
@@ -2786,14 +2792,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void abandonStaged() {
+ final Runnable r;
synchronized (mLock) {
- if (mDestroyed) {
- // If a user abandons staged session in an unsafe state, then system will try to
- // abandon the destroyed staged session when it is safe on behalf of the user.
- assertCallerIsOwnerOrRootOrSystemLocked();
- } else {
- assertCallerIsOwnerOrRootLocked();
- }
+ assertCallerIsOwnerOrRootLocked();
if (isStagedAndInTerminalState()) {
// We keep the session in the database if it's in a finalized state. It will be
// removed by PackageInstallerService when the last update time is old enough.
@@ -2802,17 +2803,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return;
}
mDestroyed = true;
- if (mCommitted) {
- if (!mStagingManager.abortCommittedSessionLocked(this)) {
- // Do not clean up the staged session from system. It is not safe yet.
- mCallback.onStagedSessionChanged(this);
- return;
+ boolean isCommitted = mCommitted;
+ List<PackageInstallerSession> childSessions = getChildSessionsLocked();
+ r = () -> {
+ assertNotLocked("abandonStaged");
+ if (isCommitted) {
+ mStagingManager.abortCommittedSession(this);
}
+ cleanStageDir(childSessions);
+ destroyInternal();
+ dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
+ };
+ if (mInPreRebootVerification) {
+ // Pre-reboot verification is ongoing. It is not safe to clean up the session yet.
+ mPendingAbandonCallback = r;
+ mCallback.onStagedSessionChanged(this);
+ return;
}
- cleanStageDir(getChildSessionsLocked());
- destroyInternal();
}
- dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
+ r.run();
}
@Override
@@ -2829,6 +2838,50 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ /**
+ * Notified by the staging manager that pre-reboot verification is about to start. The return
+ * value should be checked to decide whether it is OK to start pre-reboot verification. In
+ * the case of a destroyed session, {@code false} is returned and there is no need to start
+ * pre-reboot verification.
+ */
+ boolean notifyStagedStartPreRebootVerification() {
+ synchronized (mLock) {
+ if (mInPreRebootVerification) {
+ throw new IllegalStateException("Pre-reboot verification has started");
+ }
+ if (mDestroyed) {
+ return false;
+ }
+ mInPreRebootVerification = true;
+ return true;
+ }
+ }
+
+ private void dispatchPendingAbandonCallback() {
+ final Runnable callback;
+ synchronized (mLock) {
+ callback = mPendingAbandonCallback;
+ mPendingAbandonCallback = null;
+ }
+ if (callback != null) {
+ callback.run();
+ }
+ }
+
+ /**
+ * Notified by the staging manager that pre-reboot verification has ended. Now it is safe to
+ * clean up the session if {@link #abandon()} has been called previously.
+ */
+ void notifyStagedEndPreRebootVerification() {
+ synchronized (mLock) {
+ if (!mInPreRebootVerification) {
+ throw new IllegalStateException("Pre-reboot verification not started");
+ }
+ mInPreRebootVerification = false;
+ }
+ dispatchPendingAbandonCallback();
+ }
+
@Override
public boolean isMultiPackage() {
return params.isMultiPackage;
@@ -3306,8 +3359,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Send broadcast to default launcher only if it's a new install
// TODO(b/144270665): Secure the usage of this broadcast.
final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
- if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
- && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
+ if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()) {
mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId);
}
@@ -3744,7 +3796,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
out.endTag(null, TAG_SESSION);
}
- // Sanity check to be performed when the session is restored from an external file. Only one
+ // Validity check to be performed when the session is restored from an external file. Only one
// of the session states should be true, or none of them.
private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied,
boolean isFailed) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c05bc455887d..9f78f0f08fd1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -254,6 +254,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
+import android.os.ParcelableException;
import android.os.PatternMatcher;
import android.os.PersistableBundle;
import android.os.Process;
@@ -394,6 +395,7 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -404,7 +406,10 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -926,6 +931,7 @@ public class PackageManagerService extends IPackageManager.Stub
private final Object mLock;
private final Installer mInstaller;
private final Object mInstallLock;
+ private final Handler mBackgroundHandler;
private final Executor mBackgroundExecutor;
// ----- producers -----
@@ -948,7 +954,7 @@ public class PackageManagerService extends IPackageManager.Stub
Injector(Context context, Object lock, Installer installer,
Object installLock, PackageAbiHelper abiHelper,
- Executor backgroundExecutor,
+ Handler backgroundHandler,
Producer<ComponentResolver> componentResolverProducer,
Producer<PermissionManagerServiceInternal> permissionManagerProducer,
Producer<UserManagerService> userManagerProducer,
@@ -970,7 +976,8 @@ public class PackageManagerService extends IPackageManager.Stub
mInstaller = installer;
mAbiHelper = abiHelper;
mInstallLock = installLock;
- mBackgroundExecutor = backgroundExecutor;
+ mBackgroundHandler = backgroundHandler;
+ mBackgroundExecutor = new HandlerExecutor(backgroundHandler);
mComponentResolverProducer = new Singleton<>(componentResolverProducer);
mPermissionManagerProducer = new Singleton<>(permissionManagerProducer);
mUserManagerProducer = new Singleton<>(userManagerProducer);
@@ -1085,6 +1092,10 @@ public class PackageManagerService extends IPackageManager.Stub
return mPlatformCompatProducer.get(this, mPackageManager);
}
+ public Handler getBackgroundHandler() {
+ return mBackgroundHandler;
+ }
+
public Executor getBackgroundExecutor() {
return mBackgroundExecutor;
}
@@ -2400,9 +2411,12 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUserId = UserHandle.getUserId(callingUid);
for (String packageName : packages) {
- PackageSetting setting = mSettings.mPackages.get(packageName);
- if (setting != null
- && !shouldFilterApplicationLocked(setting, callingUid, callingUserId)) {
+ final boolean filterApp;
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
+ filterApp = shouldFilterApplicationLocked(ps, callingUid, callingUserId);
+ }
+ if (!filterApp) {
notifyInstallObserver(packageName);
}
}
@@ -2443,6 +2457,68 @@ public class PackageManagerService extends IPackageManager.Stub
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
}
+ @Override
+ public void getChecksums(@NonNull String packageName, boolean includeSplits,
+ @PackageManager.FileChecksumKind int optional,
+ @PackageManager.FileChecksumKind int required, @Nullable List trustedInstallers,
+ @NonNull IntentSender statusReceiver, int userId) {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(statusReceiver);
+
+ final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0,
+ Binder.getCallingUid(), userId);
+ if (applicationInfo == null) {
+ throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
+ }
+
+ List<Pair<String, File>> filesToChecksum = new ArrayList<>();
+
+ // Adding base split.
+ filesToChecksum.add(Pair.create(null, new File(applicationInfo.sourceDir)));
+
+ // Adding other splits.
+ if (includeSplits && applicationInfo.splitNames != null) {
+ for (int i = 0, size = applicationInfo.splitNames.length; i < size; ++i) {
+ filesToChecksum.add(Pair.create(applicationInfo.splitNames[i],
+ new File(applicationInfo.splitSourceDirs[i])));
+ }
+ }
+
+ for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
+ final File file = filesToChecksum.get(i).second;
+ if (!file.exists()) {
+ throw new IllegalStateException("File not found: " + file.getPath());
+ }
+ }
+
+ final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates(
+ trustedInstallers) : null;
+
+ mInjector.getBackgroundExecutor().execute(() -> {
+ ApkChecksums.Injector injector = new ApkChecksums.Injector(
+ () -> mContext,
+ () -> mInjector.getBackgroundHandler(),
+ () -> mContext.getSystemService(IncrementalManager.class));
+ ApkChecksums.getChecksums(filesToChecksum, optional, required, trustedCerts,
+ statusReceiver, injector);
+ });
+ }
+
+ private static @NonNull Certificate[] decodeCertificates(@NonNull List certs) {
+ try {
+ final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ final Certificate[] result = new Certificate[certs.size()];
+ for (int i = 0, size = certs.size(); i < size; ++i) {
+ final InputStream is = new ByteArrayInputStream((byte[]) certs.get(i));
+ final X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
+ result[i] = cert;
+ }
+ return result;
+ } catch (CertificateException e) {
+ throw ExceptionUtils.propagate(e);
+ }
+ }
+
/**
* Gets the type of the external storage a package is installed on.
* @param packageVolume The storage volume of the package.
@@ -2597,7 +2673,7 @@ public class PackageManagerService extends IPackageManager.Stub
Injector injector = new Injector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
- new HandlerExecutor(backgroundHandler),
+ backgroundHandler,
(i, pm) ->
new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
(i, pm) ->
@@ -3268,6 +3344,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
// app completely. Otherwise, revoke their system privileges.
+ final int[] userIds = mUserManager.getUserIds();
for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
final AndroidPackage pkg = mPackages.get(packageName);
@@ -3310,7 +3387,7 @@ public class PackageManagerService extends IPackageManager.Stub
// partition], completely remove the package data.
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null && mPackages.get(packageName) == null) {
- removePackageDataLIF(ps, null, null, 0, false);
+ removePackageDataLIF(ps, userIds, null, 0, false);
}
logCriticalInfo(Log.WARN, msg);
@@ -3777,8 +3854,9 @@ public class PackageManagerService extends IPackageManager.Stub
// If we don't, installing the system package fails during scan
enableSystemPackageLPw(stubPkg);
}
- installPackageFromSystemLIF(stubPkg.getCodePath(), null /*allUserHandles*/,
- null /*origUserHandles*/, true /*writeSettings*/);
+ installPackageFromSystemLIF(stubPkg.getCodePath(),
+ mUserManager.getUserIds() /*allUserHandles*/, null /*origUserHandles*/,
+ true /*writeSettings*/);
} catch (PackageManagerException pme) {
// Serious WTF; we have to be able to install the stub
Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
@@ -8964,10 +9042,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (providerInfo == null) {
return null;
}
- if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
- return null;
- }
synchronized (mLock) {
+ if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
+ return null;
+ }
final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
final ComponentName component =
new ComponentName(providerInfo.packageName, providerInfo.name);
@@ -9054,9 +9132,11 @@ public class PackageManagerService extends IPackageManager.Stub
String targetPackage, int flags) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- final PackageSetting ps = mSettings.mPackages.get(targetPackage);
- if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
- return ParceledListSlice.emptyList();
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.getPackageLPr(targetPackage);
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
+ return ParceledListSlice.emptyList();
+ }
}
return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags,
callingUserId));
@@ -9504,8 +9584,8 @@ public class PackageManagerService extends IPackageManager.Stub
try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage(
parsedPackage.getPackageName(),
"scanPackageInternalLI")) {
- deletePackageLIF(parsedPackage.getPackageName(), null, true, null, 0, null,
- false, null);
+ deletePackageLIF(parsedPackage.getPackageName(), null, true,
+ mUserManager.getUserIds(), 0, null, false, null);
}
pkgSetting = null;
} else if (newPkgVersionGreater) {
@@ -11587,7 +11667,7 @@ public class PackageManagerService extends IPackageManager.Stub
configurePackageComponents(parsedPackage);
}
- final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride, pkgSetting);
+ final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride);
final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
@@ -13793,7 +13873,7 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId);
final long callingId = Binder.clearCallingIdentity();
try {
- final String activeLauncherPackageName = getActiveLauncherPackageName(userId);
+ final String activeLauncherPackageName = mPermissionManager.getDefaultHome(userId);
final String dialerPackageName = mPermissionManager.getDefaultDialer(userId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
@@ -13869,18 +13949,6 @@ public class PackageManagerService extends IPackageManager.Stub
return canSuspend;
}
- private String getActiveLauncherPackageName(int userId) {
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = resolveIntent(
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.MATCH_DEFAULT_ONLY,
- userId);
-
- return resolveInfo == null ? null : resolveInfo.activityInfo.packageName;
- }
-
@Override
public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
mContext.enforceCallingOrSelfPermission(
@@ -14572,7 +14640,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageSetting ps;
int appId = -1;
long ceDataInode = -1;
- synchronized (mSettings) {
+ synchronized (mLock) {
ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
appId = ps.appId;
@@ -16322,9 +16390,11 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private static class CommitRequest {
final Map<String, ReconciledPackage> reconciledPackages;
+ @NonNull
final int[] mAllUsers;
- private CommitRequest(Map<String, ReconciledPackage> reconciledPackages, int[] allUsers) {
+ private CommitRequest(Map<String, ReconciledPackage> reconciledPackages,
+ @NonNull int[] allUsers) {
this.reconciledPackages = reconciledPackages;
this.mAllUsers = allUsers;
}
@@ -17620,7 +17690,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
&& pkgSetting.getPkgState().isUpdatedSystemApp();
- final String abiOverride = deriveAbiOverride(args.abiOverride, pkgSetting);
+ final String abiOverride = deriveAbiOverride(args.abiOverride);
AndroidPackage oldPackage = mPackages.get(pkgName);
boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
@@ -18837,7 +18907,7 @@ public class PackageManagerService extends IPackageManager.Stub
* make sure this flag is set for partially installed apps. If not its meaningless to
* delete a partially installed application.
*/
- private void removePackageDataLIF(final PackageSetting deletedPs, int[] allUserHandles,
+ private void removePackageDataLIF(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = deletedPs.name;
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
@@ -18925,7 +18995,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// make sure to preserve per-user disabled state if this removal was just
// a downgrade of a system app to the factory package
- if (allUserHandles != null && outInfo != null && outInfo.origUsers != null) {
+ if (outInfo != null && outInfo.origUsers != null) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across downgrade");
}
@@ -18978,11 +19048,10 @@ public class PackageManagerService extends IPackageManager.Stub
* Tries to delete system package.
*/
private void deleteSystemPackageLIF(DeletePackageAction action, PackageSetting deletedPs,
- int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo,
+ @NonNull int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo,
boolean writeSettings)
throws SystemDeleteException {
- final boolean applyUserRestrictions =
- (allUserHandles != null) && outInfo != null && (outInfo.origUsers != null);
+ final boolean applyUserRestrictions = outInfo != null && (outInfo.origUsers != null);
final AndroidPackage deletedPkg = deletedPs.pkg;
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
@@ -19066,7 +19135,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Installs a package that's already on the system partition.
*/
private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString,
- @Nullable int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
+ @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
throws PackageManagerException {
final File codePath = new File(codePathString);
@ParseFlags int parseFlags =
@@ -19108,8 +19177,7 @@ public class PackageManagerService extends IPackageManager.Stub
// and granting install permissions.
mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
- final boolean applyUserRestrictions
- = (allUserHandles != null) && (origUserHandles != null);
+ final boolean applyUserRestrictions = origUserHandles != null;
if (applyUserRestrictions) {
boolean installedStateChanged = false;
if (DEBUG_REMOVE) {
@@ -19146,7 +19214,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private void deleteInstalledPackageLIF(PackageSetting ps,
- boolean deleteCodeAndResources, int flags, int[] allUserHandles,
+ boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles,
PackageRemovedInfo outInfo, boolean writeSettings) {
synchronized (mLock) {
if (outInfo != null) {
@@ -19266,7 +19334,7 @@ public class PackageManagerService extends IPackageManager.Stub
* This method handles package deletion in general
*/
private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
- boolean deleteCodeAndResources, int[] allUserHandles, int flags,
+ boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags,
PackageRemovedInfo outInfo, boolean writeSettings,
ParsedPackage replacingPackage) {
final DeletePackageAction action;
@@ -19303,7 +19371,7 @@ public class PackageManagerService extends IPackageManager.Stub
/** Deletes a package. Only throws when install of a disabled package fails. */
private void executeDeletePackageLIF(DeletePackageAction action,
String packageName, boolean deleteCodeAndResources,
- int[] allUserHandles, boolean writeSettings,
+ @NonNull int[] allUserHandles, boolean writeSettings,
ParsedPackage replacingPackage) throws SystemDeleteException {
final PackageSetting ps = action.deletingPs;
final PackageRemovedInfo outInfo = action.outInfo;
@@ -19453,6 +19521,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (outInfo != null) {
+ if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+ outInfo.dataRemoved = true;
+ }
outInfo.removedPackage = ps.name;
outInfo.installerPackageName = ps.installSource.installerPackageName;
outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
@@ -19488,9 +19559,11 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */, "clear application data");
- final PackageSetting ps = mSettings.getPackageLPr(packageName);
- final boolean filterApp =
- (ps != null && shouldFilterApplicationLocked(ps, callingUid, userId));
+ final boolean filterApp;
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.getPackageLPr(packageName);
+ filterApp = shouldFilterApplicationLocked(ps, callingUid, userId);
+ }
if (!filterApp && mProtectedPackages.isPackageDataProtected(userId, packageName)) {
throw new SecurityException("Cannot clear data for a protected package: "
+ packageName);
@@ -19770,11 +19843,13 @@ public class PackageManagerService extends IPackageManager.Stub
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLPr(callingUid)
- < Build.VERSION_CODES.FROYO) {
- Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
- + callingUid);
- return;
+ synchronized (mLock) {
+ if (getUidTargetSdkVersionLockedLPr(callingUid)
+ < Build.VERSION_CODES.FROYO) {
+ Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+ + callingUid);
+ return;
+ }
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -19954,8 +20029,9 @@ public class PackageManagerService extends IPackageManager.Stub
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
private void clearPackagePreferredActivities(String packageName, int userId) {
final SparseBooleanArray changedUsers = new SparseBooleanArray();
-
- clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
+ synchronized (mLock) {
+ clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
+ }
if (changedUsers.size() > 0) {
updateDefaultHomeNotLocked(changedUsers);
postPreferredActivityChangedBroadcast(userId);
@@ -20077,7 +20153,9 @@ public class PackageManagerService extends IPackageManager.Stub
// writer
try {
final SparseBooleanArray changedUsers = new SparseBooleanArray();
- clearPackagePreferredActivitiesLPw(null, changedUsers, userId);
+ synchronized (mLock) {
+ clearPackagePreferredActivitiesLPw(null, changedUsers, userId);
+ }
if (changedUsers.size() > 0) {
postPreferredActivityChangedBroadcast(userId);
}
@@ -20545,6 +20623,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (cn != null) {
return cn;
}
+ // TODO: This should not happen since there should always be a default package set for
+ // ROLE_HOME in RoleManager. Continue with a warning log for now.
+ Slog.w(TAG, "Default package for ROLE_HOME is not set in RoleManager");
// Find the launcher with the highest priority and return that component if there are no
// other home activity with the same priority.
@@ -20593,6 +20674,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null) {
return null;
}
+
int resolveInfosSize = resolveInfos.size();
for (int i = 0; i < resolveInfosSize; i++) {
ResolveInfo resolveInfo = resolveInfos.get(i);
@@ -20652,6 +20734,11 @@ public class PackageManagerService extends IPackageManager.Stub
// PermissionController manages default home directly.
return false;
}
+
+ if (packageName == null) {
+ // Keep the default home package in RoleManager.
+ return false;
+ }
mPermissionManager.setDefaultHome(packageName, userId, (successful) -> {
if (successful) {
postPreferredActivityChangedBroadcast(userId);
@@ -21087,15 +21174,19 @@ public class PackageManagerService extends IPackageManager.Stub
// Limit who can change which apps
if (!UserHandle.isSameApp(callingUid, pkgSetting.appId)) {
// Don't allow apps that don't have permission to modify other apps
- if (!allowedByPermission
- || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
+ final boolean filterApp;
+ synchronized (mLock) {
+ filterApp = (!allowedByPermission
+ || shouldFilterApplicationLocked(pkgSetting, callingUid, userId));
+ }
+ if (filterApp) {
throw new SecurityException(
"Attempt to change component state; "
- + "pid=" + Binder.getCallingPid()
- + ", uid=" + callingUid
- + (className == null
+ + "pid=" + Binder.getCallingPid()
+ + ", uid=" + callingUid
+ + (className == null
? ", package=" + packageName
- : ", component=" + packageName + "/" + className));
+ : ", component=" + packageName + "/" + className));
}
// Don't allow changing protected packages.
if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
@@ -21558,8 +21649,6 @@ public class PackageManagerService extends IPackageManager.Stub
.getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL);
co.onChange(true);
- mAppsFilter.onSystemReady();
-
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(
@@ -21708,6 +21797,9 @@ public class PackageManagerService extends IPackageManager.Stub
mInstallerService.restoreAndApplyStagedSessionIfNeeded();
mExistingPackages = null;
+
+ // We'll do this last as it builds its cache while holding mLock via callback.
+ mAppsFilter.onSystemReady();
}
public void waitForAppDataPrepared() {
@@ -22694,6 +22786,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
+ final int[] userIds = mUserManager.getUserIds();
final ArrayList<AndroidPackage> unloaded = new ArrayList<>();
synchronized (mInstallLock) {
synchronized (mLock) {
@@ -22707,7 +22800,7 @@ public class PackageManagerService extends IPackageManager.Stub
try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags,
"unloadPrivatePackagesInner")) {
- if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo,
+ if (deletePackageLIF(ps.name, null, false, userIds, deleteFlags, outInfo,
false, null)) {
unloaded.add(pkg);
} else {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 491b4fc515ce..5553cd0e2fb8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -421,18 +421,13 @@ public class PackageManagerServiceUtils {
/**
* Derive the value of the {@code cpuAbiOverride} based on the provided
- * value and an optional stored value from the package settings.
+ * value.
*/
- public static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
- String cpuAbiOverride = null;
+ public static String deriveAbiOverride(String abiOverride) {
if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
- cpuAbiOverride = null;
- } else if (abiOverride != null) {
- cpuAbiOverride = abiOverride;
- } else if (settings != null) {
- cpuAbiOverride = settings.cpuAbiOverrideString;
+ return null;
}
- return cpuAbiOverride;
+ return abiOverride;
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
index 3614cc047bf8..2bbca79741bd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
@@ -67,7 +67,6 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService {
}
}
- // Sanity check.
if (sShellCommands.size() > TOO_MANY_PENDING_SHELL_COMMANDS) {
Slog.e(TAG, "Too many pending shell commands: " + sShellCommands.size());
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 0c4eaec32ba5..462b21535371 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -60,7 +60,6 @@ import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.apk.ApkSignatureVerifier;
@@ -1028,22 +1027,12 @@ public class StagingManager {
/**
* <p>Abort committed staged session
- *
- * <p>This method must be called while holding {@link PackageInstallerSession#mLock}.
- *
- * <p>The method returns {@code false} to indicate it is not safe to clean up the session from
- * system yet. When it is safe, the method returns {@code true}.
- *
- * <p> When it is safe to clean up, {@link StagingManager} will call
- * {@link PackageInstallerSession#abandon()} on the session again.
- *
- * @return {@code true} if it is safe to cleanup the session resources, otherwise {@code false}.
*/
- boolean abortCommittedSessionLocked(@NonNull PackageInstallerSession session) {
+ void abortCommittedSession(@NonNull PackageInstallerSession session) {
int sessionId = session.sessionId;
- if (session.isStagedSessionApplied()) {
- Slog.w(TAG, "Cannot abort applied session : " + sessionId);
- return false;
+ if (session.isStagedAndInTerminalState()) {
+ Slog.w(TAG, "Cannot abort session in final state: " + sessionId);
+ return;
}
if (!session.isDestroyed()) {
throw new IllegalStateException("Committed session must be destroyed before aborting it"
@@ -1051,15 +1040,7 @@ public class StagingManager {
}
if (getStagedSession(sessionId) == null) {
Slog.w(TAG, "Session " + sessionId + " has been abandoned already");
- return false;
- }
-
- // If pre-reboot verification is running, then return false. StagingManager will call
- // abandon again when pre-reboot verification ends.
- if (mPreRebootVerificationHandler.isVerificationRunning(sessionId)) {
- Slog.w(TAG, "Session " + sessionId + " aborted before pre-reboot "
- + "verification completed.");
- return false;
+ return;
}
// A session could be marked ready once its pre-reboot verification ends
@@ -1075,7 +1056,6 @@ public class StagingManager {
// Session was successfully aborted from apexd (if required) and pre-reboot verification
// is also complete. It is now safe to clean up the session from system.
abortSession(session);
- return true;
}
/**
@@ -1264,8 +1244,8 @@ public class StagingManager {
// TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
// verification logic is extracted out of StagingManager into PMS, we can remove
// this.
- void notifyVerificationComplete(int sessionId) {
- mPreRebootVerificationHandler.onPreRebootVerificationComplete(sessionId);
+ void notifyVerificationComplete(PackageInstallerSession session) {
+ mPreRebootVerificationHandler.onPreRebootVerificationComplete(session);
}
// TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
@@ -1279,8 +1259,6 @@ public class StagingManager {
// Hold session ids before handler gets ready to do the verification.
private IntArray mPendingSessionIds;
private boolean mIsReady;
- @GuardedBy("mVerificationRunning")
- private final SparseBooleanArray mVerificationRunning = new SparseBooleanArray();
PreRebootVerificationHandler(Looper looper) {
super(looper);
@@ -1316,7 +1294,7 @@ public class StagingManager {
}
if (session.isDestroyed() || session.isStagedSessionFailed()) {
// No point in running verification on a destroyed/failed session
- onPreRebootVerificationComplete(sessionId);
+ onPreRebootVerificationComplete(session);
return;
}
switch (msg.what) {
@@ -1357,15 +1335,10 @@ public class StagingManager {
}
PackageInstallerSession session = getStagedSession(sessionId);
- synchronized (mVerificationRunning) {
- // Do not start verification on a session that has been abandoned
- if (session == null || session.isDestroyed()) {
- return;
- }
+ if (session != null && session.notifyStagedStartPreRebootVerification()) {
Slog.d(TAG, "Starting preRebootVerification for session " + sessionId);
- mVerificationRunning.put(sessionId, true);
+ obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
}
- obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
}
private void onPreRebootVerificationFailure(PackageInstallerSession session,
@@ -1376,28 +1349,14 @@ public class StagingManager {
// failed on next step and staging directory for session will be deleted.
}
session.setStagedSessionFailed(errorCode, errorMessage);
- onPreRebootVerificationComplete(session.sessionId);
+ onPreRebootVerificationComplete(session);
}
// Things to do when pre-reboot verification completes for a particular sessionId
- private void onPreRebootVerificationComplete(int sessionId) {
- // Remove it from mVerificationRunning so that verification is considered complete
- synchronized (mVerificationRunning) {
- Slog.d(TAG, "Stopping preRebootVerification for session " + sessionId);
- mVerificationRunning.delete(sessionId);
- }
- // Check if the session was destroyed while pre-reboot verification was running. If so,
- // abandon it again.
- PackageInstallerSession session = getStagedSession(sessionId);
- if (session != null && session.isDestroyed()) {
- session.abandon();
- }
- }
-
- private boolean isVerificationRunning(int sessionId) {
- synchronized (mVerificationRunning) {
- return mVerificationRunning.get(sessionId);
- }
+ private void onPreRebootVerificationComplete(PackageInstallerSession session) {
+ int sessionId = session.sessionId;
+ Slog.d(TAG, "Stopping preRebootVerification for session " + sessionId);
+ session.notifyStagedEndPreRebootVerification();
}
private void notifyPreRebootVerification_Start_Complete(int sessionId) {
@@ -1516,7 +1475,7 @@ public class StagingManager {
// or activate its apex, there won't be any files to work with as they will be cleaned
// up by the system as part of abandonment. If session is abandoned before this point,
// then the session is already destroyed and cannot be marked ready anymore.
- onPreRebootVerificationComplete(session.sessionId);
+ onPreRebootVerificationComplete(session);
// Proactively mark session as ready before calling apexd. Although this call order
// looks counter-intuitive, this is the easiest way to ensure that session won't end up
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index dbe96e63d978..485868237895 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -33,6 +33,9 @@
"name": "CtsContentTestCases",
"options": [
{
+ "include-filter": "android.content.pm.cts.ChecksumsTest"
+ },
+ {
"include-filter": "android.content.pm.cts.PackageManagerShellCommandTest"
},
{
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d137fd05f793..6ecaab6692a2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -407,6 +407,10 @@ public class UserManagerService extends IUserManager.Stub {
@GuardedBy("mUsersLock")
private int[] mUserIds;
+
+ @GuardedBy("mUsersLock")
+ private int[] mUserIdsIncludingPreCreated;
+
@GuardedBy("mPackagesLock")
private int mNextSerialNumber;
private int mUserVersion = 0;
@@ -760,6 +764,8 @@ public class UserManagerService extends IUserManager.Stub {
return null;
}
+ // TODO(b/157921703): replace by getAliveUsers() or remove (so callers
+ // explicitly call the 3-booleans version)
public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */
true);
@@ -2494,16 +2500,35 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
- * Returns an array of user ids. This array is cached here for quick access, so do not modify or
- * cache it elsewhere.
+ * Returns an array of user ids.
+ *
+ * <p>This array is cached here for quick access, so do not modify or cache it elsewhere.
+ *
* @return the array of user ids.
*/
- public int[] getUserIds() {
+ public @NonNull int[] getUserIds() {
synchronized (mUsersLock) {
return mUserIds;
}
}
+ /**
+ * Returns an array of user ids, including pre-created users.
+ *
+ * <p>This method should only used for the specific cases that need to handle pre-created users;
+ * most callers should call {@link #getUserIds()} instead.
+ *
+ * <p>This array is cached here for quick access, so do not modify or
+ * cache it elsewhere.
+ *
+ * @return the array of user ids.
+ */
+ public @NonNull int[] getUserIdsIncludingPreCreated() {
+ synchronized (mUsersLock) {
+ return mUserIdsIncludingPreCreated;
+ }
+ }
+
@GuardedBy({"mRestrictionsLock", "mPackagesLock"})
private void readUserListLP() {
if (!mUserListFile.exists()) {
@@ -4359,23 +4384,43 @@ public class UserManagerService extends IUserManager.Stub {
*/
private void updateUserIds() {
int num = 0;
+ int numIncludingPreCreated = 0;
synchronized (mUsersLock) {
final int userSize = mUsers.size();
for (int i = 0; i < userSize; i++) {
- UserInfo userInfo = mUsers.valueAt(i).info;
- if (!userInfo.partial && !userInfo.preCreated) {
- num++;
+ final UserInfo userInfo = mUsers.valueAt(i).info;
+ if (!userInfo.partial) {
+ numIncludingPreCreated++;
+ if (!userInfo.preCreated) {
+ num++;
+ }
}
}
+ if (DBG) {
+ Slog.d(LOG_TAG, "updateUserIds(): numberUsers= " + num
+ + " includingPreCreated=" + numIncludingPreCreated);
+ }
final int[] newUsers = new int[num];
+ final int[] newUsersIncludingPreCreated = new int[numIncludingPreCreated];
+
int n = 0;
+ int nIncludingPreCreated = 0;
for (int i = 0; i < userSize; i++) {
- UserInfo userInfo = mUsers.valueAt(i).info;
- if (!userInfo.partial && !userInfo.preCreated) {
- newUsers[n++] = mUsers.keyAt(i);
+ final UserInfo userInfo = mUsers.valueAt(i).info;
+ if (!userInfo.partial) {
+ final int userId = mUsers.keyAt(i);
+ newUsersIncludingPreCreated[nIncludingPreCreated++] = userId;
+ if (!userInfo.preCreated) {
+ newUsers[n++] = userId;
+ }
}
}
mUserIds = newUsers;
+ mUserIdsIncludingPreCreated = newUsersIncludingPreCreated;
+ if (DBG) {
+ Slog.d(LOG_TAG, "updateUserIds(): userIds= " + Arrays.toString(mUserIds)
+ + " includingPreCreated=" + Arrays.toString(mUserIdsIncludingPreCreated));
+ }
}
}
@@ -4839,6 +4884,8 @@ public class UserManagerService extends IUserManager.Stub {
synchronized (mUsersLock) {
pw.print(" Cached user IDs: ");
pw.println(Arrays.toString(mUserIds));
+ pw.print(" Cached user IDs (including pre-created): ");
+ pw.println(Arrays.toString(mUserIdsIncludingPreCreated));
}
} // synchronized (mPackagesLock)
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 75a88e2e04b6..f7721a4d6f22 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -414,17 +414,14 @@ public final class DefaultPermissionGrantPolicy {
if (pkg == null
|| !doesPackageSupportRuntimePermissions(pkg)
|| ArrayUtils.isEmpty(pkg.requestedPermissions)
- || !pkg.applicationInfo.isPrivilegedApp()) {
+ || !pm.isGranted(Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ pkg, UserHandle.of(userId))) {
continue;
}
- for (String permission : pkg.requestedPermissions) {
- if (Manifest.permission.READ_PRIVILEGED_PHONE_STATE.equals(permission)) {
- grantRuntimePermissions(pm, pkg,
- Collections.singleton(Manifest.permission.READ_PHONE_STATE),
- true, // systemFixed
- userId);
- }
- }
+ grantRuntimePermissions(pm, pkg,
+ Collections.singleton(Manifest.permission.READ_PHONE_STATE),
+ true, // systemFixed
+ userId);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index f5dd918a18f3..ffdcc227b7f1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -83,7 +83,6 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -121,7 +120,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.TimingsTraceLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -3146,17 +3144,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @return user ids for created users and pre-created users
*/
private int[] getAllUserIds() {
- final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
- t.traceBegin("getAllUserIds");
- List<UserInfo> users = UserManagerService.getInstance().getUsers(
- /*excludePartial=*/ true, /*excludeDying=*/ true, /*excludePreCreated=*/ false);
- int size = users.size();
- final int[] userIds = new int[size];
- for (int i = 0; i < size; i++) {
- userIds[i] = users.get(i).id;
- }
- t.traceEnd();
- return userIds;
+ return UserManagerService.getInstance().getUserIdsIncludingPreCreated();
}
/**
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index ae2b040d0a89..e1cd9e334f4c 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -31,6 +31,7 @@ import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -242,8 +243,9 @@ public final class PermissionPolicyService extends SystemService {
public void onReceive(Context context, Intent intent) {
boolean hasSetupRun = true;
try {
- hasSetupRun = Settings.Secure.getInt(getContext().getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE) != 0;
+ final ContentResolver cr = getContext().getContentResolver();
+ hasSetupRun = Settings.Secure.getIntForUser(cr,
+ Settings.Secure.USER_SETUP_COMPLETE, cr.getUserId()) != 0;
} catch (Settings.SettingNotFoundException e) {
// Ignore error, assume setup has run
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 137c587b1d79..d01a30fbd818 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -69,6 +69,7 @@ import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -148,6 +149,7 @@ import android.os.UEventObserver;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
+import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
@@ -1378,12 +1380,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private long getScreenshotChordLongPressDelay() {
+ long delayMs = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_SYSTEMUI, SCREENSHOT_KEYCHORD_DELAY,
+ ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout());
if (mKeyguardDelegate.isShowing()) {
// Double the time it takes to take a screenshot from the keyguard
- return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
- ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout());
+ return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER * delayMs);
}
- return ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout();
+ return delayMs;
}
private long getRingerToggleChordDelay() {
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 2b793c894eb0..f204aa2cc1ca 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -52,6 +52,9 @@ abstract public class VerityUtils {
/** The maximum size of signature file. This is just to avoid potential abuse. */
private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192;
+ /** SHA256 hash size. */
+ private static final int HASH_SIZE_BYTES = 32;
+
private static final boolean DEBUG = false;
/** Returns true if the given file looks like containing an fs-verity signature. */
@@ -90,8 +93,23 @@ abstract public class VerityUtils {
return (retval == 1);
}
+ /** Returns hash of a root node for the fs-verity enabled file. */
+ public static byte[] getFsverityRootHash(@NonNull String filePath) {
+ byte[] result = new byte[HASH_SIZE_BYTES];
+ int retval = measureFsverityNative(filePath, result);
+ if (retval < 0) {
+ if (retval != -OsConstants.ENODATA) {
+ Slog.e(TAG, "Failed to measure fs-verity, errno " + -retval + ": " + filePath);
+ }
+ return null;
+ }
+ return result;
+ }
+
private static native int enableFsverityNative(@NonNull String filePath,
@NonNull byte[] pkcs7Signature);
+ private static native int measureFsverityNative(@NonNull String filePath,
+ @NonNull byte[] digest);
private static native int statxForFsverityNative(@NonNull String filePath);
/**
diff --git a/services/core/java/com/android/server/slice/SliceFullAccessList.java b/services/core/java/com/android/server/slice/SliceFullAccessList.java
index 6f5afa207d31..d25ddf877951 100644
--- a/services/core/java/com/android/server/slice/SliceFullAccessList.java
+++ b/services/core/java/com/android/server/slice/SliceFullAccessList.java
@@ -101,7 +101,7 @@ public class SliceFullAccessList {
public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
// upgrade xml
int xmlVersion = XmlUtils.readIntAttribute(parser, ATT_VERSION, 0);
- final List<UserInfo> activeUsers = UserManager.get(mContext).getUsers(true);
+ final List<UserInfo> activeUsers = UserManager.get(mContext).getAliveUsers();
for (UserInfo userInfo : activeUsers) {
upgradeXml(xmlVersion, userInfo.getUserHandle().getIdentifier());
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
index 8e5ecee8262b..ebe9733e5d55 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
@@ -35,7 +35,8 @@ import java.util.TimerTask;
* HAL whenever they expire.
*/
public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 {
- private static final long TIMEOUT_MS = 1000;
+ // TODO(b/166328980): Reduce this to 1000 as soon as HAL is fixed.
+ private static final long TIMEOUT_MS = 10000;
private static final String TAG = "SoundTriggerHw2Watchdog";
private final @NonNull
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index c382e1152e4b..5a587cc9764c 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -36,7 +36,6 @@ import android.media.soundtrigger_middleware.Status;
import android.os.IBinder;
import android.os.IHwBinder;
import android.os.RemoteException;
-import android.os.ServiceSpecificException;
import android.util.Log;
import java.util.ArrayList;
@@ -293,7 +292,11 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
} catch (Exception e) {
// We must do this outside the lock, to avoid possible deadlocks with the remote
// process that provides the audio sessions, which may also be calling into us.
- mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ try {
+ mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ } catch (Exception ee) {
+ Log.e(TAG, "Failed to release session.", ee);
+ }
throw e;
}
}
@@ -321,7 +324,11 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
} catch (Exception e) {
// We must do this outside the lock, to avoid possible deadlocks with the remote
// process that provides the audio sessions, which may also be calling into us.
- mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ try {
+ mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ } catch (Exception ee) {
+ Log.e(TAG, "Failed to release session.", ee);
+ }
throw e;
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index aee3d8d3499b..b68c54fc6365 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -25,6 +25,7 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
+import android.os.UserHandle;
import java.util.Objects;
@@ -56,6 +57,12 @@ public final class ConfigurationInternal {
return mUserId;
}
+ /** Returns the handle of the user this configuration is associated with. */
+ @NonNull
+ public UserHandle getUserHandle() {
+ return UserHandle.of(mUserId);
+ }
+
/** Returns true if the user allowed to modify time zone configuration. */
public boolean isUserConfigAllowed() {
return mUserConfigAllowed;
@@ -198,13 +205,13 @@ public final class ConfigurationInternal {
@Override
public String toString() {
- return "TimeZoneDetectorConfiguration{"
+ return "ConfigurationInternal{"
+ "mUserId=" + mUserId
- + "mUserConfigAllowed=" + mUserConfigAllowed
- + "mAutoDetectionSupported=" + mAutoDetectionSupported
- + "mAutoDetectionEnabled=" + mAutoDetectionEnabled
- + "mLocationEnabled=" + mLocationEnabled
- + "mGeoDetectionEnabled=" + mGeoDetectionEnabled
+ + ", mUserConfigAllowed=" + mUserConfigAllowed
+ + ", mAutoDetectionSupported=" + mAutoDetectionSupported
+ + ", mAutoDetectionEnabled=" + mAutoDetectionEnabled
+ + ", mLocationEnabled=" + mLocationEnabled
+ + ", mGeoDetectionEnabled=" + mGeoDetectionEnabled
+ '}';
}
diff --git a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
new file mode 100644
index 000000000000..91e172c9d153
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.timezonedetector."
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
index 3230ef192b4b..a8d5c0282025 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -23,7 +23,7 @@ import java.io.PrintWriter;
import java.util.function.Consumer;
import java.util.function.Supplier;
-/** Implemented the shell command interface for {@link TimeZoneDetectorService}. */
+/** Implements the shell command interface for {@link TimeZoneDetectorService}. */
class TimeZoneDetectorShellCommand extends ShellCommand {
private final TimeZoneDetectorService mInterface;
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 0c85387be695..89b108c24630 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -126,6 +126,8 @@ public class TrustManagerService extends SystemService {
private static final String TRUST_TIMEOUT_ALARM_TAG = "TrustManagerService.trustTimeoutForUser";
private static final long TRUST_TIMEOUT_IN_MILLIS = 4 * 60 * 60 * 1000;
+ private static final String PRIV_NAMESPACE = "http://schemas.android.com/apk/prv/res/android";
+
private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
private final Receiver mReceiver = new Receiver();
@@ -379,7 +381,7 @@ public class TrustManagerService extends SystemService {
}
private void updateTrustAll() {
- List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
+ List<UserInfo> userInfos = mUserManager.getAliveUsers();
for (UserInfo userInfo : userInfos) {
updateTrust(userInfo.id, 0);
}
@@ -485,7 +487,7 @@ public class TrustManagerService extends SystemService {
List<UserInfo> userInfos;
if (userIdOrAll == UserHandle.USER_ALL) {
- userInfos = mUserManager.getUsers(true /* excludeDying */);
+ userInfos = mUserManager.getAliveUsers();
} else {
userInfos = new ArrayList<>();
userInfos.add(mUserManager.getUserInfo(userIdOrAll));
@@ -644,7 +646,7 @@ public class TrustManagerService extends SystemService {
}
List<UserInfo> userInfos;
if (userId == UserHandle.USER_ALL) {
- userInfos = mUserManager.getUsers(true /* excludeDying */);
+ userInfos = mUserManager.getAliveUsers();
} else {
userInfos = new ArrayList<>();
userInfos.add(mUserManager.getUserInfo(userId));
@@ -811,8 +813,8 @@ public class TrustManagerService extends SystemService {
TypedArray sa = res
.obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent);
cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity);
- canUnlockProfile = sa.getBoolean(
- com.android.internal.R.styleable.TrustAgent_unlockProfile, false);
+ canUnlockProfile = attrs.getAttributeBooleanValue(
+ PRIV_NAMESPACE, "unlockProfile", false);
sa.recycle();
} catch (PackageManager.NameNotFoundException e) {
caughtException = e;
@@ -1171,7 +1173,7 @@ public class TrustManagerService extends SystemService {
fout.println("disabled because the third-party apps can't run yet.");
return;
}
- final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
+ final List<UserInfo> userInfos = mUserManager.getAliveUsers();
mHandler.runWithScissors(new Runnable() {
@Override
public void run() {
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 0b0bb7059f3b..53d51463295f 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -115,7 +115,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
private static final String TAG = "UriGrantsManagerService";
// Maximum number of persisted Uri grants a package is allowed
private static final int MAX_PERSISTED_URI_GRANTS = 512;
- private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true;
+ private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false;
private final Object mLock = new Object();
private final H mH;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 56261c4fce97..6df46ed2532b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -133,6 +133,7 @@ import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING;
import static com.android.server.wm.ActivityRecordProto.NAME;
import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS;
import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS;
+import static com.android.server.wm.ActivityRecordProto.PIP_AUTO_ENTER_ALLOWED;
import static com.android.server.wm.ActivityRecordProto.PROC_ID;
import static com.android.server.wm.ActivityRecordProto.REPORTED_DRAWN;
import static com.android.server.wm.ActivityRecordProto.REPORTED_VISIBLE;
@@ -401,7 +402,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final ActivityTaskManagerService mAtmService;
final ActivityInfo info; // activity info provided by developer in AndroidManifest
- // Non-null only for application tokens.
// TODO: rename to mActivityToken
final ActivityRecord.Token appToken;
// Which user is this running for?
@@ -1587,7 +1587,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
hasBeenLaunched = false;
mStackSupervisor = supervisor;
- info.taskAffinity = getTaskAffinityWithUid(info.taskAffinity, info.applicationInfo.uid);
+ info.taskAffinity = computeTaskAffinity(info.taskAffinity, info.applicationInfo.uid,
+ launchMode);
taskAffinity = info.taskAffinity;
final String uid = Integer.toString(info.applicationInfo.uid);
if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
@@ -1648,17 +1649,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * Generate the task affinity with uid. For b/35954083, Limit task affinity to uid to avoid
- * issues associated with sharing affinity across uids.
+ * Generate the task affinity with uid and activity launch mode. For b/35954083, Limit task
+ * affinity to uid to avoid issues associated with sharing affinity across uids.
*
* @param affinity The affinity of the activity.
* @param uid The user-ID that has been assigned to this application.
- * @return The task affinity with uid.
+ * @param launchMode The activity launch mode
+ * @return The task affinity
*/
- static String getTaskAffinityWithUid(String affinity, int uid) {
+ static String computeTaskAffinity(String affinity, int uid, int launchMode) {
final String uidStr = Integer.toString(uid);
if (affinity != null && !affinity.startsWith(uidStr)) {
- affinity = uidStr + ":" + affinity;
+ affinity = uidStr + (launchMode == LAUNCH_SINGLE_INSTANCE ? "-si:" : ":") + affinity;
}
return affinity;
}
@@ -2123,11 +2125,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return task != null ? task.getRootTaskId() : INVALID_TASK_ID;
}
- DisplayContent getDisplay() {
- final Task stack = getRootTask();
- return stack != null ? stack.getDisplay() : null;
- }
-
@Override
@Nullable
TaskDisplayArea getDisplayArea() {
@@ -2387,7 +2384,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- return (canReceiveKeys() || isAlwaysFocusable()) && getDisplay() != null;
+ // Check isAttached() because the method may be called when removing this activity from
+ // display, and WindowContainer#compareTo will throw exception if it doesn't have a parent
+ // when updating focused window from DisplayContent#findFocusedWindow.
+ return (canReceiveKeys() || isAlwaysFocusable()) && isAttached();
}
/**
@@ -2664,7 +2664,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
private void prepareActivityHideTransitionAnimation(int transit) {
- final DisplayContent dc = getDisplay().mDisplayContent;
+ final DisplayContent dc = mDisplayContent;
dc.prepareAppTransition(transit, false);
setVisibility(false);
dc.executeAppTransition();
@@ -2709,7 +2709,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
if (ensureVisibility) {
- getDisplay().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ mDisplayContent.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, true /* notifyClients */);
}
}
@@ -4653,7 +4653,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Check if the activity is on a sleeping display, and if it can turn it ON.
- if (getDisplay().isSleeping()) {
+ if (mDisplayContent.isSleeping()) {
final boolean canTurnScreenOn = !mSetToSleep || canTurnScreenOn()
|| canShowWhenLocked() || containsDismissKeyguardWindow();
if (!canTurnScreenOn) {
@@ -4742,6 +4742,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
&& !isState(STARTED, STOPPING, STOPPED, PAUSED);
+ if (deferHidingClient && pictureInPictureArgs.isAutoEnterAllowed()) {
+ // Go ahead and just put the activity in pip if it supports auto-pip.
+ mAtmService.enterPictureInPictureMode(this, pictureInPictureArgs);
+ return;
+ }
setDeferHidingClient(deferHidingClient);
setVisibility(false);
@@ -4932,12 +4937,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
r.setSavedState(null /* savedState */);
- final DisplayContent display = r.getDisplay();
- if (display != null) {
- display.handleActivitySizeCompatModeIfNeeded(r);
- }
-
- r.getDisplayContent().mUnknownAppVisibilityController.notifyAppResumedFinished(r);
+ r.mDisplayContent.handleActivitySizeCompatModeIfNeeded(r);
+ r.mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(r);
}
/**
@@ -5480,10 +5481,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void updateReportedVisibilityLocked() {
- if (appToken == null) {
- return;
- }
-
if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
final int count = mChildren.size();
@@ -6330,8 +6327,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
private void setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded) {
- final IBinder binder =
- (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null;
+ final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
setOrientation(requestedOrientation, binder, this);
// Push the new configuration to the requested app in case where it's not pushed, e.g. when
@@ -6840,7 +6836,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
onMergedOverrideConfigurationChanged();
}
- final DisplayContent display = getDisplay();
+ final DisplayContent display = mDisplayContent;
if (display == null) {
return;
}
@@ -7265,7 +7261,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(
- getDisplay().mDisplayContent.isNextTransitionForward());
+ mDisplayContent.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
@@ -7590,11 +7586,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* otherwise.
*/
boolean isFocusedActivityOnDisplay() {
- final DisplayContent display = getDisplay();
- if (display == null) {
- return false;
- }
- return display.forAllTaskDisplayAreas(taskDisplayArea ->
+ return mDisplayContent.forAllTaskDisplayAreas(taskDisplayArea ->
taskDisplayArea.getFocusedActivity() == this);
}
@@ -7692,6 +7684,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (hasProcess()) {
proto.write(PROC_ID, app.getPid());
}
+ proto.write(PIP_AUTO_ENTER_ALLOWED, pictureInPictureArgs.isAutoEnterAllowed());
}
@Override
@@ -7713,9 +7706,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void writeNameToProto(ProtoOutputStream proto, long fieldId) {
- if (appToken != null) {
- proto.write(fieldId, appToken.getName());
- }
+ proto.write(fieldId, appToken.getName());
}
@Override
@@ -7802,42 +7793,40 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/** Gets the horizontal centered container bounds for size compatibility mode. */
void getContainerBounds(Rect outAppBounds, Rect outBounds, int rotation, int orientation,
boolean orientationRequested, boolean canChangeOrientation) {
+ getFrameByOrientation(outBounds, orientation);
if (mIsFloating) {
- getFrameByOrientation(outBounds, orientation);
outAppBounds.set(outBounds);
return;
}
- if (canChangeOrientation) {
- getBoundsByRotation(outBounds, rotation);
- if (orientationRequested) {
- getFrameByOrientation(outAppBounds, orientation);
- } else {
- outAppBounds.set(outBounds);
- }
- } else {
- if (orientationRequested) {
- getFrameByOrientation(outBounds, orientation);
- if ((outBounds.width() > outBounds.height()) != (mWidth > mHeight)) {
- // The orientation is mismatched but the display cannot rotate. The bounds
- // will fit to the short side of display.
- if (orientation == ORIENTATION_LANDSCAPE) {
- outBounds.bottom = (int) ((float) mWidth * mWidth / mHeight);
- outBounds.right = mWidth;
- } else {
- outBounds.bottom = mHeight;
- outBounds.right = (int) ((float) mHeight * mHeight / mWidth);
- }
- outBounds.offset(
- getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
- }
+ getBoundsByRotation(outAppBounds, rotation);
+ final int dW = outAppBounds.width();
+ final int dH = outAppBounds.height();
+ final boolean isOrientationMismatched =
+ ((outBounds.width() > outBounds.height()) != (dW > dH));
+
+ if (isOrientationMismatched && !canChangeOrientation && orientationRequested) {
+ // The orientation is mismatched but the display cannot rotate. The bounds will fit
+ // to the short side of container.
+ if (orientation == ORIENTATION_LANDSCAPE) {
+ outBounds.bottom = (int) ((float) dW * dW / dH);
+ outBounds.right = dW;
} else {
- outBounds.set(0, 0, mWidth, mHeight);
+ outBounds.bottom = dH;
+ outBounds.right = (int) ((float) dH * dH / dW);
}
- outAppBounds.set(outBounds);
- }
-
- if (rotation != ROTATION_UNDEFINED) {
+ outBounds.offset(getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
+ }
+ outAppBounds.set(outBounds);
+
+ if (isOrientationMismatched) {
+ // One side of container is smaller than the requested size, then it will be scaled
+ // and the final position will be calculated according to the parent container and
+ // scale, so the original size shouldn't be shrunk by insets.
+ final Rect insets = mNonDecorInsets[rotation];
+ outBounds.offset(insets.left, insets.top);
+ outAppBounds.offset(insets.left, insets.top);
+ } else if (rotation != ROTATION_UNDEFINED) {
// Ensure the app bounds won't overlap with insets.
Task.intersectWithInsetsIfFits(outAppBounds, outBounds, mNonDecorInsets[rotation]);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 34f7f79d7716..9df192b76f9a 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -837,7 +837,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
- final DisplayContent dc = r.getDisplay().mDisplayContent;
+ final DisplayContent dc = r.mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index be7a6aed7489..19755f29043e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1710,8 +1710,9 @@ class ActivityStarter {
mRootWindowContainer.startPowerModeLaunchIfNeeded(
false /* forceSend */, mStartActivity);
- mTargetStack.startActivityLocked(mStartActivity, topStack.getTopNonFinishingActivity(),
- newTask, mKeepCurTransition, mOptions);
+ mTargetStack.startActivityLocked(mStartActivity,
+ topStack != null ? topStack.getTopNonFinishingActivity() : null, newTask,
+ mKeepCurTransition, mOptions);
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
@@ -1730,7 +1731,7 @@ class ActivityStarter {
0 /* configChanges */, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
- mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
+ mTargetStack.mDisplayContent.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
@@ -2480,7 +2481,7 @@ class ActivityStarter {
// to the front if the caller is not itself in the front.
final boolean differentTopTask;
if (mTargetStack.getDisplayArea() == mPreferredTaskDisplayArea) {
- final Task focusStack = mTargetStack.getDisplay().getFocusedStack();
+ final Task focusStack = mTargetStack.mDisplayContent.getFocusedStack();
final ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
final Task topTask = curTop != null ? curTop.getTask() : null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 6a8cbfbb5840..080a438df357 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -125,6 +125,7 @@ import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.Manifest;
import android.annotation.IntDef;
@@ -252,7 +253,6 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.SystemServiceManager;
import com.android.server.UiThread;
import com.android.server.Watchdog;
@@ -2024,7 +2024,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (self.isState(
Task.ActivityState.RESUMED, Task.ActivityState.PAUSING)) {
- self.getDisplay().mDisplayContent.mAppTransition.overridePendingAppTransition(
+ self.mDisplayContent.mAppTransition.overridePendingAppTransition(
packageName, enterAnim, exitAnim, null, null);
}
@@ -2408,7 +2408,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
} else {
stack.setWindowingMode(windowingMode);
- stack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+ stack.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
true /* notifyClients */);
}
return true;
@@ -4058,6 +4058,60 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
&& r.getRootTask().isInTask(r) != null;
}
+ /**
+ * Puts the given activity in picture in picture mode if possible.
+ *
+ * @return true if the activity is now in picture-in-picture mode, or false if it could not
+ * enter picture-in-picture mode.
+ */
+ boolean enterPictureInPictureMode(ActivityRecord r, final PictureInPictureParams params) {
+ // If the activity is already in picture in picture mode, then just return early
+ if (isInPictureInPictureMode(r)) {
+ return true;
+ }
+
+ // Activity supports picture-in-picture, now check that we can enter PiP at this
+ // point, if it is
+ if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode",
+ false /* beforeStopping */)) {
+ return false;
+ }
+
+ final Runnable enterPipRunnable = () -> {
+ synchronized (mGlobalLock) {
+ if (r.getParent() == null) {
+ Slog.e(TAG, "Skip enterPictureInPictureMode, destroyed " + r);
+ return;
+ }
+ // Only update the saved args from the args that are set
+ r.setPictureInPictureParams(params);
+ final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
+ final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
+ mRootWindowContainer.moveActivityToPinnedStack(
+ r, "enterPictureInPictureMode");
+ final Task stack = r.getRootTask();
+ stack.setPictureInPictureAspectRatio(aspectRatio);
+ stack.setPictureInPictureActions(actions);
+ }
+ };
+
+ if (isKeyguardLocked()) {
+ // If the keyguard is showing or occluded, then try and dismiss it before
+ // entering picture-in-picture (this will prompt the user to authenticate if the
+ // device is currently locked).
+ dismissKeyguard(r.appToken, new KeyguardDismissCallback() {
+ @Override
+ public void onDismissSucceeded() {
+ mH.post(enterPipRunnable);
+ }
+ }, null /* message */);
+ } else {
+ // Enter picture in picture immediately otherwise
+ enterPipRunnable.run();
+ }
+ return true;
+ }
+
@Override
public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureParams params) {
final long origId = Binder.clearCallingIdentity();
@@ -4065,52 +4119,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
final ActivityRecord r = ensureValidPictureInPictureActivityParamsLocked(
"enterPictureInPictureMode", token, params);
-
- // If the activity is already in picture in picture mode, then just return early
- if (isInPictureInPictureMode(r)) {
- return true;
- }
-
- // Activity supports picture-in-picture, now check that we can enter PiP at this
- // point, if it is
- if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode",
- false /* beforeStopping */)) {
- return false;
- }
-
- final Runnable enterPipRunnable = () -> {
- synchronized (mGlobalLock) {
- if (r.getParent() == null) {
- Slog.e(TAG, "Skip enterPictureInPictureMode, destroyed " + r);
- return;
- }
- // Only update the saved args from the args that are set
- r.setPictureInPictureParams(params);
- final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
- final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
- mRootWindowContainer.moveActivityToPinnedStack(
- r, "enterPictureInPictureMode");
- final Task stack = r.getRootTask();
- stack.setPictureInPictureAspectRatio(aspectRatio);
- stack.setPictureInPictureActions(actions);
- }
- };
-
- if (isKeyguardLocked()) {
- // If the keyguard is showing or occluded, then try and dismiss it before
- // entering picture-in-picture (this will prompt the user to authenticate if the
- // device is currently locked).
- dismissKeyguard(token, new KeyguardDismissCallback() {
- @Override
- public void onDismissSucceeded() {
- mH.post(enterPipRunnable);
- }
- }, null /* message */);
- } else {
- // Enter picture in picture immediately otherwise
- enterPipRunnable.run();
- }
- return true;
+ return enterPictureInPictureMode(r, params);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4175,7 +4184,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (params.hasSetAspectRatio()
&& !mWindowManager.isValidPictureInPictureAspectRatio(
- r.getDisplay(), params.getAspectRatio())) {
+ r.mDisplayContent, params.getAspectRatio())) {
final float minAspectRatio = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
final float maxAspectRatio = mContext.getResources().getFloat(
@@ -4619,7 +4628,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final long origId = Binder.clearCallingIdentity();
try {
- display.mDisplayContent.registerRemoteAnimations(definition);
+ display.registerRemoteAnimations(definition);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -4856,6 +4865,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"Requested PIP on an activity that doesn't support it");
}
+ if (activity.pictureInPictureArgs.isAutoEnterAllowed()) {
+ enterPictureInPictureMode(activity, activity.pictureInPictureArgs);
+ return;
+ }
+
try {
final ClientTransaction transaction = ClientTransaction.obtain(
activity.app.getThread(),
@@ -5465,8 +5479,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
updateResumedAppTrace(r);
mLastResumedActivity = r;
- r.getDisplay().setFocusedApp(r, true);
-
+ final boolean changed = r.mDisplayContent.setFocusedApp(r);
+ if (changed) {
+ mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+ true /*updateInputWindows*/);
+ }
if (prevTask == null || task != prevTask) {
if (prevTask != null) {
mTaskChangeNotificationController.notifyTaskFocusChanged(prevTask.mTaskId, false);
@@ -6202,12 +6219,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// We might change the visibilities here, so prepare an empty app transition which
// might be overridden later if we actually change visibilities.
- final DisplayContent displayContent =
- mRootWindowContainer.getDisplayContent(displayId);
- if (displayContent == null) {
+ final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
+ if (dc == null) {
return;
}
- final DisplayContent dc = displayContent.mDisplayContent;
final boolean wasTransitionSet =
dc.mAppTransition.getAppTransition() != TRANSIT_NONE;
if (!wasTransitionSet) {
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 9a397fe07f4e..01c007e381b1 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -18,6 +18,9 @@ package com.android.server.wm;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
+
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -25,6 +28,8 @@ import android.view.SurfaceControl;
import android.window.IDisplayAreaOrganizer;
import android.window.IDisplayAreaOrganizerController;
+import com.android.internal.protolog.common.ProtoLog;
+
import java.util.HashMap;
public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub {
@@ -67,9 +72,12 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
@Override
public void registerOrganizer(IDisplayAreaOrganizer organizer, int feature) {
enforceStackPermission("registerOrganizer()");
+ final long uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d",
+ organizer.asBinder(), uid);
if (mOrganizersByFeatureIds.get(feature) != null) {
throw new IllegalStateException(
"Replacing existing organizer currently unsupported");
@@ -96,9 +104,12 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
@Override
public void unregisterOrganizer(IDisplayAreaOrganizer organizer) {
enforceStackPermission("unregisterTaskOrganizer()");
+ final long uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister display organizer=%s uid=%d",
+ organizer.asBinder(), uid);
mOrganizersByFeatureIds.entrySet().removeIf(
entry -> entry.getValue().asBinder() == organizer.asBinder());
@@ -113,6 +124,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
}
void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea appeared name=%s", da.getName());
try {
SurfaceControl outSurfaceControl = new SurfaceControl(da.getSurfaceControl(),
"DisplayAreaOrganizerController.onDisplayAreaAppeared");
@@ -123,6 +135,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
}
void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea vanished name=%s", da.getName());
try {
organizer.onDisplayAreaVanished(da.getDisplayAreaInfo());
} catch (RemoteException e) {
@@ -131,6 +144,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
}
void onDisplayAreaInfoChanged(IDisplayAreaOrganizer organizer, DisplayArea da) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea info changed name=%s", da.getName());
try {
organizer.onDisplayAreaInfoChanged(da.getDisplayAreaInfo());
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2f7cc69b01a7..8ccbd1166a44 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -115,13 +115,11 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIG
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.H.REPORT_FOCUS_CHANGE;
import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE;
import static com.android.server.wm.WindowManagerService.H.UPDATE_MULTI_WINDOW_STACKS;
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
@@ -649,8 +647,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
private final ToBooleanFunction<WindowState> mFindFocusedWindow = w -> {
final ActivityRecord focusedApp = mFocusedApp;
- ProtoLog.v(WM_DEBUG_FOCUS, "Looking for focus: %s, flags=%d, canReceive=%b",
- w, w.mAttrs.flags, w.canReceiveKeys());
+ ProtoLog.v(WM_DEBUG_FOCUS, "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
+ w, w.mAttrs.flags, w.canReceiveKeys(),
+ w.canReceiveKeysReason(false /* fromUserTouch */));
if (!w.canReceiveKeys()) {
return false;
@@ -3072,7 +3071,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
WindowState findFocusedWindowIfNeeded(int topFocusedDisplayId) {
return (mWmService.mPerDisplayFocusEnabled || topFocusedDisplayId == INVALID_DISPLAY)
- ? findFocusedWindow() : null;
+ ? findFocusedWindow() : null;
}
WindowState findFocusedWindow() {
@@ -3081,7 +3080,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */);
if (mTmpWindow == null) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows.");
+ ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows, display=%d",
+ getDisplayId());
return null;
}
return mTmpWindow;
@@ -3116,18 +3116,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
&& mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) {
assignWindowLayers(false /* setLayoutNeeded */);
}
- }
- if (imWindowChanged) {
- mWmService.mWindowsChanged = true;
- setLayoutNeeded();
- newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
- }
- if (mCurrentFocus != newFocus) {
- mWmService.mH.obtainMessage(REPORT_FOCUS_CHANGE, this).sendToTarget();
+ if (imWindowChanged) {
+ mWmService.mWindowsChanged = true;
+ setLayoutNeeded();
+ newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
+ }
}
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
+ ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
@@ -3185,9 +3182,25 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
}
+
+ // Notify the accessibility manager for the change so it has the windows before the newly
+ // focused one starts firing events.
+ // TODO(b/151179149) investigate what info accessibility service needs before input can
+ // dispatch focus to clients.
+ if (mWmService.mAccessibilityController != null) {
+ mWmService.mH.sendMessage(PooledLambda.obtainMessage(
+ this::updateAccessibilityOnWindowFocusChanged,
+ mWmService.mAccessibilityController));
+ }
+
+ mLastFocus = mCurrentFocus;
return true;
}
+ void updateAccessibilityOnWindowFocusChanged(AccessibilityController accessibilityController) {
+ accessibilityController.onWindowFocusChangedNotLocked(getDisplayId());
+ }
+
private static void onWindowFocusChanged(WindowState oldFocus, WindowState newFocus) {
final Task focusedTask = newFocus != null ? newFocus.getTask() : null;
final Task unfocusedTask = oldFocus != null ? oldFocus.getTask() : null;
@@ -3219,6 +3232,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (mFocusedApp == newFocus) {
return false;
}
+ ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "setFocusedApp %s displayId=%d Callers=%s",
+ newFocus, getDisplayId(), Debug.getCallers(4));
mFocusedApp = newFocus;
getInputMonitor().setFocusedAppLw(newFocus);
updateTouchExcludeRegion();
@@ -3473,7 +3488,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return false;
}
return mWmService.mDisplayWindowSettings.shouldShowImeLocked(this)
- || mWmService.mForceDesktopModeOnExternalDisplays;
+ || forceDesktopMode();
+ }
+
+ boolean forceDesktopMode() {
+ return mWmService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay && !isPrivate();
}
private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) {
@@ -4527,7 +4546,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
boolean supportsSystemDecorations() {
return (mWmService.mDisplayWindowSettings.shouldShowSystemDecorsLocked(this)
|| (mDisplay.getFlags() & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0
- || mWmService.mForceDesktopModeOnExternalDisplays)
+ || forceDesktopMode())
// VR virtual display will be used to run and render 2D app within a VR experience.
&& mDisplayId != mWmService.mVr2dDisplayId
// Do not show system decorations on untrusted virtual display.
@@ -4708,7 +4727,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Traverse all windows top down to assemble the gesture exclusion rects.
// For each window, we only take the rects that fall within its touchable region.
forAllWindows(w -> {
- if (w.cantReceiveTouchInput() || !w.isVisible()
+ if (!w.canReceiveTouchInput() || !w.isVisible()
|| (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
|| unhandled.isEmpty()) {
return;
@@ -5225,30 +5244,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
&& (mAtmService.mRunningVoice == null);
}
- void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
- final ActivityRecord newFocus;
- final IBinder token = r.appToken;
- if (token == null) {
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Clearing focused app, displayId=%d",
- mDisplayId);
- newFocus = null;
- } else {
- newFocus = mWmService.mRoot.getActivityRecord(token);
- if (newFocus == null) {
- Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
- + ", displayId=" + mDisplayId);
- }
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
- "Set focused app to: %s moveFocusNow=%b displayId=%d", newFocus,
- moveFocusNow, mDisplayId);
- }
-
- final boolean changed = setFocusedApp(newFocus);
- if (moveFocusNow && changed) {
- mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
- true /*updateInputWindows*/);
- }
- }
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1c147c259f07..779f6b2d30cc 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -29,6 +29,7 @@ import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
+import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -38,11 +39,6 @@ import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
@@ -57,20 +53,18 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCRE
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
@@ -78,27 +72,21 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
-import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
@@ -171,7 +159,6 @@ import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.Surface;
import android.view.View;
-import android.view.ViewRootImpl;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type;
@@ -913,10 +900,6 @@ public class DisplayPolicy {
(int) attrs.hideTimeoutMilliseconds,
AccessibilityManager.FLAG_CONTENT_TEXT);
attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
- // Toast can show with below conditions when the screen is locked.
- if (canToastShowWhenLocked(callingPid)) {
- attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
- }
// Toasts can't be clickable
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
break;
@@ -947,16 +930,6 @@ public class DisplayPolicy {
}
/**
- * @return {@code true} if the calling activity initiate toast and is visible with
- * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
- */
- boolean canToastShowWhenLocked(int callingPid) {
- return mDisplayContent.forAllWindows(w -> {
- return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
- }, true /* traverseTopToBottom */);
- }
-
- /**
* Check if a window can be added to the system.
*
* Currently enforces that two window types are singletons per display:
@@ -1440,8 +1413,7 @@ public class DisplayPolicy {
DisplayCutout.ParcelableWrapper outDisplayCutout) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
final int pfl = attrs.privateFlags;
- final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
- final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
+ final int sysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
final boolean layoutInScreenAndInsetDecor = layoutInScreen
@@ -1461,7 +1433,7 @@ public class DisplayPolicy {
: mDisplayContent.mDisplayFrames;
if (layoutInScreenAndInsetDecor && !screenDecor) {
- if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+ if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
|| (attrs.getFitInsetsTypes() & Type.navigationBars()) == 0) {
outFrame.set(displayFrames.mUnrestricted);
} else {
@@ -1492,7 +1464,6 @@ public class DisplayPolicy {
InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
.getDisplayCutout());
- return mForceShowSystemBars;
} else {
if (layoutInScreen) {
outFrame.set(displayFrames.mUnrestricted);
@@ -1506,22 +1477,8 @@ public class DisplayPolicy {
outContentInsets.setEmpty();
outStableInsets.setEmpty();
outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
- return mForceShowSystemBars;
}
- }
-
- // TODO(b/118118435): remove after migration
- private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
- int impliedFlags = 0;
- final boolean forceWindowDrawsBarBackgrounds =
- (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
- && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
- if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
- || forceWindowDrawsBarBackgrounds) {
- impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- }
- return impliedFlags;
+ return mForceShowSystemBars;
}
private final Runnable mClearHideNavigationFlag = new Runnable() {
@@ -1557,7 +1514,7 @@ public class DisplayPolicy {
if (mInputConsumer == null) {
return;
}
- showNavigationBar();
+ showSystemBars();
// Any user activity always causes us to show the
// navigation controls, if they had been hidden.
// We also clear the low profile and only content
@@ -1592,13 +1549,13 @@ public class DisplayPolicy {
}
}
- private void showNavigationBar() {
+ private void showSystemBars() {
final InsetsSourceProvider provider = mDisplayContent.getInsetsStateController()
.peekSourceProvider(ITYPE_NAVIGATION_BAR);
final InsetsControlTarget target =
provider != null ? provider.getControlTarget() : null;
if (target != null) {
- target.showInsets(Type.navigationBars(), false /* fromIme */);
+ target.showInsets(Type.systemBars(), false /* fromIme */);
}
}
}
@@ -1668,11 +1625,8 @@ public class DisplayPolicy {
final int behavior = mLastBehavior;
final InsetsSourceProvider provider =
mDisplayContent.getInsetsStateController().peekSourceProvider(ITYPE_NAVIGATION_BAR);
- boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
- ? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- : provider != null
- ? provider.isClientVisible()
- : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
+ boolean navVisible = provider != null ? provider.isClientVisible()
+ : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
boolean navTranslucent = (sysui
& (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
@@ -2057,80 +2011,6 @@ public class DisplayPolicy {
return mNavigationBarController.checkHiddenLw();
}
- private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
- boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf,
- DisplayFrames displayFrames) {
- if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
- // Here's a special case: if the child window is not the 'dock window'
- // or input method target, and the window it is attached to is below
- // the dock window, then the frames we computed for the window it is
- // attached to can not be used because the dock is effectively part
- // of the underlying window and the attached window is floating on top
- // of the whole thing. So, we ignore the attached window and explicitly
- // compute the frames that would be appropriate without the dock.
- vf.set(displayFrames.mDock);
- cf.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- } else {
-
- // In case we forced the window to draw behind the navigation bar, restrict df to
- // DF.Restricted to simulate old compat behavior.
- Rect parentDisplayFrame = attached.getDisplayFrame();
- final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
- if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
- && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (attachedAttrs.systemUiVisibility
- & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
- parentDisplayFrame = new Rect(parentDisplayFrame);
- parentDisplayFrame.intersect(displayFrames.mRestricted);
- }
-
- // The effective display frame of the attached window depends on whether it is taking
- // care of insetting its content. If not, we need to use the parent's content frame so
- // that the entire window is positioned within that content. Otherwise we can use the
- // parent display frame and let the attached window take care of positioning its content
- // appropriately.
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- // Set the content frame of the attached window to the parent's decor frame
- // (same as content frame when IME isn't present) if specifically requested by
- // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
- // Otherwise, use the overscan frame.
- cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
- ? attached.getContentFrame() : parentDisplayFrame);
- } else {
- // If the window is resizing, then we want to base the content frame on our attached
- // content frame to resize...however, things can be tricky if the attached window is
- // NOT in resize mode, in which case its content frame will be larger.
- // Ungh. So to deal with that, make sure the content frame we end up using is not
- // covering the IM dock.
- cf.set(attached.getContentFrame());
- if (attached.isVoiceInteraction()) {
- cf.intersectUnchecked(displayFrames.mVoiceContent);
- } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
- cf.intersectUnchecked(displayFrames.mContent);
- }
- }
- df.set(insetDecors ? parentDisplayFrame : cf);
- vf.set(attached.getVisibleFrame());
- }
- // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
- // positioned relative to its parent or the entire screen.
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
- }
-
- private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
- if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
- return;
- }
- // If app is requesting a stable layout, don't let the content insets go below the stable
- // values.
- if ((fl & FLAG_FULLSCREEN) != 0) {
- r.intersectUnchecked(displayFrames.mStableFullscreen);
- } else {
- r.intersectUnchecked(displayFrames.mStable);
- }
- }
-
private boolean canReceiveInput(WindowState win) {
boolean notFocusable =
(win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
@@ -2165,8 +2045,6 @@ public class DisplayPolicy {
final int fl = PolicyControl.getWindowFlags(win, attrs);
final int pfl = attrs.privateFlags;
final int sim = attrs.softInputMode;
- final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
- final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
displayFrames = win.getDisplayFrames(displayFrames);
final WindowFrames windowFrames = win.getWindowFrames();
@@ -2191,351 +2069,60 @@ public class DisplayPolicy {
sf.set(displayFrames.mStable);
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
- final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
- final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
- getRotatedWindowBounds(displayFrames, win, sTmpRect);
- final Rect dfu = sTmpRect;
- Insets insets = Insets.of(0, 0, 0, 0);
- for (int i = types.size() - 1; i >= 0; i--) {
- final InsetsSource source = mDisplayContent.getInsetsPolicy()
- .getInsetsForDispatch(win).peekSource(types.valueAt(i));
- if (source == null) {
- continue;
- }
- insets = Insets.max(insets, source.calculateInsets(
- dfu, attrs.isFitInsetsIgnoringVisibility()));
- }
- final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
- final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
- final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
- final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
- df.set(dfu.left + left, dfu.top + top, dfu.right - right, dfu.bottom - bottom);
- if (attached == null) {
- pf.set(df);
- vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
- ? displayFrames.mCurrent : displayFrames.mDock);
- } else {
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
- vf.set(attached.getVisibleFrame());
- }
- cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
- ? displayFrames.mDock : displayFrames.mContent);
- dcf.set(displayFrames.mSystem);
- } else if (type == TYPE_INPUT_METHOD) {
- vf.set(displayFrames.mDock);
- cf.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- pf.set(displayFrames.mDock);
- // IM dock windows layout below the nav bar...
- pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
- // ...with content insets above the nav bar
- cf.bottom = vf.bottom = displayFrames.mStable.bottom;
- if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
- // The status bar forces the navigation bar while it's visible. Make sure the IME
- // avoids the navigation bar in that case.
- if (mNavigationBarPosition == NAV_BAR_RIGHT) {
- pf.right = df.right = cf.right = vf.right =
- displayFrames.mStable.right;
- } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
- pf.left = df.left = cf.left = vf.left = displayFrames.mStable.left;
- }
- }
-
- // In case the navigation bar is on the bottom, we use the frame height instead of the
- // regular height for the insets we send to the IME as we need some space to show
- // additional buttons in SystemUI when the IME is up.
- if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
- final int rotation = displayFrames.mRotation;
- final int uimode = mService.mPolicy.getUiMode();
- final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
- - getNavigationBarHeight(rotation, uimode);
- if (navHeightOffset > 0) {
- cf.bottom -= navHeightOffset;
- sf.bottom -= navHeightOffset;
- vf.bottom -= navHeightOffset;
- dcf.bottom -= navHeightOffset;
- }
- }
-
- // IM dock windows always go to the bottom of the screen.
- attrs.gravity = Gravity.BOTTOM;
- } else if (type == TYPE_VOICE_INTERACTION) {
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
+ final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
+ final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
+ final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
+ getRotatedWindowBounds(displayFrames, win, sTmpRect);
+ final Rect dfu = sTmpRect;
+ Insets insets = Insets.of(0, 0, 0, 0);
+ for (int i = types.size() - 1; i >= 0; i--) {
+ final InsetsSource source = mDisplayContent.getInsetsPolicy()
+ .getInsetsForDispatch(win).peekSource(types.valueAt(i));
+ if (source == null) {
+ continue;
}
- } else if (type == TYPE_WALLPAPER) {
- layoutWallpaper(displayFrames, pf, df, cf);
- } else if (win == mStatusBar || type == TYPE_NOTIFICATION_SHADE) {
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- cf.set(displayFrames.mStable);
- vf.set(displayFrames.mStable);
-
- if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
- // cf.bottom should not be below the stable bottom, or the content might be obscured
- // by the navigation bar.
- if (cf.bottom > displayFrames.mContent.bottom) {
- cf.bottom = displayFrames.mContent.bottom;
- }
- } else {
- if (cf.bottom > displayFrames.mDock.bottom) {
- cf.bottom = displayFrames.mDock.bottom;
- }
- if (vf.bottom > displayFrames.mContent.bottom) {
- vf.bottom = displayFrames.mContent.bottom;
+ insets = Insets.max(insets, source.calculateInsets(
+ dfu, attrs.isFitInsetsIgnoringVisibility()));
+ }
+ final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
+ final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
+ final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
+ final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
+ df.set(dfu.left + left, dfu.top + top, dfu.right - right, dfu.bottom - bottom);
+ if (attached == null) {
+ pf.set(df);
+ if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
+ final InsetsSource source = mDisplayContent.getInsetsPolicy()
+ .getInsetsForDispatch(win).peekSource(ITYPE_IME);
+ if (source != null) {
+ pf.inset(source.calculateInsets(pf, false /* ignoreVisibility */));
}
}
+ vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
+ ? displayFrames.mCurrent : displayFrames.mDock);
} else {
- dcf.set(displayFrames.mSystem);
- final boolean isAppWindow =
- type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
- final boolean topAtRest =
- win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
- if (isAppWindow && !topAtRest) {
- if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
- && (fl & FLAG_FULLSCREEN) == 0
- && (fl & FLAG_TRANSLUCENT_STATUS) == 0
- && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
- // Ensure policy decor includes status bar
- dcf.top = displayFrames.mStable.top;
- }
- if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
- && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
- // Ensure policy decor includes navigation bar
- dcf.bottom = displayFrames.mStable.bottom;
- dcf.right = displayFrames.mStable.right;
- }
- }
-
- if (layoutInScreen && layoutInsetDecor) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): IN_SCREEN, INSET_DECOR");
- // This is the case for a normal activity window: we want it to cover all of the
- // screen space, and it can take care of moving its contents to account for screen
- // decorations that intrude into that space.
- if (attached != null) {
- // If this window is attached to another, our display
- // frame is the same as the one we are attached to.
- setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf,
- displayFrames);
- } else {
- if (type == TYPE_STATUS_BAR_ADDITIONAL || type == TYPE_STATUS_BAR_SUB_PANEL) {
- // Status bar panels are the only windows who can go on top of the status
- // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
- // have the same privileges as the status bar itself.
- //
- // However, they should still dodge the navigation bar if it exists.
-
- pf.left = df.left = hasNavBar
- ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
- pf.top = df.top = displayFrames.mUnrestricted.top;
- pf.right = df.right = hasNavBar
- ? displayFrames.mRestricted.right
- : displayFrames.mUnrestricted.right;
- pf.bottom = df.bottom = hasNavBar
- ? displayFrames.mRestricted.bottom
- : displayFrames.mUnrestricted.bottom;
-
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
- } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
- || type == TYPE_VOLUME_OVERLAY
- || type == TYPE_KEYGUARD_DIALOG)) {
- // Asking for layout as if the nav bar is hidden, lets the application
- // extend into the unrestricted overscan screen area. We only do this for
- // application windows and certain system windows to ensure no window that
- // can be above the nav bar can do this.
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else {
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- }
-
- if ((fl & FLAG_FULLSCREEN) == 0) {
- if (win.isVoiceInteraction()) {
- cf.set(displayFrames.mVoiceContent);
- } else {
- // IME Insets are handled on the client for ADJUST_RESIZE in the new
- // insets world
- if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
- || adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- }
- } else {
- // Full screen windows are always given a layout that is as if the status
- // bar and other transient decors are gone. This is to avoid bad states when
- // moving from a window that is not hiding the status bar to one that is.
- cf.set(displayFrames.mRestricted);
- }
- applyStableConstraints(sysUiFl, fl, cf, displayFrames);
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- }
- } else if (layoutInScreen || (sysUiFl
- & (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): IN_SCREEN");
- // A window that has requested to fill the entire screen just
- // gets everything, period.
- if (type == TYPE_STATUS_BAR_ADDITIONAL || type == TYPE_STATUS_BAR_SUB_PANEL) {
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (hasNavBar) {
- pf.left = df.left = cf.left = displayFrames.mDock.left;
- pf.right = df.right = cf.right = displayFrames.mRestricted.right;
- pf.bottom = df.bottom = cf.bottom =
- displayFrames.mRestricted.bottom;
- }
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
- } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
- // The navigation bar has Real Ultimate Power.
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
- } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
- && ((fl & FLAG_FULLSCREEN) != 0)) {
- // Fullscreen secure system overlays get what they ask for. Screenshot region
- // selection overlay should also expand to full screen.
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if (type == TYPE_BOOT_PROGRESS) {
- // Boot progress screen always covers entire display.
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && (type == TYPE_NOTIFICATION_SHADE
- || type == TYPE_TOAST
- || type == TYPE_DOCK_DIVIDER
- || type == TYPE_VOICE_INTERACTION_STARTING
- || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
- // Asking for layout as if the nav bar is hidden, lets the
- // application extend into the unrestricted screen area. We
- // only do this for application windows (or toasts) to ensure no window that
- // can be above the nav bar can do this.
- // XXX This assumes that an app asking for this will also
- // ask for layout in only content. We can't currently figure out
- // what the screen would be if only laying out to hide the nav bar.
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
-
- // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
- // world
- if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
- || adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- } else {
- cf.set(displayFrames.mRestricted);
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- }
-
- applyStableConstraints(sysUiFl, fl, cf, displayFrames);
-
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- } else if (attached != null) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): attached to " + attached);
- // A child window should be placed inside of the same visible
- // frame that its parent had.
- setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf,
- displayFrames);
- } else {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): normal window");
- // Otherwise, a normal window must be placed inside the content
- // of all screen decorations.
- if (type == TYPE_STATUS_BAR_ADDITIONAL) {
- // Status bar panels can go on
- // top of the status bar. They are protected by the STATUS_BAR_SERVICE
- // permission, so they have the same privileges as the status bar itself.
- cf.set(displayFrames.mRestricted);
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
- // These dialogs are stable to interim decor changes.
- cf.set(displayFrames.mStable);
- df.set(displayFrames.mStable);
- pf.set(displayFrames.mStable);
- } else {
- pf.set(displayFrames.mContent);
- if (win.isVoiceInteraction()) {
- cf.set(displayFrames.mVoiceContent);
- df.set(displayFrames.mVoiceContent);
- } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- df.set(displayFrames.mContent);
- }
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- }
- }
+ pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
+ vf.set(attached.getVisibleFrame());
}
+ cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
+ ? displayFrames.mDock : displayFrames.mContent);
+ dcf.set(displayFrames.mSystem);
final int cutoutMode = attrs.layoutInDisplayCutoutMode;
- final boolean attachedInParent = attached != null && !layoutInScreen;
- final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
- || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
- || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
- ITYPE_STATUS_BAR));
- final boolean requestedHideNavigation =
- (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
- || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
- ITYPE_NAVIGATION_BAR));
-
- // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
- // cropped / shifted to the displayFrame in WindowState.
- final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
- && type != TYPE_BASE_APPLICATION;
// Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
// the cutout safe zone.
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
+ final boolean attachedInParent = attached != null && !layoutInScreen;
+ final InsetsState requestedInsetsState = win.getRequestedInsetsState();
+ final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
+ || !requestedInsetsState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR);
+ final boolean requestedHideNavigation =
+ !requestedInsetsState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR);
+
+ // TYPE_BASE_APPLICATION windows are never considered floating here because they don't
+ // get cropped / shifted to the displayFrame in WindowState.
+ final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
+ && type != TYPE_BASE_APPLICATION;
final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
@@ -2631,13 +2218,6 @@ public class DisplayPolicy {
}
}
- private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect cf) {
- // The wallpaper has Real Ultimate Power
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- cf.set(displayFrames.mUnrestricted);
- }
-
private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
final int rotation = displayFrames.mRotation;
final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
@@ -3343,54 +2923,37 @@ public class DisplayPolicy {
// Swipe-up for navigation bar is disabled during setup
return;
}
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
- final InsetsControlTarget controlTarget = provider != null
- ? provider.getControlTarget() : null;
+ final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
+ final InsetsControlTarget controlTarget = provider != null
+ ? provider.getControlTarget() : null;
- if (controlTarget == null || controlTarget == getNotificationShade()) {
- // No transient mode on lockscreen (in notification shade window).
- return;
- }
+ if (controlTarget == null || controlTarget == getNotificationShade()) {
+ // No transient mode on lockscreen (in notification shade window).
+ return;
+ }
- final InsetsState requestedState = controlTarget.getRequestedInsetsState();
- final @InsetsType int restorePositionTypes =
- (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
- ? Type.navigationBars() : 0)
- | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
- ? Type.statusBars() : 0);
-
- if (swipeTarget == mNavigationBar
- && (restorePositionTypes & Type.navigationBars()) != 0) {
- // Don't show status bar when swiping on already visible navigation bar.
- // But restore the position of navigation bar if it has been moved by the control
- // target.
- controlTarget.showInsets(Type.navigationBars(), false);
- return;
- }
+ final InsetsState requestedState = controlTarget.getRequestedInsetsState();
+ final @InsetsType int restorePositionTypes = (requestedState.getSourceOrDefaultVisibility(
+ ITYPE_NAVIGATION_BAR) ? Type.navigationBars() : 0) | (
+ requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR) ? Type.statusBars()
+ : 0);
- if (controlTarget.canShowTransient()) {
- // Show transient bars if they are hidden; restore position if they are visible.
- mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
- controlTarget.showInsets(restorePositionTypes, false);
- } else {
- // Restore visibilities and positions of system bars.
- controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
- }
+ if (swipeTarget == mNavigationBar
+ && (restorePositionTypes & Type.navigationBars()) != 0) {
+ // Don't show status bar when swiping on already visible navigation bar.
+ // But restore the position of navigation bar if it has been moved by the control
+ // target.
+ controlTarget.showInsets(Type.navigationBars(), false);
+ return;
+ }
+
+ if (controlTarget.canShowTransient()) {
+ // Show transient bars if they are hidden; restore position if they are visible.
+ mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
+ controlTarget.showInsets(restorePositionTypes, false);
} else {
- boolean sb = mStatusBarController.checkShowTransientBarLw();
- boolean nb = mNavigationBarController.checkShowTransientBarLw()
- && !isNavBarEmpty(mLastSystemUiFlags);
- if (sb || nb) {
- // Don't show status bar when swiping on already visible navigation bar
- if (!nb && swipeTarget == mNavigationBar) {
- if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
- return;
- }
- if (sb) mStatusBarController.showTransient();
- if (nb) mNavigationBarController.showTransient();
- updateSystemUiVisibilityLw();
- }
+ // Restore visibilities and positions of system bars.
+ controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
}
mImmersiveModeConfirmation.confirmCurrentPrompt();
}
@@ -3479,11 +3042,10 @@ public class DisplayPolicy {
navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
final int opaqueAppearance = InsetsFlags.getAppearance(visibility)
& (APPEARANCE_OPAQUE_STATUS_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS);
- final int appearance = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- ? updateLightNavigationBarAppearanceLw(win.mAttrs.insetsFlags.appearance,
- mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
- mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance
- : InsetsFlags.getAppearance(visibility);
+ final int appearance = updateLightNavigationBarAppearanceLw(
+ win.mAttrs.insetsFlags.appearance, mTopFullscreenOpaqueWindowState,
+ mTopFullscreenOpaqueOrDimmingWindowState,
+ mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance;
final int diff = visibility ^ mLastSystemUiFlags;
final InsetsPolicy insetsPolicy = getInsetsPolicy();
final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
@@ -3805,9 +3367,8 @@ public class DisplayPolicy {
vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
// update navigation bar
- boolean newInsetsMode = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL;
- boolean oldImmersiveMode = newInsetsMode ? mLastImmersiveMode : isImmersiveMode(oldVis);
- boolean newImmersiveMode = newInsetsMode ? isImmersiveMode(win) : isImmersiveMode(vis);
+ boolean oldImmersiveMode = mLastImmersiveMode;
+ boolean newImmersiveMode = isImmersiveMode(win);
if (oldImmersiveMode != newImmersiveMode) {
mLastImmersiveMode = newImmersiveMode;
final String pkg = win.getOwningPackage();
@@ -3911,15 +3472,6 @@ public class DisplayPolicy {
}
}
- // TODO(b/118118435): Remove this after migration
- private boolean isImmersiveMode(int vis) {
- final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- return getNavigationBar() != null
- && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
- && (vis & flags) != 0
- && canHideNavigationBar();
- }
-
private boolean isImmersiveMode(WindowState win) {
if (win == null) {
return false;
@@ -4110,9 +3662,7 @@ public class DisplayPolicy {
mPointerLocationView = new PointerLocationView(mContext);
mPointerLocationView.setPrintCoords(false);
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.MATCH_PARENT);
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
lp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 0206787ef226..0f43e49b568b 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -330,10 +330,8 @@ public class DisplayRotation {
// It's also not likely to rotate a TV screen.
final boolean isTv = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK);
- final boolean forceDesktopMode =
- mService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay;
mDefaultFixedToUserRotation =
- (isCar || isTv || mService.mIsPc || forceDesktopMode)
+ (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode())
// For debug purposes the next line turns this feature off with:
// $ adb shell setprop config.override_forced_orient true
// $ adb shell wm size reset
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index df7c07055e87..c8c83a6e34f0 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -248,7 +248,7 @@ class DisplayWindowSettings {
writeSettingsIfNeeded(entry, displayInfo);
}
- private int getWindowingModeLocked(Entry entry, int displayId) {
+ private int getWindowingModeLocked(Entry entry, DisplayContent dc) {
int windowingMode = entry != null ? entry.mWindowingMode
: WindowConfiguration.WINDOWING_MODE_UNDEFINED;
// This display used to be in freeform, but we don't support freeform anymore, so fall
@@ -259,10 +259,8 @@ class DisplayWindowSettings {
}
// No record is present so use default windowing mode policy.
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- final boolean forceDesktopMode = mService.mForceDesktopModeOnExternalDisplays
- && displayId != Display.DEFAULT_DISPLAY;
windowingMode = mService.mAtmService.mSupportsFreeformWindowManagement
- && (mService.mIsPc || forceDesktopMode)
+ && (mService.mIsPc || dc.forceDesktopMode())
? WindowConfiguration.WINDOWING_MODE_FREEFORM
: WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
}
@@ -272,7 +270,7 @@ class DisplayWindowSettings {
int getWindowingModeLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
final Entry entry = getEntry(displayInfo);
- return getWindowingModeLocked(entry, dc.getDisplayId());
+ return getWindowingModeLocked(entry, dc);
}
void setWindowingModeLocked(DisplayContent dc, int mode) {
@@ -382,7 +380,7 @@ class DisplayWindowSettings {
final Entry entry = getOrCreateEntry(displayInfo);
// Setting windowing mode first, because it may override overscan values later.
- dc.setWindowingMode(getWindowingModeLocked(entry, dc.getDisplayId()));
+ dc.setWindowingMode(getWindowingModeLocked(entry, dc));
dc.getDisplayRotation().restoreSettings(entry.mUserRotationMode,
entry.mUserRotation, entry.mFixedToUserRotation);
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 999aab982816..ec62ed44c640 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -114,7 +114,7 @@ class DragDropController {
final WindowState callingWin = mService.windowForClientLocked(
null, window, false);
- if (callingWin == null || callingWin.cantReceiveTouchInput()) {
+ if (callingWin == null || !callingWin.canReceiveTouchInput()) {
Slog.w(TAG_WM, "Bad requesting window " + window);
return null; // !!! TODO: throw here?
}
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index e166bfc08ad4..0978636ea502 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -24,6 +24,7 @@ import android.view.InputApplicationHandle;
import android.view.KeyEvent;
import android.view.WindowManager;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
import com.android.server.input.InputManagerService;
import com.android.server.wm.EmbeddedWindowController.EmbeddedWindow;
@@ -252,7 +253,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
// All the calls below need to happen without the WM lock held since they call into AM.
mService.mAtmInternal.saveANRState(reason);
- if (activity != null && activity.appToken != null) {
+ if (activity != null) {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
final boolean abort = activity.keyDispatchingTimedOut(reason, windowPid);
@@ -410,6 +411,8 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
requestRefreshConfiguration = dispatchPointerCaptureChanged(focusedWindow, false);
}
mFocusedWindow.set(newFocusedWindow);
+ mService.mH.sendMessage(PooledLambda.obtainMessage(mService::reportFocusChanged,
+ oldToken, newToken));
return requestRefreshConfiguration;
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index fb511e032c98..4efd687b7bb4 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -370,7 +370,8 @@ final class InputMonitor {
* Layer assignment is assumed to be complete by the time this is called.
*/
public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
- ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s", newWindow);
+ ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s display=%d",
+ newWindow, mDisplayId);
if (newWindow != mInputFocus) {
if (newWindow != null && newWindow.canReceiveKeys()) {
@@ -493,7 +494,7 @@ final class InputMonitor {
final int type = w.mAttrs.type;
final boolean isVisible = w.isVisibleLw();
if (inputChannel == null || inputWindowHandle == null || w.mRemoved
- || (w.cantReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
+ || (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
if (w.mWinAnimator.hasSurface()) {
// Assign an InputInfo with type to the overlay window which can't receive input
// event. This is used to omit Surfaces from occlusion detection.
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index c36a75b01293..69e8c57a489c 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -190,7 +190,7 @@ class KeyguardController {
mAodShowing ? 1 : 0,
1 /* keyguardGoingAway */,
"keyguardGoingAway");
- mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mRootWindowContainer.getDefaultDisplay()
.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
false /* alwaysKeepCurrent */, convertTransitFlags(flags),
false /* forceOverride */);
@@ -314,7 +314,7 @@ class KeyguardController {
if (isKeyguardLocked()) {
mService.deferWindowLayout();
try {
- mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mRootWindowContainer.getDefaultDisplay()
.prepareAppTransition(resolveOccludeTransit(),
false /* alwaysKeepCurrent */, 0 /* flags */,
true /* forceOverride */);
@@ -344,8 +344,7 @@ class KeyguardController {
// If we are about to unocclude the Keyguard, but we can dismiss it without security,
// we immediately dismiss the Keyguard so the activity gets shown without a flicker.
- final DisplayContent dc =
- mRootWindowContainer.getDefaultDisplay().mDisplayContent;
+ final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
if (mKeyguardShowing && canDismissKeyguard()
&& dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
dc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
@@ -368,7 +367,7 @@ class KeyguardController {
}
private int resolveOccludeTransit() {
- final DisplayContent dc = mRootWindowContainer.getDefaultDisplay().mDisplayContent;
+ final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
&& dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
// TODO(b/113840485): Handle app transition for individual display.
@@ -485,7 +484,7 @@ class KeyguardController {
}
// TODO(b/123372519): isShowingDream can only works on default display.
if (mDisplayId == DEFAULT_DISPLAY) {
- mOccluded |= mService.mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mOccluded |= mService.mRootWindowContainer.getDefaultDisplay()
.getDisplayPolicy().isShowingDreamLw();
}
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index c8d7693c9229..c49690157c08 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -619,7 +619,7 @@ public class LockTaskController {
mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities();
final Task rootTask = task.getRootTask();
if (rootTask != null) {
- rootTask.getDisplay().mDisplayContent.executeAppTransition();
+ rootTask.mDisplayContent.executeAppTransition();
}
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index 4be4c896cbff..1077736cebb5 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -11,3 +11,4 @@ erosky@google.com
riddlehsu@google.com
louischang@google.com
winsonc@google.com
+tigerhuang@google.com
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 3c64ffb237d6..255b3f147d30 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1346,11 +1346,8 @@ class RecentTasks {
// singleTaskInstance is set on the VirtualDisplay managed by ActivityView
// TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance
final Task rootTask = task.getRootTask();
- if (rootTask != null) {
- DisplayContent display = rootTask.getDisplay();
- if (display != null && display.isSingleTaskInstance()) {
- return false;
- }
+ if (rootTask != null && rootTask.isSingleTaskInstance()) {
+ return false;
}
// If we're in lock task mode, ignore the root task
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 21e30ce0a495..6539e1325ec1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -129,6 +129,7 @@ import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.IntArray;
@@ -162,7 +163,6 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -214,7 +214,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
private int mTopFocusedDisplayId = INVALID_DISPLAY;
// Map from the PID to the top most app which has a focused window of the process.
- final HashMap<Integer, ActivityRecord> mTopFocusedAppByProcess = new HashMap<>();
+ final ArrayMap<Integer, ActivityRecord> mTopFocusedAppByProcess = new ArrayMap<>();
// Only a separate transaction until we separate the apply surface changes
// transaction from the global transaction.
@@ -480,8 +480,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mTopFocusedDisplayId = topFocusedDisplayId;
mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);
mWmService.mPolicy.setTopFocusedDisplay(topFocusedDisplayId);
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d",
- topFocusedDisplayId);
+ ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d", topFocusedDisplayId);
}
return changed;
}
@@ -2289,10 +2288,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- if (display.shouldSleep()) {
- continue;
- }
-
final boolean curResult = result;
boolean resumedOnDisplay = display.reduceOnAllTaskDisplayAreas(
(taskDisplayArea, resumed) -> {
@@ -2753,7 +2748,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
r.detachFromProcess();
- r.getDisplay().mDisplayContent.prepareAppTransition(
+ r.mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
r.destroyIfPossible("handleAppCrashed");
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 33935d61ead2..7df2b407557d 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -26,6 +26,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.util.DebugUtils;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
@@ -429,7 +430,8 @@ class SurfaceAnimator {
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mLeash="); pw.print(mLeash);
- pw.print(" mAnimationType=" + mAnimationType);
+ pw.print(" mAnimationType=" + DebugUtils.valueToString(SurfaceAnimator.class,
+ "ANIMATION_TYPE_", mAnimationType));
pw.println(mAnimationStartDelayed ? " mAnimationStartDelayed=true" : "");
pw.print(prefix); pw.print("Animation: "); pw.println(mAnimation);
if (mAnimation != null) {
@@ -442,56 +444,56 @@ class SurfaceAnimator {
* No animation is specified.
* @hide
*/
- static final int ANIMATION_TYPE_NONE = 0;
+ public static final int ANIMATION_TYPE_NONE = 0;
/**
* Animation for an app transition.
* @hide
*/
- static final int ANIMATION_TYPE_APP_TRANSITION = 1;
+ public static final int ANIMATION_TYPE_APP_TRANSITION = 1;
/**
* Animation for screen rotation.
* @hide
*/
- static final int ANIMATION_TYPE_SCREEN_ROTATION = 1 << 1;
+ public static final int ANIMATION_TYPE_SCREEN_ROTATION = 1 << 1;
/**
* Animation for dimming.
* @hide
*/
- static final int ANIMATION_TYPE_DIMMER = 1 << 2;
+ public static final int ANIMATION_TYPE_DIMMER = 1 << 2;
/**
* Animation for recent apps.
* @hide
*/
- static final int ANIMATION_TYPE_RECENTS = 1 << 3;
+ public static final int ANIMATION_TYPE_RECENTS = 1 << 3;
/**
* Animation for a {@link WindowState} without animating the activity.
* @hide
*/
- static final int ANIMATION_TYPE_WINDOW_ANIMATION = 1 << 4;
+ public static final int ANIMATION_TYPE_WINDOW_ANIMATION = 1 << 4;
/**
* Animation to control insets. This is actually not an animation, but is used to give the
* client a leash over the system window causing insets.
* @hide
*/
- static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
+ public static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5;
/**
* Animation when a fixed rotation transform is applied to a window token.
* @hide
*/
- static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
+ public static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6;
/**
* Bitmask to include all animation types. This is NOT an {@link AnimationType}
* @hide
*/
- static final int ANIMATION_TYPE_ALL = -1;
+ public static final int ANIMATION_TYPE_ALL = -1;
/**
* The type of the animation.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 19bf451cec05..c35d73282442 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2319,8 +2319,7 @@ class Task extends WindowContainer<WindowContainer> {
taskDisplayArea.onStackWindowingModeChanged(this);
}
- final DisplayContent display = getDisplay();
- if (display == null ) {
+ if (mDisplayContent == null) {
return;
}
@@ -2336,7 +2335,7 @@ class Task extends WindowContainer<WindowContainer> {
final int newRotation = getWindowConfiguration().getRotation();
final boolean rotationChanged = prevRotation != newRotation;
if (rotationChanged) {
- display.mDisplayContent.rotateBounds(
+ mDisplayContent.rotateBounds(
newParentConfig.windowConfiguration.getBounds(), prevRotation, newRotation,
newBounds);
hasNewOverrideBounds = true;
@@ -2594,15 +2593,12 @@ class Task extends WindowContainer<WindowContainer> {
outNonDecorBounds.set(bounds);
outStableBounds.set(bounds);
final Task rootTask = getRootTask();
- if (rootTask == null || rootTask.getDisplay() == null) {
- return;
- }
- DisplayPolicy policy = rootTask.getDisplay().mDisplayContent.getDisplayPolicy();
- if (policy == null) {
+ if (rootTask == null || rootTask.mDisplayContent == null) {
return;
}
mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
@@ -2990,14 +2986,6 @@ class Task extends WindowContainer<WindowContainer> {
}
}
- @Override
- DisplayContent getDisplayContent() {
- // TODO: Why aren't we just using our own display content vs. parent's???
- final Task stack = getRootTask();
- return stack != null && stack != this
- ? stack.getDisplayContent() : super.getDisplayContent();
- }
-
int getDisplayId() {
final DisplayContent dc = getDisplayContent();
return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
@@ -5173,14 +5161,9 @@ class Task extends WindowContainer<WindowContainer> {
!PRESERVE_WINDOWS);
}
- DisplayContent getDisplay() {
- return getDisplayContent();
- }
-
/** @return true if the stack can only contain one task */
boolean isSingleTaskInstance() {
- final DisplayContent display = getDisplay();
- return display != null && display.isSingleTaskInstance();
+ return mDisplayContent != null && mDisplayContent.isSingleTaskInstance();
}
final boolean isHomeOrRecentsStack() {
@@ -5445,6 +5428,7 @@ class Task extends WindowContainer<WindowContainer> {
mAtmService.updateCpuStats();
boolean pauseImmediately = false;
+ boolean shouldAutoPip = false;
if (resuming != null && (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0) {
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
// activity to be paused, while at the same time resuming the new resume activity
@@ -5452,26 +5436,39 @@ class Task extends WindowContainer<WindowContainer> {
// activities a chance to enter Pip before resuming the next activity.
final boolean lastResumedCanPip = prev != null && prev.checkEnterPictureInPictureState(
"shouldResumeWhilePausing", userLeaving);
- if (!lastResumedCanPip) {
+ if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterAllowed()) {
+ shouldAutoPip = true;
+ } else if (!lastResumedCanPip) {
pauseImmediately = true;
+ } else {
+ // The previous activity may still enter PIP even though it did not allow auto-PIP.
}
}
+ boolean didAutoPip = false;
if (prev.attachedToProcess()) {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
- try {
- EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
- prev.shortComponentName, "userLeaving=" + userLeaving);
-
- mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
- prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
- prev.configChangeFlags, pauseImmediately));
- } catch (Exception e) {
- // Ignore exception, if process died other code will cleanup.
- Slog.w(TAG, "Exception thrown during pause", e);
+ if (shouldAutoPip) {
+ if (DEBUG_PAUSE) {
+ Slog.d(TAG_PAUSE, "Auto-PIP allowed, entering PIP mode directly: " + prev);
+ }
+ didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs);
mPausingActivity = null;
- mLastPausedActivity = null;
- mLastNoHistoryActivity = null;
+ } else {
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
+ try {
+ EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
+ prev.shortComponentName, "userLeaving=" + userLeaving);
+
+ mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
+ prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
+ prev.configChangeFlags, pauseImmediately));
+ } catch (Exception e) {
+ // Ignore exception, if process died other code will cleanup.
+ Slog.w(TAG, "Exception thrown during pause", e);
+ mPausingActivity = null;
+ mLastPausedActivity = null;
+ mLastNoHistoryActivity = null;
+ }
}
} else {
mPausingActivity = null;
@@ -5485,6 +5482,11 @@ class Task extends WindowContainer<WindowContainer> {
mStackSupervisor.acquireLaunchWakelock();
}
+ if (didAutoPip) {
+ // Already entered PIP mode, no need to keep pausing.
+ return true;
+ }
+
if (mPausingActivity != null) {
// Have the window manager pause its key dispatching until the new
// activity has started. If we're pausing the activity just because
@@ -5620,8 +5622,7 @@ class Task extends WindowContainer<WindowContainer> {
* otherwise.
*/
boolean isFocusedStackOnDisplay() {
- final DisplayContent display = getDisplay();
- return display != null && this == display.getFocusedStack();
+ return mDisplayContent != null && this == mDisplayContent.getFocusedStack();
}
/**
@@ -5760,7 +5761,7 @@ class Task extends WindowContainer<WindowContainer> {
* {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
*/
boolean canShowWithInsecureKeyguard() {
- final DisplayContent displayContent = getDisplay();
+ final DisplayContent displayContent = mDisplayContent;
if (displayContent == null) {
throw new IllegalStateException("Stack is not attached to any display, stackId="
+ getRootTaskId());
@@ -6348,7 +6349,7 @@ class Task extends WindowContainer<WindowContainer> {
return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea());
}
- void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
+ void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
Task rTask = r.getTask();
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
@@ -6399,7 +6400,7 @@ class Task extends WindowContainer<WindowContainer> {
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.
if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) {
- final DisplayContent dc = getDisplay().mDisplayContent;
+ final DisplayContent dc = mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
@@ -6410,7 +6411,7 @@ class Task extends WindowContainer<WindowContainer> {
if (newTask) {
if (r.mLaunchTaskBehind) {
transit = TRANSIT_TASK_OPEN_BEHIND;
- } else if (getDisplay().isSingleTaskInstance()) {
+ } else if (dc.isSingleTaskInstance()) {
// If a new task is being launched in a single task display, we don't need
// to play normal animation, but need to trigger a callback when an app
// transition is actually handled. So ignore already prepared activity, and
@@ -6454,7 +6455,7 @@ class Task extends WindowContainer<WindowContainer> {
ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
// Go ahead to execute app transition for this activity since the app transition
// will not be triggered through the resume channel.
- getDisplay().mDisplayContent.executeAppTransition();
+ mDisplayContent.executeAppTransition();
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
@@ -6567,7 +6568,7 @@ class Task extends WindowContainer<WindowContainer> {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
Task finishedTask = r.getTask();
- getDisplay().mDisplayContent.prepareAppTransition(
+ mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
r.finishIfPossible(reason, false /* oomAdj */);
@@ -6655,7 +6656,8 @@ class Task extends WindowContainer<WindowContainer> {
// Basic case: for simple app-centric recents, we need to recreate
// the task if the affinity has changed.
- final String affinity = ActivityRecord.getTaskAffinityWithUid(destAffinity, srec.getUid());
+ final String affinity = ActivityRecord.computeTaskAffinity(destAffinity, srec.getUid(),
+ srec.launchMode);
if (srec == null || srec.getTask().affinity == null
|| !srec.getTask().affinity.equals(affinity)) {
return true;
@@ -6807,7 +6809,7 @@ class Task extends WindowContainer<WindowContainer> {
ActivityOptions.abort(options);
}
}
- getDisplay().mDisplayContent.prepareAppTransition(transit, false,
+ mDisplayContent.prepareAppTransition(transit, false,
0 /* flags */, forceOverride);
}
@@ -6855,7 +6857,7 @@ class Task extends WindowContainer<WindowContainer> {
// Defer updating the IME target since the new IME target will try to get computed
// before updating all closing and opening apps, which can cause the ime target to
// get calculated incorrectly.
- getDisplay().deferUpdateImeTarget();
+ mDisplayContent.deferUpdateImeTarget();
// Shift all activities with this task up to the top
// of the stack, keeping them in the same internal order.
@@ -6879,7 +6881,7 @@ class Task extends WindowContainer<WindowContainer> {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
- getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_NONE, false);
+ mDisplayContent.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */);
if (r != null) {
mStackSupervisor.mNoAnimActivities.add(r);
}
@@ -6909,7 +6911,7 @@ class Task extends WindowContainer<WindowContainer> {
mAtmService.getTaskChangeNotificationController()
.notifyTaskMovedToFront(tr.getTaskInfo());
} finally {
- getDisplay().continueUpdateImeTarget();
+ mDisplayContent.continueUpdateImeTarget();
}
}
@@ -6959,7 +6961,7 @@ class Task extends WindowContainer<WindowContainer> {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task="
+ tr.mTaskId);
- getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
+ mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false /* alwaysKeepCurrent */);
moveToBack("moveTaskToBackLocked", tr);
if (inPinnedWindowingMode()) {
@@ -6968,7 +6970,7 @@ class Task extends WindowContainer<WindowContainer> {
}
mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
- getDisplay().mDisplayId, false /* markFrozenIfConfigChanged */,
+ mDisplayContent.mDisplayId, false /* markFrozenIfConfigChanged */,
false /* deferResume */);
ActivityRecord topActivity = getDisplayArea().topRunningActivity();
@@ -6976,7 +6978,7 @@ class Task extends WindowContainer<WindowContainer> {
if (topStack != null && topStack != this && topActivity.isState(RESUMED)) {
// Usually resuming a top activity triggers the next app transition, but nothing's got
// resumed in this case, so we need to execute it explicitly.
- getDisplay().mDisplayContent.executeAppTransition();
+ mDisplayContent.executeAppTransition();
} else {
mRootWindowContainer.resumeFocusedStacksTopActivities();
}
@@ -7575,17 +7577,21 @@ class Task extends WindowContainer<WindowContainer> {
}
void executeAppTransition(ActivityOptions options) {
- getDisplay().mDisplayContent.executeAppTransition();
+ mDisplayContent.executeAppTransition();
ActivityOptions.abort(options);
}
boolean shouldSleepActivities() {
- final DisplayContent display = getDisplay();
+ final DisplayContent display = mDisplayContent;
// Do not sleep activities in this stack if we're marked as focused and the keyguard
// is in the process of going away.
if (isFocusedStackOnDisplay()
- && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()) {
+ && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()
+ // Avoid resuming activities on secondary displays since we don't want bubble
+ // activities to be resumed while bubble is still collapsed.
+ // TODO(b/113840485): Having keyguard going away state for secondary displays.
+ && display.isDefaultDisplay) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index f8465ddc02a2..d9290fb18f08 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
@@ -43,16 +44,15 @@ import android.window.ITaskOrganizerController;
import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.LinkedHashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
import java.util.WeakHashMap;
import java.util.function.Consumer;
@@ -126,6 +126,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void onTaskAppeared(Task task) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
final boolean visible = task.isVisible();
final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
@@ -147,6 +148,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
void onTaskVanished(Task task) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId);
final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
try {
@@ -163,6 +165,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
// by the organizer that don't receive that signal
return;
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
mDeferTaskOrgCallbacksConsumer.accept(() -> {
if (!task.isOrganized()) {
// This is safe to ignore if the task is no longer organized
@@ -177,6 +180,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void onBackPressedOnTaskRoot(Task task) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task back pressed on root taskId=%d",
+ task.mTaskId);
if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
// Skip if the task has not yet received taskAppeared(), except for tasks created
// by the organizer that don't receive that signal
@@ -201,7 +206,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
private final DeathRecipient mDeathRecipient;
private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
private final int mUid;
- private boolean mInterceptBackPressedOnTaskRoot;
TaskOrganizerState(ITaskOrganizer organizer, int uid) {
final Consumer<Runnable> deferTaskOrgCallbacksConsumer =
@@ -219,10 +223,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mUid = uid;
}
- void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) {
- mInterceptBackPressedOnTaskRoot = interceptBackPressed;
- }
-
void addTask(Task t) {
if (t.mTaskAppearedSent) return;
@@ -242,6 +242,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mOrganizer.onTaskVanished(t);
}
mOrganizedTasks.remove(t);
+ mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
}
void dispose() {
@@ -273,6 +274,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
+ // Set of organized tasks (by taskId) that dispatch back pressed to their organizers
+ private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
private final ActivityTaskManagerService mService;
@@ -306,6 +309,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d",
+ organizer.asBinder(), uid);
for (int winMode : SUPPORTED_WINDOWING_MODES) {
if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
mTaskOrganizers.add(organizer);
@@ -327,6 +332,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
@Override
public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
enforceStackPermission("unregisterTaskOrganizer()");
+ final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -334,6 +340,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
if (state == null) {
return;
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task organizer=%s uid=%d",
+ organizer.asBinder(), uid);
state.unlinkDeath();
state.dispose();
}
@@ -383,6 +391,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return null;
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d",
+ displayId, windowingMode);
final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode,
ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(),
true /* createdByOrganizer */);
@@ -407,6 +417,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
throw new IllegalArgumentException(
"Attempt to delete task not created by organizer task=" + task);
}
+
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d",
+ task.getDisplayId(), task.getWindowingMode());
task.removeImmediately();
return true;
}
@@ -608,15 +621,23 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
@Override
- public void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer,
+ public void setInterceptBackPressedOnTaskRoot(WindowContainerToken token,
boolean interceptBackPressed) {
enforceStackPermission("setInterceptBackPressedOnTaskRoot()");
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
- if (state != null) {
- state.setInterceptBackPressedOnTaskRoot(interceptBackPressed);
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set intercept back pressed on root=%b",
+ interceptBackPressed);
+ final Task task = WindowContainer.fromBinder(token.asBinder()).asTask();
+ if (task == null) {
+ Slog.w(TAG, "Could not resolve task from token");
+ return;
+ }
+ if (interceptBackPressed) {
+ mInterceptBackPressedOnRootTasks.add(task.mTaskId);
+ } else {
+ mInterceptBackPressedOnRootTasks.remove(task.mTaskId);
}
}
} finally {
@@ -625,15 +646,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
public boolean handleInterceptBackPressedOnTaskRoot(Task task) {
- if (task == null || !task.isOrganized()) {
+ if (task == null || !task.isOrganized()
+ || !mInterceptBackPressedOnRootTasks.contains(task.mTaskId)) {
return false;
}
final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
- if (!state.mInterceptBackPressedOnTaskRoot) {
- return false;
- }
-
state.mOrganizer.onBackPressedOnTaskRoot(task);
return true;
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index e3112efdead2..f39fa1b7fbc8 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -16,7 +16,9 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -615,8 +617,8 @@ class TaskSnapshotController {
return state.calculateInsets(frame, null /* ignoringVisibilityState */,
false /* isScreenRound */, false /* alwaysConsumeSystemBars */,
null /* displayCutout */, 0 /* legacySoftInputMode */, 0 /* legacyWindowFlags */,
- 0 /* legacySystemUiFlags */, null /* typeSideMap */).getInsets(
- WindowInsets.Type.systemBars()).toRect();
+ 0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+ null /* typeSideMap */).getInsets(WindowInsets.Type.systemBars()).toRect();
}
void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c45ccb6e17e3..017747f03ca0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -376,8 +376,11 @@ public class WindowManagerService extends IWindowManager.Stub
private static final String BOOT_ANIMATION_SERVICE = "bootanim";
static final int UPDATE_FOCUS_NORMAL = 0;
+ /** Caller will assign layers */
static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
+ /** Caller is performing surface placement */
static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
+ /** Caller will performSurfacePlacement */
static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
/** Indicates we are removing the focused window when updating the focus. */
static final int UPDATE_FOCUS_REMOVING_FOCUS = 4;
@@ -1407,7 +1410,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (!displayContent.hasAccess(session.mUid)) {
ProtoLog.w(WM_ERROR,
"Attempted to add window to a display for which the application "
- + "does not have access: %d. Aborting.", displayId);
+ + "does not have access: %d. Aborting.",
+ displayContent.getDisplayId());
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
@@ -4730,12 +4734,30 @@ public class WindowManagerService extends IWindowManager.Stub
return false;
}
+ void reportFocusChanged(IBinder oldToken, IBinder newToken) {
+ WindowState lastFocus;
+ WindowState newFocus;
+ synchronized (mGlobalLock) {
+ lastFocus = mInputToWindowMap.get(oldToken);
+ newFocus = mInputToWindowMap.get(newToken);
+ ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus changing: %s -> %s", lastFocus, newFocus);
+ }
+
+ if (newFocus != null) {
+ newFocus.reportFocusChangedSerialized(true);
+ notifyFocusChanged();
+ }
+
+ if (lastFocus != null) {
+ lastFocus.reportFocusChangedSerialized(false);
+ }
+ }
+
// -------------------------------------------------------------
// Async Handler
// -------------------------------------------------------------
final class H extends android.os.Handler {
- public static final int REPORT_FOCUS_CHANGE = 2;
public static final int WINDOW_FREEZE_TIMEOUT = 11;
public static final int PERSIST_ANIMATION_SCALE = 14;
@@ -4788,50 +4810,6 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.v(TAG_WM, "handleMessage: entry what=" + msg.what);
}
switch (msg.what) {
- case REPORT_FOCUS_CHANGE: {
- final DisplayContent displayContent = (DisplayContent) msg.obj;
- WindowState lastFocus;
- WindowState newFocus;
-
- AccessibilityController accessibilityController = null;
-
- synchronized (mGlobalLock) {
- if (mAccessibilityController != null) {
- accessibilityController = mAccessibilityController;
- }
-
- lastFocus = displayContent.mLastFocus;
- newFocus = displayContent.mCurrentFocus;
- if (lastFocus == newFocus) {
- // Focus is not changing, so nothing to do.
- return;
- }
- displayContent.mLastFocus = newFocus;
- ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus moving from %s"
- + " to %s displayId=%d", lastFocus, newFocus,
- displayContent.getDisplayId());
- }
-
- // First notify the accessibility manager for the change so it has
- // the windows before the newly focused one starts firing events.
- if (accessibilityController != null) {
- accessibilityController.onWindowFocusChangedNotLocked(
- displayContent.getDisplayId());
- }
-
- if (newFocus != null) {
- ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Gaining focus: %s", newFocus);
- newFocus.reportFocusChangedSerialized(true);
- notifyFocusChanged();
- }
-
- if (lastFocus != null) {
- ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Losing focus: %s", lastFocus);
- lastFocus.reportFocusChangedSerialized(false);
- }
- break;
- }
-
case WINDOW_FREEZE_TIMEOUT: {
final DisplayContent displayContent = (DisplayContent) msg.obj;
synchronized (mGlobalLock) {
@@ -7994,6 +7972,8 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
+ ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s",
+ touchedWindow);
final DisplayContent displayContent = touchedWindow.getDisplayContent();
if (!displayContent.isOnTop()) {
displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent,
@@ -8022,10 +8002,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- try {
- mActivityTaskManager.setFocusedTask(task.mTaskId);
- } catch (RemoteException e) {
- }
+ mAtmService.setFocusedTask(task.mTaskId);
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d25a64890337..c7cad2f76486 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
@@ -45,6 +46,7 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -127,6 +129,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (callback != null) {
syncId = startSyncWithOrganizer(callback);
}
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d",
+ syncId);
mService.deferWindowLayout();
try {
ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
@@ -427,6 +431,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
@VisibleForTesting
void setSyncReady(int id) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set sync ready, syncId=%d", id);
mBLASTSyncEngine.setReady(id);
}
@@ -436,9 +441,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
@Override
- public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) {
+ public void onTransactionReady(int syncId, Set<WindowContainer> windowContainersReady) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Transaction ready, syncId=%d", syncId);
final IWindowContainerTransactionCallback callback =
- mTransactionCallbacksByPendingSyncId.get(mSyncId);
+ mTransactionCallbacksByPendingSyncId.get(syncId);
SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction();
for (WindowContainer container : windowContainersReady) {
@@ -446,14 +452,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
try {
- callback.onTransactionReady(mSyncId, mergedTransaction);
+ callback.onTransactionReady(syncId, mergedTransaction);
} catch (RemoteException e) {
// If there's an exception when trying to send the mergedTransaction to the client, we
// should immediately apply it here so the transactions aren't lost.
mergedTransaction.apply();
}
- mTransactionCallbacksByPendingSyncId.remove(mSyncId);
+ mTransactionCallbacksByPendingSyncId.remove(syncId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c5ebace78261..8bf0820c7dad 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -729,15 +729,16 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return true;
}
- final DisplayContent display = activity.getDisplay();
- if (display == null) {
+ if (!activity.isAttached()) {
// No need to update if the activity hasn't attach to any display.
return false;
}
boolean canUpdate = false;
final DisplayContent topDisplay =
- mPreQTopResumedActivity != null ? mPreQTopResumedActivity.getDisplay() : null;
+ (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isAttached())
+ ? mPreQTopResumedActivity.mDisplayContent
+ : null;
// Update the topmost activity if current top activity is
// - not on any display OR
// - no longer visible OR
@@ -748,8 +749,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
canUpdate = true;
}
+ final DisplayContent display = activity.mDisplayContent;
// Update the topmost activity if the current top activity wasn't on top of the other one.
- if (!canUpdate && topDisplay.mDisplayContent.compareTo(display.mDisplayContent) < 0) {
+ if (!canUpdate && topDisplay.compareTo(display) < 0) {
canUpdate = true;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9ff33b18cb89..84a9c750d2d3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2884,12 +2884,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return canReceiveKeys(false /* fromUserTouch */);
}
+ public String canReceiveKeysReason(boolean fromUserTouch) {
+ return "fromTouch= " + fromUserTouch
+ + " isVisibleOrAdding=" + isVisibleOrAdding()
+ + " mViewVisibility=" + mViewVisibility
+ + " mRemoveOnExit=" + mRemoveOnExit
+ + " flags=" + mAttrs.flags
+ + " appWindowsAreFocusable="
+ + (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
+ + " canReceiveTouchInput=" + canReceiveTouchInput()
+ + " displayIsOnTop=" + getDisplayContent().isOnTop()
+ + " displayIsTrusted=" + getDisplayContent().isTrusted();
+ }
+
public boolean canReceiveKeys(boolean fromUserTouch) {
final boolean canReceiveKeys = isVisibleOrAdding()
&& (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
&& (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
- && !cantReceiveTouchInput();
+ && canReceiveTouchInput();
if (!canReceiveKeys) {
return false;
}
@@ -2907,15 +2920,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return showBecauseOfActivity || showBecauseOfWindow;
}
- /** @return {@code false} if this window desires touch events. */
- boolean cantReceiveTouchInput() {
- if (mActivityRecord == null || mActivityRecord.getTask() == null) {
- return false;
+ /**
+ * @return {@code true} if this window can receive touches based on among other things,
+ * windowing state and recents animation state.
+ **/
+ boolean canReceiveTouchInput() {
+ if (mActivityRecord == null || mActivityRecord.getTask() == null) {
+ return true;
}
- return mActivityRecord.getTask().getRootTask().shouldIgnoreInput()
- || !mActivityRecord.mVisibleRequested
- || isRecentsAnimationConsumingAppInput();
+ return !mActivityRecord.getTask().getRootTask().shouldIgnoreInput()
+ && mActivityRecord.mVisibleRequested
+ && !isRecentsAnimationConsumingAppInput();
}
/**
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 4b5f38c40e4f..d84f9d1a7dad 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -97,6 +97,7 @@ cc_defaults {
"libnativehelper",
"libnativewindow",
"libpowermanager",
+ "libprocessgroup",
"libutils",
"libui",
"libvibratorservice",
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 6a6da0e2b395..7e9e11d209a6 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -30,6 +30,7 @@
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
+#include <processgroup/processgroup.h>
using android::base::StringPrintf;
using android::base::WriteStringToFile;
@@ -74,9 +75,26 @@ static void com_android_server_am_CachedAppOptimizer_compactSystem(JNIEnv *, job
}
}
+static void com_android_server_am_CachedAppOptimizer_enableFreezerInternal(
+ JNIEnv *env, jobject clazz, jboolean enable) {
+ bool success = true;
+
+ if (enable) {
+ success = SetTaskProfiles(0, {"FreezerEnabled"}, true);
+ } else {
+ success = SetTaskProfiles(0, {"FreezerDisabled"}, true);
+ }
+
+ if (!success) {
+ jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
+ }
+}
+
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
+ {"enableFreezerInternal", "(Z)V",
+ (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal},
};
int register_android_server_am_CachedAppOptimizer(JNIEnv* env)
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9751c46f93c9..5dd6cd7b42e9 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -233,7 +233,8 @@ public:
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId);
virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices);
- virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier);
+ virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
+ const InputDeviceIdentifier& identifier);
virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier);
virtual TouchAffineTransformation getTouchAffineTransformation(JNIEnv *env,
jfloatArray matrixArr);
@@ -622,12 +623,12 @@ void NativeInputManager::notifyInputDevicesChanged(const std::vector<InputDevice
checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged");
}
-sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
+std::shared_ptr<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
const InputDeviceIdentifier& identifier) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
- sp<KeyCharacterMap> result;
+ std::shared_ptr<KeyCharacterMap> result;
ScopedLocalRef<jstring> descriptor(env, env->NewStringUTF(identifier.descriptor.c_str()));
ScopedLocalRef<jobject> identifierObj(env, env->NewObject(gInputDeviceIdentifierInfo.clazz,
gInputDeviceIdentifierInfo.constructor, descriptor.get(),
@@ -642,8 +643,12 @@ sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
ScopedUtfChars filenameChars(env, filenameObj.get());
ScopedUtfChars contentsChars(env, contentsObj.get());
- KeyCharacterMap::loadContents(filenameChars.c_str(),
- contentsChars.c_str(), KeyCharacterMap::FORMAT_OVERLAY, &result);
+ base::Result<std::shared_ptr<KeyCharacterMap>> ret =
+ KeyCharacterMap::loadContents(filenameChars.c_str(), contentsChars.c_str(),
+ KeyCharacterMap::FORMAT_OVERLAY);
+ if (ret) {
+ result = *ret;
+ }
}
checkAndClearExceptionFromCallback(env, "getKeyboardLayoutOverlay");
return result;
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 777cbf410b9b..4e53aa218b71 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -928,7 +928,7 @@ Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSys
* GnssPsdsCallback class implements the callback methods for the IGnssPsds
* interface.
*/
-class GnssPsdsCallback : public IGnssPsdsCallback {
+struct GnssPsdsCallback : public IGnssPsdsCallback {
Return<void> downloadRequestCb() override;
Return<void> downloadRequestCb_3_0(int32_t psdsType) override;
};
@@ -2743,19 +2743,26 @@ static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env
static jboolean android_location_GnssLocationProvider_supports_psds(
JNIEnv* /* env */, jobject /* obj */) {
- return (gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+ return (gnssPsdsIface != nullptr || gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
}
static void android_location_GnssLocationProvider_inject_psds_data(JNIEnv* env, jobject /* obj */,
- jbyteArray data, jint length) {
- if (gnssXtraIface == nullptr) {
- ALOGE("%s: IGnssXtra interface not available.", __func__);
+ jbyteArray data, jint length,
+ jint psdsType) {
+ if (gnssPsdsIface == nullptr && gnssXtraIface == nullptr) {
+ ALOGE("%s: IGnssPsds or IGnssXtra interface not available.", __func__);
return;
}
jbyte* bytes = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(data, 0));
- auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
- checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ if (gnssPsdsIface != nullptr) {
+ auto result = gnssPsdsIface->injectPsdsData_3_0(psdsType,
+ std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssPsds injectPsdsData() failed.");
+ } else if (gnssXtraIface != nullptr) {
+ auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ }
env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
}
@@ -3685,7 +3692,7 @@ static const JNINativeMethod sLocationProviderMethods[] = {
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_location)},
{"native_supports_psds", "()Z",
reinterpret_cast<void*>(android_location_GnssLocationProvider_supports_psds)},
- {"native_inject_psds_data", "([BI)V",
+ {"native_inject_psds_data", "([BII)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_psds_data)},
{"native_agps_set_id", "(ILjava/lang/String;)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_agps_set_id)},
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index 0277f16d5e54..46e6f912edb0 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -33,6 +33,8 @@
#include <android-base/unique_fd.h>
+#include <type_traits>
+
namespace android {
namespace {
@@ -53,7 +55,7 @@ int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath, jbyteArra
fsverity_enable_arg arg = {};
arg.version = 1;
- arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
+ arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; // hardcoded in measureFsverity below
arg.block_size = 4096;
arg.salt_size = 0;
arg.salt_ptr = reinterpret_cast<uintptr_t>(nullptr);
@@ -85,9 +87,41 @@ int statxForFsverity(JNIEnv *env, jobject /* clazz */, jstring filePath) {
return (out.stx_attributes & STATX_ATTR_VERITY) != 0;
}
+int measureFsverity(JNIEnv *env, jobject /* clazz */, jstring filePath, jbyteArray digest) {
+ static constexpr auto kDigestSha256 = 32;
+ using Storage = std::aligned_storage_t<sizeof(fsverity_digest) + kDigestSha256>;
+
+ Storage bytes;
+ fsverity_digest *data = reinterpret_cast<fsverity_digest *>(&bytes);
+ data->digest_size = kDigestSha256; // the only input/output parameter
+
+ ScopedUtfChars path(env, filePath);
+ ::android::base::unique_fd rfd(open(path.c_str(), O_RDONLY | O_CLOEXEC));
+ if (rfd.get() < 0) {
+ return rfd.get();
+ }
+ if (auto err = ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data); err < 0) {
+ return err;
+ }
+
+ if (data->digest_algorithm != FS_VERITY_HASH_ALG_SHA256) {
+ return -EINVAL;
+ }
+
+ if (digest != nullptr && data->digest_size > 0) {
+ auto digestSize = env->GetArrayLength(digest);
+ if (data->digest_size > digestSize) {
+ return -E2BIG;
+ }
+ env->SetByteArrayRegion(digest, 0, data->digest_size, (const jbyte *)data->digest);
+ }
+
+ return 0;
+}
const JNINativeMethod sMethods[] = {
{"enableFsverityNative", "(Ljava/lang/String;[B)I", (void *)enableFsverity},
{"statxForFsverityNative", "(Ljava/lang/String;)I", (void *)statxForFsverity},
+ {"measureFsverityNative", "(Ljava/lang/String;[B)I", (void *)measureFsverity},
};
} // namespace
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 22e309cdc2b4..80455833a3eb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5782,9 +5782,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mHasFeature) {
return;
}
- final CallerIdentity identity = getCallerIdentity();
- Preconditions.checkCallAuthorization(isSystemUid(identity) || isRootUid(identity)
- || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL));
final ActiveAdmin admin;
synchronized (getLockObject()) {
@@ -9438,8 +9435,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(isDeviceOwner(identity));
return mInjector.binderWithCleanCallingIdentity(() -> {
- final List<UserInfo> userInfos = mInjector.getUserManager().getUsers(true
- /*excludeDying*/);
+ final List<UserInfo> userInfos = mInjector.getUserManager().getAliveUsers();
final List<UserHandle> userHandles = new ArrayList<>();
for (UserInfo userInfo : userInfos) {
UserHandle userHandle = userInfo.getUserHandle();
@@ -10362,7 +10358,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private void maybeClearLockTaskPolicyLocked() {
mInjector.binderWithCleanCallingIdentity(() -> {
- final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
+ final List<UserInfo> userInfos = mUserManager.getAliveUsers();
for (int i = userInfos.size() - 1; i >= 0; i--) {
int userId = userInfos.get(i).id;
if (canUserUseLockTaskLocked(userId)) {
@@ -10849,7 +10845,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
* them.
*/
void updateUserSetupCompleteAndPaired() {
- List<UserInfo> users = mUserManager.getUsers(true);
+ List<UserInfo> users = mUserManager.getAliveUsers();
final int N = users.size();
for (int i = 0; i < N; i++) {
int userHandle = users.get(i).id;
@@ -12052,14 +12048,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public boolean isSystemOnlyUser(ComponentName admin) {
- Objects.requireNonNull(admin, "ComponentName is null");
- final CallerIdentity identity = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isDeviceOwner(identity));
- return UserManager.isSplitSystemUser() && identity.getUserId() == UserHandle.USER_SYSTEM;
- }
-
- @Override
public void reboot(ComponentName admin) {
Objects.requireNonNull(admin, "ComponentName is null");
final CallerIdentity identity = getCallerIdentity(admin);
@@ -12579,7 +12567,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private boolean areAllUsersAffiliatedWithDeviceLocked() {
return mInjector.binderWithCleanCallingIdentity(() -> {
- final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
+ final List<UserInfo> userInfos = mUserManager.getAliveUsers();
for (int i = 0; i < userInfos.size(); i++) {
int userId = userInfos.get(i).id;
if (!isUserAffiliatedWithDeviceLocked(userId)) {
@@ -13048,7 +13036,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
} else {
// Caller is the device owner: Look for profile owners that it can bind to.
- final List<UserInfo> userInfos = mUserManager.getUsers(/*excludeDying=*/ true);
+ final List<UserInfo> userInfos = mUserManager.getAliveUsers();
for (int i = 0; i < userInfos.size(); i++) {
final int userId = userInfos.get(i).id;
if (userId != callingUserId && canUserBindToDeviceOwnerLocked(userId)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 3cdd482ffa37..7649af4ee911 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -169,7 +169,7 @@ class Owners {
// First, try to read from the legacy file.
final File legacy = getLegacyConfigFile();
- final List<UserInfo> users = mUserManager.getUsers(true);
+ final List<UserInfo> users = mUserManager.getAliveUsers();
if (readLegacyOwnerFileLocked(legacy)) {
if (DEBUG) {
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index 7534c7c40a3d..e978ed4000e0 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/Android.bp
@@ -51,9 +51,9 @@ cc_defaults {
static_libs: [
"libbase",
"libext2_uuid",
- "libdataloader_aidl-cpp",
- "libincremental_aidl-cpp",
- "libincremental_manager_aidl-cpp",
+ "libdataloader_aidl-unstable-cpp",
+ "libincremental_aidl-unstable-cpp",
+ "libincremental_manager_aidl-unstable-cpp",
"libprotobuf-cpp-lite",
"service.incremental.proto",
"libutils",
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 41945a276fde..87ae4d719d11 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -237,6 +237,13 @@ binder::Status BinderIncrementalService::unlink(int32_t storageId, const std::st
return ok();
}
+binder::Status BinderIncrementalService::isFileFullyLoaded(int32_t storageId,
+ const std::string& path,
+ int32_t* _aidl_return) {
+ *_aidl_return = mImpl.isFileFullyLoaded(storageId, path);
+ return ok();
+}
+
binder::Status BinderIncrementalService::getLoadingProgress(int32_t storageId,
float* _aidl_return) {
*_aidl_return = mImpl.getLoadingProgress(storageId);
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 8b40350468ce..8478142b2d95 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -66,6 +66,8 @@ public:
int32_t destStorageId, const std::string& destPath,
int32_t* _aidl_return) final;
binder::Status unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) final;
+ binder::Status isFileFullyLoaded(int32_t storageId, const std::string& path,
+ int32_t* _aidl_return) final;
binder::Status getLoadingProgress(int32_t storageId, float* _aidl_return) final;
binder::Status getMetadataByPath(int32_t storageId, const std::string& path,
std::vector<uint8_t>* _aidl_return) final;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index ba6ae9262aea..447ee552a335 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1603,7 +1603,8 @@ void IncrementalService::extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle
const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId);
if (!writeFd.ok()) {
- LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
+ LOG(ERROR) << "Failed to open write fd for: " << targetLibPath
+ << " errno: " << writeFd.get();
return;
}
@@ -1673,6 +1674,37 @@ bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) {
return mRunning;
}
+int IncrementalService::isFileFullyLoaded(StorageId storage, const std::string& path) const {
+ std::unique_lock l(mLock);
+ const auto ifs = getIfsLocked(storage);
+ if (!ifs) {
+ LOG(ERROR) << "isFileFullyLoaded failed, invalid storageId: " << storage;
+ return -EINVAL;
+ }
+ const auto storageInfo = ifs->storages.find(storage);
+ if (storageInfo == ifs->storages.end()) {
+ LOG(ERROR) << "isFileFullyLoaded failed, no storage: " << storage;
+ return -EINVAL;
+ }
+ l.unlock();
+ return isFileFullyLoadedFromPath(*ifs, path);
+}
+
+int IncrementalService::isFileFullyLoadedFromPath(const IncFsMount& ifs,
+ std::string_view filePath) const {
+ const auto [filledBlocks, totalBlocks] = mIncFs->countFilledBlocks(ifs.control, filePath);
+ if (filledBlocks < 0) {
+ LOG(ERROR) << "isFileFullyLoadedFromPath failed to get filled blocks count for: "
+ << filePath << " errno: " << filledBlocks;
+ return filledBlocks;
+ }
+ if (totalBlocks < filledBlocks) {
+ LOG(ERROR) << "isFileFullyLoadedFromPath failed to get total num of blocks";
+ return -EINVAL;
+ }
+ return totalBlocks - filledBlocks;
+}
+
float IncrementalService::getLoadingProgress(StorageId storage) const {
std::unique_lock l(mLock);
const auto ifs = getIfsLocked(storage);
@@ -1706,8 +1738,8 @@ float IncrementalService::getLoadingProgressFromPath(const IncFsMount& ifs,
}
if (totalBlocks == 0) {
- LOG(ERROR) << "getLoadingProgress failed to get total num of blocks";
- return -EINVAL;
+ // No file in the storage or files are empty; regarded as fully loaded
+ return 1;
}
return (float)filledBlocks / (float)totalBlocks;
}
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index cd6bfedb8a9e..267458d8769c 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -132,6 +132,7 @@ public:
std::string_view newPath);
int unlink(StorageId storage, std::string_view path);
+ int isFileFullyLoaded(StorageId storage, const std::string& path) const;
float getLoadingProgress(StorageId storage) const;
RawMetadata getMetadata(StorageId storage, std::string_view path) const;
@@ -339,6 +340,7 @@ private:
int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode);
binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
+ int isFileFullyLoadedFromPath(const IncFsMount& ifs, std::string_view filePath) const;
float getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const;
void registerAppOpsCallback(const std::string& packageName);
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 1ed46c49c5e1..f6d89c53be32 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -195,8 +195,8 @@ public:
ErrorCode unlink(const Control& control, std::string_view path) const final {
return incfs::unlink(control, path);
}
- base::unique_fd openForSpecialOps(const Control& control, FileId id) const final {
- return base::unique_fd{incfs::openForSpecialOps(control, id).release()};
+ incfs::UniqueFd openForSpecialOps(const Control& control, FileId id) const final {
+ return incfs::openForSpecialOps(control, id);
}
ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final {
return incfs::writeBlocks({blocks.data(), size_t(blocks.size())});
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 82a170470fee..6376d86543f8 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -74,6 +74,7 @@ public:
using Control = incfs::Control;
using FileId = incfs::FileId;
using ErrorCode = incfs::ErrorCode;
+ using UniqueFd = incfs::UniqueFd;
using WaitResult = incfs::WaitResult;
using ExistingMountCallback =
@@ -96,7 +97,7 @@ public:
virtual ErrorCode link(const Control& control, std::string_view from,
std::string_view to) const = 0;
virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
- virtual base::unique_fd openForSpecialOps(const Control& control, FileId id) const = 0;
+ virtual UniqueFd openForSpecialOps(const Control& control, FileId id) const = 0;
virtual ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const = 0;
virtual WaitResult waitForPendingReads(
const Control& control, std::chrono::milliseconds timeout,
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 44cef49a716c..a290a1791481 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -289,7 +289,7 @@ public:
ErrorCode(const Control& control, std::string_view from,
std::string_view to));
MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
- MOCK_CONST_METHOD2(openForSpecialOps, base::unique_fd(const Control& control, FileId id));
+ MOCK_CONST_METHOD2(openForSpecialOps, UniqueFd(const Control& control, FileId id));
MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
MOCK_CONST_METHOD3(waitForPendingReads,
WaitResult(const Control& control, std::chrono::milliseconds timeout,
@@ -304,6 +304,10 @@ public:
ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(1, 2)));
}
+ void countFilledBlocksFullyLoaded() {
+ ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(10000, 10000)));
+ }
+
void countFilledBlocksFails() {
ON_CALL(*this, countFilledBlocks(_, _)).WillByDefault(Return(std::make_pair(-1, -1)));
}
@@ -1069,7 +1073,54 @@ TEST_F(IncrementalServiceTest, testMakeDirectories) {
ASSERT_EQ(res, 0);
}
-TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithNoFile) {
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithNoFile) {
+ mIncFs->countFilledBlocksFails();
+ mFs->hasNoFile();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithFailedRanges) {
+ mIncFs->countFilledBlocksFails();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+ ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccessWithEmptyRanges) {
+ mIncFs->countFilledBlocksEmpty();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+ ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccess) {
+ mIncFs->countFilledBlocksFullyLoaded();
+ mFs->hasFiles();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, {}, {});
+ EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
+ ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+}
+
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithNoFile) {
mIncFs->countFilledBlocksSuccess();
mFs->hasNoFile();
@@ -1077,7 +1128,7 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithNoFile) {
int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew,
{}, {}, {});
- ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+ ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId));
}
TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
@@ -1092,7 +1143,7 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
ASSERT_EQ(-1, mIncrementalService->getLoadingProgress(storageId));
}
-TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithEmptyRanges) {
+TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithEmptyRanges) {
mIncFs->countFilledBlocksEmpty();
mFs->hasFiles();
@@ -1101,7 +1152,7 @@ TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithEmptyRanges) {
IncrementalService::CreateOptions::CreateNew,
{}, {}, {});
EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
- ASSERT_EQ(-EINVAL, mIncrementalService->getLoadingProgress(storageId));
+ ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId));
}
TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 6cd083e11754..f4c6918c0e96 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -67,7 +67,6 @@ import static org.mockito.Mockito.verify;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
import android.app.IActivityManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
@@ -87,6 +86,7 @@ import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.SystemClock;
+import android.provider.DeviceConfig;
import androidx.test.runner.AndroidJUnit4;
@@ -99,6 +99,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoSession;
@@ -106,6 +107,8 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
+import java.util.concurrent.Executor;
+
/**
* Tests for {@link com.android.server.DeviceIdleController}.
*/
@@ -124,8 +127,6 @@ public class DeviceIdleControllerTest {
@Mock
private ConnectivityManager mConnectivityManager;
@Mock
- private ContentResolver mContentResolver;
- @Mock
private IActivityManager mIActivityManager;
@Mock
private LocationManager mLocationManager;
@@ -294,6 +295,7 @@ public class DeviceIdleControllerTest {
mMockingSession = mockitoSession()
.initMocks(this)
.strictness(Strictness.LENIENT)
+ .spyStatic(DeviceConfig.class)
.spyStatic(LocalServices.class)
.startMocking();
spyOn(getContext());
@@ -310,6 +312,14 @@ public class DeviceIdleControllerTest {
.thenReturn(mock(PowerSaveState.class));
doReturn(mock(NetworkPolicyManagerInternal.class))
.when(() -> LocalServices.getService(NetworkPolicyManagerInternal.class));
+ doAnswer((Answer<Void>) invocationOnMock -> null)
+ .when(() -> DeviceConfig.addOnPropertiesChangedListener(
+ anyString(), any(Executor.class),
+ any(DeviceConfig.OnPropertiesChangedListener.class)));
+ doAnswer((Answer<DeviceConfig.Properties>) invocationOnMock
+ -> mock(DeviceConfig.Properties.class))
+ .when(() -> DeviceConfig.getProperties(
+ anyString(), ArgumentMatchers.<String>any()));
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
doNothing().when(mWakeLock).acquire();
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), anyString(), any(), any());
@@ -319,7 +329,6 @@ public class DeviceIdleControllerTest {
mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper());
mAnyMotionDetector = new AnyMotionDetectorForTest();
mInjector = new InjectorForTest(getContext());
- doNothing().when(mContentResolver).registerContentObserver(any(), anyBoolean(), any());
mDeviceIdleController = new DeviceIdleController(getContext(), mInjector);
spyOn(mDeviceIdleController);
@@ -330,8 +339,7 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.setLightEnabledForTest(true);
// Get the same Constants object that mDeviceIdleController got.
- mConstants = mInjector.getConstants(mDeviceIdleController,
- mInjector.getHandler(mDeviceIdleController), mContentResolver);
+ mConstants = mInjector.getConstants(mDeviceIdleController);
}
@After
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 77232dc4644c..0789d680a80c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -780,7 +780,7 @@ public class AlarmManagerServiceTest {
setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 2, alarmPi);
assertEquals(mNowElapsedTest + 2, mTestTimer.getElapsed());
- final SparseArray<ArrayList<AlarmManagerService.Alarm>> restrictedAlarms =
+ final SparseArray<ArrayList<Alarm>> restrictedAlarms =
mService.mPendingBackgroundAlarms;
assertNull(restrictedAlarms.get(TEST_CALLING_UID));
@@ -993,7 +993,7 @@ public class AlarmManagerServiceTest {
@Test
public void alarmCountOnRemoveFromPendingWhileIdle() {
- mService.mPendingIdleUntil = mock(AlarmManagerService.Alarm.class);
+ mService.mPendingIdleUntil = mock(Alarm.class);
final int numAlarms = 15;
final PendingIntent[] pis = new PendingIntent[numAlarms];
for (int i = 0; i < numAlarms; i++) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
new file mode 100644
index 000000000000..9e43b4ab9b5a
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.alarm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class AlarmStoreTest {
+ private static final int TEST_CALLING_UID = 12345;
+ private static final String TEST_CALLING_PACKAGE = "android.alarm.unit.test";
+
+ private AlarmStore mAlarmStore;
+
+ @Before
+ public void setUp() {
+ mAlarmStore = new BatchingAlarmStore(null);
+ }
+
+ private static Alarm createAlarm(long whenElapsed, long windowLength, PendingIntent mockPi,
+ AlarmManager.AlarmClockInfo alarmClock) {
+ return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength, mockPi,
+ alarmClock);
+ }
+
+ private static Alarm createWakeupAlarm(long whenElapsed, long windowLength,
+ PendingIntent mockPi, AlarmManager.AlarmClockInfo alarmClock) {
+ return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength, mockPi,
+ alarmClock);
+ }
+
+ private static Alarm createAlarm(int type, long whenElapsed, long windowLength,
+ PendingIntent mockPi, AlarmManager.AlarmClockInfo alarmClock) {
+ return new Alarm(type, whenElapsed, whenElapsed, windowLength, whenElapsed + windowLength,
+ 0, mockPi, null, null, null, 0, alarmClock, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+ }
+
+ private void addAlarmsToStore(Alarm... alarms) {
+ for (Alarm a : alarms) {
+ mAlarmStore.add(a);
+ }
+ }
+
+ @Test
+ public void add() {
+ final Alarm a1 = createAlarm(1, 0, mock(PendingIntent.class), null);
+ mAlarmStore.add(a1);
+ assertEquals(1, mAlarmStore.size());
+
+ final Alarm a2 = createAlarm(2, 0, mock(PendingIntent.class), null);
+ mAlarmStore.add(a2);
+ assertEquals(2, mAlarmStore.size());
+
+ ArrayList<Alarm> alarmsAdded = mAlarmStore.asList();
+ assertEquals(2, alarmsAdded.size());
+ assertTrue(alarmsAdded.contains(a1) && alarmsAdded.contains(a2));
+ }
+
+ @Test
+ public void remove() {
+ final Alarm a1 = createAlarm(1, 0, mock(PendingIntent.class), null);
+ final Alarm a2 = createAlarm(2, 0, mock(PendingIntent.class), null);
+ final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a1, a2, a5);
+
+ ArrayList<Alarm> removed = mAlarmStore.remove(a -> (a.whenElapsed < 4));
+ assertEquals(2, removed.size());
+ assertEquals(1, mAlarmStore.size());
+ assertTrue(removed.contains(a1) && removed.contains(a2));
+
+ final Alarm a8 = createAlarm(8, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a8, a2, a1);
+
+ removed = mAlarmStore.remove(unused -> false);
+ assertEquals(0, removed.size());
+ assertEquals(4, mAlarmStore.size());
+
+ removed = mAlarmStore.remove(unused -> true);
+ assertEquals(4, removed.size());
+ assertEquals(0, mAlarmStore.size());
+ }
+
+ @Test
+ public void removePendingAlarms() {
+ final Alarm a1_11 = createAlarm(1, 10, mock(PendingIntent.class), null);
+ final Alarm a2_5 = createAlarm(2, 3, mock(PendingIntent.class), null);
+ final Alarm a6_9 = createAlarm(6, 3, mock(PendingIntent.class), null);
+ addAlarmsToStore(a2_5, a6_9, a1_11);
+
+ final ArrayList<Alarm> pendingAt0 = mAlarmStore.removePendingAlarms(0);
+ assertEquals(0, pendingAt0.size());
+ assertEquals(3, mAlarmStore.size());
+
+ final ArrayList<Alarm> pendingAt3 = mAlarmStore.removePendingAlarms(3);
+ assertEquals(2, pendingAt3.size());
+ assertTrue(pendingAt3.contains(a1_11) && pendingAt3.contains(a2_5));
+ assertEquals(1, mAlarmStore.size());
+
+ addAlarmsToStore(a2_5, a1_11);
+ final ArrayList<Alarm> pendingAt7 = mAlarmStore.removePendingAlarms(7);
+ assertEquals(3, pendingAt7.size());
+ assertTrue(pendingAt7.contains(a1_11) && pendingAt7.contains(a2_5) && pendingAt7.contains(
+ a6_9));
+ assertEquals(0, mAlarmStore.size());
+ }
+
+ @Test
+ public void getNextWakeupDeliveryTime() {
+ final Alarm a1_10 = createAlarm(1, 9, mock(PendingIntent.class), null);
+ final Alarm a3_8_wakeup = createWakeupAlarm(3, 5, mock(PendingIntent.class), null);
+ final Alarm a6_wakeup = createWakeupAlarm(6, 0, mock(PendingIntent.class), null);
+ final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a5, a6_wakeup, a3_8_wakeup, a1_10);
+
+ // The wakeup alarms are [6] and [3, 8], hence 6 is the latest time till when we can
+ // defer delivering any wakeup alarm.
+ assertTrue(mAlarmStore.getNextWakeupDeliveryTime() <= 6);
+
+ mAlarmStore.remove(a -> a.wakeup);
+ assertEquals(2, mAlarmStore.size());
+ // No wakeup alarms left.
+ assertEquals(0, mAlarmStore.getNextWakeupDeliveryTime());
+
+ mAlarmStore.remove(unused -> true);
+ assertEquals(0, mAlarmStore.getNextWakeupDeliveryTime());
+ }
+
+ @Test
+ public void getNextDeliveryTime() {
+ final Alarm a1_10 = createAlarm(1, 9, mock(PendingIntent.class), null);
+ final Alarm a3_8_wakeup = createWakeupAlarm(3, 5, mock(PendingIntent.class), null);
+ final Alarm a6_wakeup = createWakeupAlarm(6, 0, mock(PendingIntent.class), null);
+ final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a5, a6_wakeup, a3_8_wakeup, a1_10);
+
+ assertTrue(mAlarmStore.getNextDeliveryTime() <= 5);
+
+ mAlarmStore.remove(unused -> true);
+ assertEquals(0, mAlarmStore.getNextWakeupDeliveryTime());
+ }
+
+ @Test
+ public void recalculateAlarmDeliveries() {
+ final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
+ final Alarm a8 = createAlarm(8, 0, mock(PendingIntent.class), null);
+ final Alarm a10 = createAlarm(10, 0, mock(PendingIntent.class), null);
+ addAlarmsToStore(a8, a10, a5);
+
+ assertEquals(5, mAlarmStore.getNextDeliveryTime());
+
+ mAlarmStore.recalculateAlarmDeliveries(a -> {
+ a.whenElapsed += 3;
+ a.maxWhenElapsed = a.whenElapsed;
+ return true;
+ });
+ assertEquals(8, mAlarmStore.getNextDeliveryTime());
+
+ mAlarmStore.recalculateAlarmDeliveries(a -> {
+ a.whenElapsed = 20 - a.whenElapsed;
+ a.maxWhenElapsed = a.whenElapsed;
+ return true;
+ });
+ assertEquals(7, mAlarmStore.getNextDeliveryTime());
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
index 12e953a4d4e8..6465739f6822 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
@@ -27,7 +27,6 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ObjectUtils;
-import com.android.server.alarm.AlarmManagerService.Alarm;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
index fdcadf3e3088..80ad0a838bbb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -33,6 +33,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
import static com.android.server.location.LocationUtils.createLocation;
+import static com.android.server.location.listeners.RemoteListenerRegistration.IN_PROCESS_EXECUTOR;
import static com.google.common.truth.Truth.assertThat;
@@ -85,7 +86,6 @@ import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.location.listeners.ListenerRegistration;
import com.android.server.location.util.FakeUserInfoHelper;
import com.android.server.location.util.TestInjector;
@@ -274,60 +274,55 @@ public class LocationProviderManagerTest {
@Test
public void testGetLastLocation_Fine() {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
}
@Test
public void testGetLastLocation_Coarse() {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- Location coarse = mManager.getLastLocation(request, IDENTITY, PERMISSION_COARSE);
+ Location coarse = mManager.getLastLocation(IDENTITY, PERMISSION_COARSE, false);
assertThat(coarse).isNotEqualTo(loc);
assertThat(coarse).isNearby(loc, 5000);
}
@Test
public void testGetLastLocation_Bypass() {
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
- LocationRequest bypassRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
- false).setLocationSettingsIgnored(true);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isNull();
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
mProvider.setProviderAllowed(false);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
mProvider.setProviderAllowed(true);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
- assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
loc);
}
@@ -337,13 +332,12 @@ public class LocationProviderManagerTest {
mockProvider.setAllowed(true);
mManager.setMockProvider(mockProvider);
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
Location loc = createLocation(NAME, mRandom);
mockProvider.setProviderLocation(loc);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
mManager.setMockProvider(null);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
}
@Test
@@ -351,13 +345,12 @@ public class LocationProviderManagerTest {
Location loc1 = createLocation(NAME, mRandom);
mManager.injectLastLocation(loc1, CURRENT_USER);
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc1);
Location loc2 = createLocation(NAME, mRandom);
mManager.injectLastLocation(loc2, CURRENT_USER);
- assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+ assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc1);
}
@Test
@@ -381,9 +374,7 @@ public class LocationProviderManagerTest {
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
- LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
- 0, false);
- assertThat(mPassive.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mPassive.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
}
@Test
@@ -484,7 +475,7 @@ public class LocationProviderManagerTest {
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
- ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ IN_PROCESS_EXECUTOR.execute(() -> {
try {
blocker.await();
} catch (InterruptedException e) {
@@ -622,7 +613,7 @@ public class LocationProviderManagerTest {
PERMISSION_FINE, listener);
CountDownLatch blocker = new CountDownLatch(1);
- ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ IN_PROCESS_EXECUTOR.execute(() -> {
try {
blocker.await();
} catch (InterruptedException e) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
index 1ef12555a83a..69a9f4415fe7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/listeners/ListenerMultiplexerTest.java
@@ -16,6 +16,8 @@
package com.android.server.location.listeners;
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -27,8 +29,6 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertThrows;
-import android.location.util.identity.CallerIdentity;
-import android.os.Process;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -324,10 +324,8 @@ public class ListenerMultiplexerTest {
boolean mActive = true;
protected TestListenerRegistration(Integer integer,
- Consumer<TestListenerRegistration> consumer,
- boolean outOfProcess) {
- super(integer, CallerIdentity.forTest(Process.myUid(),
- Process.myPid() + (outOfProcess ? 1 : 0), "test", "test"), consumer);
+ Consumer<TestListenerRegistration> consumer) {
+ super(DIRECT_EXECUTOR, integer, consumer);
}
}
@@ -345,7 +343,7 @@ public class ListenerMultiplexerTest {
}
public void addListener(Integer request, Consumer<TestListenerRegistration> consumer) {
- addRegistration(consumer, new TestListenerRegistration(request, consumer, true));
+ addRegistration(consumer, new TestListenerRegistration(request, consumer));
}
public void removeListener(Consumer<TestListenerRegistration> consumer) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
index 42ba842f8434..f896d75ecb3b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
@@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -27,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.view.Display;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -69,13 +71,28 @@ class MockWindowMagnificationConnection {
if (displayId != TEST_DISPLAY) {
throw new IllegalArgumentException("only support default display :" + displayId);
}
- computeMirrorWindowFrame(invocation.getArgument(1), invocation.getArgument(2));
-
+ computeMirrorWindowFrame(invocation.getArgument(2), invocation.getArgument(3));
+ final RemoteCallback callback = invocation.getArgument(4);
+ if (callback != null) {
+ callback.sendResult(null);
+ }
mIMirrorWindowCallback.onWindowMagnifierBoundsChanged(TEST_DISPLAY,
mMirrorWindowFrame);
return null;
}).when(mConnection).enableWindowMagnification(anyInt(),
- anyFloat(), anyFloat(), anyFloat());
+ anyFloat(), anyFloat(), anyFloat(), nullable(RemoteCallback.class));
+
+ doAnswer((invocation) -> {
+ final int displayId = invocation.getArgument(0);
+ if (displayId != TEST_DISPLAY) {
+ throw new IllegalArgumentException("only support default display :" + displayId);
+ }
+ final RemoteCallback callback = invocation.getArgument(1);
+ if (callback != null) {
+ callback.sendResult(null);
+ }
+ return null;
+ }).when(mConnection).disableWindowMagnification(anyInt(), nullable(RemoteCallback.class));
}
private void computeMirrorWindowFrame(float centerX, float centerY) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
index 36b304b4884c..9ef65d9cce09 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
@@ -19,6 +19,7 @@ package com.android.server.accessibility.magnification;
import static org.mockito.Mockito.verify;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.provider.Settings;
import android.view.Display;
@@ -43,18 +44,22 @@ public class WindowMagnificationConnectionWrapperTest {
private IWindowMagnificationConnection mConnection;
@Mock
private IWindowMagnificationConnectionCallback mCallback;
+ @Mock
+ private RemoteCallback.OnResultListener mOnResultListener;
+ private RemoteCallback mRemoteCallback;
private WindowMagnificationConnectionWrapper mConnectionWrapper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mConnectionWrapper = new WindowMagnificationConnectionWrapper(mConnection);
+ mRemoteCallback = new RemoteCallback(mOnResultListener);
}
@Test
public void enableWindowMagnification() throws RemoteException {
- mConnectionWrapper.enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f);
- verify(mConnection).enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f);
+ mConnectionWrapper.enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f, mRemoteCallback);
+ verify(mConnection).enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f, mRemoteCallback);
}
@Test
@@ -65,8 +70,8 @@ public class WindowMagnificationConnectionWrapperTest {
@Test
public void disableWindowMagnification() throws RemoteException {
- mConnectionWrapper.disableWindowMagnification(TEST_DISPLAY);
- verify(mConnection).disableWindowMagnification(TEST_DISPLAY);
+ mConnectionWrapper.disableWindowMagnification(TEST_DISPLAY, mRemoteCallback);
+ verify(mConnection).disableWindowMagnification(TEST_DISPLAY, mRemoteCallback);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index bec9f26672f4..a10e0ba5020c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -81,7 +81,7 @@ public class WindowMagnificationGestureHandlerTest {
@After
public void tearDown() {
- mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, true);
+ mWindowMagnificationManager.disableWindowMagnification(DISPLAY_0, true);
}
@Test
@@ -225,7 +225,7 @@ public class WindowMagnificationGestureHandlerTest {
}
break;
case STATE_SHOW_MAGNIFIER: {
- mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, false);
+ mWindowMagnificationManager.disableWindowMagnification(DISPLAY_0, false);
}
break;
case STATE_TWO_FINGERS_DOWN: {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 70e6a340816a..dcb1262ad2de 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -68,8 +68,12 @@ public class WindowMagnificationManagerTest {
private static final int CURRENT_USER_ID = UserHandle.USER_CURRENT;
private MockWindowMagnificationConnection mMockConnection;
- @Mock private Context mContext;
- @Mock private StatusBarManagerInternal mMockStatusBarManagerInternal;
+ @Mock
+ private Context mContext;
+ @Mock
+ private StatusBarManagerInternal mMockStatusBarManagerInternal;
+ @Mock
+ private Runnable mEndCallback;
private MockContentResolver mResolver;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -84,7 +88,7 @@ public class WindowMagnificationManagerTest {
when(mContext.getContentResolver()).thenReturn(mResolver);
doAnswer((InvocationOnMock invocation) -> {
- final boolean connect = (Boolean) invocation.getArguments()[0];
+ final boolean connect = (Boolean) invocation.getArguments()[0];
mWindowMagnificationManager.setConnection(
connect ? mMockConnection.getConnection() : null);
return null;
@@ -158,32 +162,53 @@ public class WindowMagnificationManagerTest {
}
@Test
- public void enable_TestDisplay_enableWindowMagnification() throws RemoteException {
+ public void enable_hasConnection_enableWindowMagnification() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2f, 200f, 300f);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f);
verify(mMockConnection.getConnection()).enableWindowMagnification(TEST_DISPLAY, 2f,
- 200f, 300f);
+ 200f, 300f, null);
}
@Test
- public void disable_testDisplay_disableWindowMagnification() throws RemoteException {
+ public void enableWithCallback_hasConnection_enableWindowMagnification()
+ throws RemoteException {
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f,
+ mEndCallback);
+
+ verify(mEndCallback).run();
+ }
+
+ @Test
+ public void disable_hasConnectionAndEnabled_disableWindowMagnification()
+ throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
- mWindowMagnificationManager.disableWindowMagnifier(TEST_DISPLAY, false);
+ mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
- verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY);
+ verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY, null);
}
@Test
- public void isWindowMagnifierEnabled_returnExpectedValue() {
+ public void disableWithCallback_hasConnectionAndEnabled_disableWindowMagnification() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false, mEndCallback);
+
+ verify(mEndCallback).run();
+ }
+
+ @Test
+ public void isWindowMagnifierEnabled_hasConnectionAndEnabled_returnExpectedValue() {
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, NaN, NaN);
assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
}
@@ -198,7 +223,7 @@ public class WindowMagnificationManagerTest {
@Test
public void persistScale_setValue_expectedValueInProvider() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2.0f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.0f, NaN, NaN);
mWindowMagnificationManager.setScale(TEST_DISPLAY, 2.5f);
mWindowMagnificationManager.persistScale(TEST_DISPLAY);
@@ -211,7 +236,7 @@ public class WindowMagnificationManagerTest {
@Test
public void scaleSetterGetter_enabledOnTestDisplay_expectedValue() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2.0f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.0f, NaN, NaN);
mWindowMagnificationManager.setScale(TEST_DISPLAY, 2.5f);
@@ -221,7 +246,7 @@ public class WindowMagnificationManagerTest {
@Test
public void scaleSetterGetter_scaleIsOutOfRang_getNormalizeValue() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2.5f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.5f, NaN, NaN);
mWindowMagnificationManager.setScale(TEST_DISPLAY, 10.0f);
@@ -230,16 +255,17 @@ public class WindowMagnificationManagerTest {
}
@Test
- public void moveWindowMagnifier() throws RemoteException {
+ public void moveWindowMagnifier_enabled_invokeConnectionMethod() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 2f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, NaN, NaN);
- mWindowMagnificationManager.moveWindowMagnifier(TEST_DISPLAY, 200, 300);
+ mWindowMagnificationManager.moveWindowMagnification(TEST_DISPLAY, 200, 300);
verify(mMockConnection.getConnection()).moveWindowMagnifier(TEST_DISPLAY, 200, 300);
}
@Test
- public void showMagnificationButton() throws RemoteException {
+ public void showMagnificationButton_hasConnection_invokeConnectionMethod()
+ throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.showMagnificationButton(TEST_DISPLAY,
@@ -252,9 +278,9 @@ public class WindowMagnificationManagerTest {
}
@Test
- public void pointersInWindow_returnCorrectValue() throws RemoteException {
+ public void pointersInWindow_magnifierEnabled_returnCorrectValue() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3.0f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, NaN, NaN);
mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(TEST_DISPLAY,
new Rect(0, 0, 500, 500));
PointF[] pointersLocation = new PointF[2];
@@ -268,7 +294,7 @@ public class WindowMagnificationManagerTest {
@Test
public void binderDied_windowMagnifierIsEnabled_resetState() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
mMockConnection.getDeathRecipient().binderDied();
@@ -280,11 +306,11 @@ public class WindowMagnificationManagerTest {
requestConnectionToNull_disableAllMagnifiersAndRequestWindowMagnificationConnection()
throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnifier(TEST_DISPLAY, 3f, NaN, NaN);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
assertTrue(mWindowMagnificationManager.requestConnection(false));
- verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY);
+ verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY, null);
verify(mMockStatusBarManagerInternal).requestWindowMagnificationConnection(false);
}
@@ -306,21 +332,24 @@ public class WindowMagnificationManagerTest {
@Test
public void requestConnection_registerAndUnregisterBroadcastReceiver() {
assertTrue(mWindowMagnificationManager.requestConnection(true));
- verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+ verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
assertTrue(mWindowMagnificationManager.requestConnection(false));
verify(mContext).unregisterReceiver(any(BroadcastReceiver.class));
}
@Test
- public void onReceiveScreenOff_removeMagnificationButtonAndDisableWindowMagnification()
+ public void onScreenOff_windowMagnifierIsEnabled_removeButtonAndDisableWindowMagnification()
throws RemoteException {
mWindowMagnificationManager.requestConnection(true);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2.5f, NaN, NaN);
+
mWindowMagnificationManager.mScreenStateReceiver.onReceive(mContext,
new Intent(Intent.ACTION_SCREEN_OFF));
verify(mMockConnection.getConnection()).removeMagnificationButton(TEST_DISPLAY);
- verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY);
+ verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY, null);
+ assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
}
private MotionEvent generatePointersDownEvent(PointF[] pointersLocation) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index b306ff091267..431cc27a6635 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -16,7 +16,6 @@
package com.android.server.devicepolicy;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -236,7 +235,7 @@ public class MockSystemServices {
}
mUserInfos.add(uh);
when(userManager.getUsers()).thenReturn(mUserInfos);
- when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos);
+ when(userManager.getAliveUsers()).thenReturn(mUserInfos);
when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true);
when(userManager.getProfileParent(anyInt())).thenAnswer(
invocation -> {
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index b1f3871274ac..73dda0736d2f 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -28,18 +29,23 @@ import static org.mockito.Mockito.when;
import android.app.PropertyInvalidatedCache;
import android.content.Context;
+import android.graphics.Insets;
+import android.graphics.Rect;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.Curve;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
+import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.input.InputManagerInternal;
import android.os.Handler;
import android.os.IBinder;
import android.view.Display;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -282,6 +288,68 @@ public class DisplayManagerServiceTest {
}
/**
+ * Tests that there should be a display change notification to WindowManager to update its own
+ * internal state for things like display cutout when nonOverrideDisplayInfo is changed.
+ */
+ @Test
+ public void testShouldNotifyChangeWhenNonOverrideDisplayInfoChanged() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+ // Add the FakeDisplayDevice
+ FakeDisplayDevice displayDevice = new FakeDisplayDevice();
+ DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
+ displayDeviceInfo.width = 100;
+ displayDeviceInfo.height = 200;
+ final Rect zeroRect = new Rect();
+ displayDeviceInfo.displayCutout = new DisplayCutout(
+ Insets.of(0, 10, 0, 0),
+ zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect);
+ displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY;
+ displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
+ displayManager.handleDisplayDeviceAdded(displayDevice);
+
+ // Find the display id of the added FakeDisplayDevice
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+ final int[] displayIds = bs.getDisplayIds();
+ assertTrue(displayIds.length > 0);
+ int displayId = Display.INVALID_DISPLAY;
+ for (int i = 0; i < displayIds.length; i++) {
+ DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayIds[i]);
+ if (displayDeviceInfo.equals(ddi)) {
+ displayId = displayIds[i];
+ break;
+ }
+ }
+ assertFalse(displayId == Display.INVALID_DISPLAY);
+
+ // Setup override DisplayInfo
+ DisplayInfo overrideInfo = bs.getDisplayInfo(displayId);
+ displayManager.setDisplayInfoOverrideFromWindowManagerInternal(displayId, overrideInfo);
+
+ Handler handler = displayManager.getDisplayHandler();
+ handler.runWithScissors(() -> {
+ }, 0 /* now */);
+
+ // register display listener callback
+ FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
+ bs.registerCallback(callback);
+
+ // Simulate DisplayDevice change
+ DisplayDeviceInfo displayDeviceInfo2 = new DisplayDeviceInfo();
+ displayDeviceInfo2.copyFrom(displayDeviceInfo);
+ displayDeviceInfo2.displayCutout = null;
+ displayDevice.setDisplayDeviceInfo(displayDeviceInfo2);
+ displayManager.handleDisplayDeviceChanged(displayDevice);
+
+ handler.runWithScissors(() -> {
+ }, 0 /* now */);
+ assertTrue(callback.mCalled);
+ }
+
+ /**
* Tests that we get a Runtime exception when we cannot initialize the default display.
*/
@Test
@@ -512,4 +580,42 @@ public class DisplayManagerServiceTest {
// flush the handler
handler.runWithScissors(() -> {}, 0 /* now */);
}
+
+ private class FakeDisplayManagerCallback extends IDisplayManagerCallback.Stub {
+ int mDisplayId;
+ boolean mCalled = false;
+
+ FakeDisplayManagerCallback(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ @Override
+ public void onDisplayEvent(int displayId, int event) {
+ if (displayId == mDisplayId && event == DisplayManagerGlobal.EVENT_DISPLAY_CHANGED) {
+ mCalled = true;
+ }
+ }
+ }
+
+ private class FakeDisplayDevice extends DisplayDevice {
+ private DisplayDeviceInfo mDisplayDeviceInfo;
+
+ FakeDisplayDevice() {
+ super(null, null, "");
+ }
+
+ public void setDisplayDeviceInfo(DisplayDeviceInfo displayDeviceInfo) {
+ mDisplayDeviceInfo = displayDeviceInfo;
+ }
+
+ @Override
+ public boolean hasStableUniqueId() {
+ return false;
+ }
+
+ @Override
+ public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+ return mDisplayDeviceInfo;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index ef2365e6da3e..0c35797b38ea 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.hdmi;
+import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -693,6 +694,84 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Test
+ public void sendVolumeKeyEvent_toTv_activeSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(false);
+ mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress,
+ "HdmiCecLocalDevicePlaybackTest");
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_TV);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
+ public void sendVolumeKeyEvent_toAudio_activeSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(true);
+ mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress,
+ "HdmiCecLocalDevicePlaybackTest");
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
+ public void sendVolumeKeyEvent_toTv_inactiveSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(false);
+ mHdmiControlService.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest");
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_TV);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
+ public void sendVolumeKeyEvent_toAudio_inactiveSource() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mHdmiControlService.setSystemAudioActivated(true);
+ mHdmiControlService.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest");
+
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+ mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+ HdmiCecMessage pressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage released = HdmiCecMessageBuilder.buildUserControlReleased(
+ mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse();
+ assertThat(mNativeWrapper.getResultMessages()).containsAllOf(pressed, released);
+ }
+
+ @Test
public void handleSetStreamPath_broadcastsActiveSource() {
HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
mPlaybackPhysicalAddress);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 775e88750cef..31cf59ee7bde 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -63,7 +63,7 @@ import java.util.ArrayList;
@RunWith(JUnit4.class)
public class HdmiControlServiceTest {
- private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDevice {
+ private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDeviceSource {
private boolean mCanGoToStandby;
private boolean mIsStandby;
@@ -405,6 +405,83 @@ public class HdmiControlServiceTest {
assertThat(callback2.mVolumeControlEnabled).isTrue();
}
+ @Test
+ public void setActiveSource_localDevice_playback() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(mMyPlaybackDevice.mAddress, physicalAddress,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ mMyPlaybackDevice.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ physicalAddress);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isTrue();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_localDevice_audio() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(mMyAudioSystemDevice.mAddress, physicalAddress,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ mMyAudioSystemDevice.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ physicalAddress);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isTrue();
+ }
+
+ @Test
+ public void setActiveSource_remoteDevice() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_TV, 0x0000, "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_TV);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x000);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_nonCecDevice() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_INVALID, 0x1234,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_INVALID);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x1234);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_unknown() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_INVALID,
+ Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_INVALID);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ Constants.INVALID_PHYSICAL_ADDRESS);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
private static class VolumeControlFeatureCallback extends
IHdmiCecVolumeControlFeatureListener.Stub {
boolean mCallbackReceived = false;
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index b2512d3ed8ca..eec7d125d219 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -379,7 +379,7 @@ public class AppsFilterTest {
}
@Test
- public void testForceQueryable_DoesntFilter() throws Exception {
+ public void testForceQueryable_SystemDoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
@@ -387,7 +387,8 @@ public class AppsFilterTest {
appsFilter.onSystemReady();
PackageSetting target = simulateAddPackage(appsFilter,
- pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID);
+ pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID,
+ setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
PackageSetting calling = simulateAddPackage(appsFilter,
pkg("com.some.other.package"), DUMMY_CALLING_APPID);
@@ -395,6 +396,24 @@ public class AppsFilterTest {
SYSTEM_USER));
}
+
+ @Test
+ public void testForceQueryable_NonSystemFilters() throws Exception {
+ final AppsFilter appsFilter =
+ new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ mMockExecutor);
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+
+ PackageSetting target = simulateAddPackage(appsFilter,
+ pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID);
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package"), DUMMY_CALLING_APPID);
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+ SYSTEM_USER));
+ }
+
@Test
public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java
new file mode 100644
index 000000000000..7049efa1cc2f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+/**
+ * A test support class used for tracking a piece of state in test objects like fakes and mocks.
+ * State can optionally be initialized using {@link #init}, which sets the value to an initial
+ * value, but is not treated as a change. Calls to {@link #set} are tracked and can be checked for
+ * during tests. The change-tracking can be cleared by calling {@link #commitLatest}, which puts the
+ * object into an unchanged state and sets the initial value to the latest value passed to
+ * {@link #set}.
+ */
+public class TestState<T> {
+ private T mInitialValue;
+ private final ArrayList<T> mValues = new ArrayList<>(5);
+
+ /** Sets the initial value for the state. */
+ public void init(T value) {
+ mValues.clear();
+ mInitialValue = value;
+ }
+
+ /** Sets the latest value for the state. */
+ public void set(T value) {
+ mValues.add(value);
+ }
+
+ /** Returns {@code true} if {@link #set} has been called. */
+ public boolean hasBeenSet() {
+ return mValues.size() > 0;
+ }
+
+ /** Fails if {@link #set} has been called. */
+ public void assertHasNotBeenSet() {
+ assertFalse(hasBeenSet());
+ }
+
+ /** Fails if {@link #set} has not been called. */
+ public void assertHasBeenSet() {
+ assertTrue(hasBeenSet());
+ }
+
+ /**
+ * Clears tracked changes and re-initializes using the latest set value as the initial value.
+ */
+ public void commitLatest() {
+ if (hasBeenSet()) {
+ mInitialValue = mValues.get(mValues.size() - 1);
+ mValues.clear();
+ }
+ }
+
+ /** Asserts the latest value passed to {@link #set} equals {@code expected}. */
+ public void assertLatestEquals(T expected) {
+ assertEquals(expected, getLatest());
+ }
+
+ /** Asserts the number of times {@link #set} has been called. */
+ public void assertChangeCount(int expectedCount) {
+ assertEquals(expectedCount, mValues.size());
+ }
+
+ /**
+ * Returns the latest value passed to {@link #set}. If {@link #set} hasn't been called then the
+ * initial value is returned.
+ */
+ public T getLatest() {
+ if (hasBeenSet()) {
+ return mValues.get(mValues.size() - 1);
+ }
+ return mInitialValue;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 2bee5e5e7295..1cdf19319209 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -54,7 +54,6 @@ import org.junit.Test;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collections;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -994,55 +993,6 @@ public class TimeZoneDetectorStrategyImplTest {
}
}
- /** Some piece of state that tests want to track. */
- private static class TestState<T> {
- private T mInitialValue;
- private LinkedList<T> mValues = new LinkedList<>();
-
- void init(T value) {
- mValues.clear();
- mInitialValue = value;
- }
-
- void set(T value) {
- mValues.addFirst(value);
- }
-
- boolean hasBeenSet() {
- return mValues.size() > 0;
- }
-
- void assertHasNotBeenSet() {
- assertFalse(hasBeenSet());
- }
-
- void assertHasBeenSet() {
- assertTrue(hasBeenSet());
- }
-
- void commitLatest() {
- if (hasBeenSet()) {
- mInitialValue = mValues.getLast();
- mValues.clear();
- }
- }
-
- void assertLatestEquals(T expected) {
- assertEquals(expected, getLatest());
- }
-
- void assertChangeCount(int expectedCount) {
- assertEquals(expectedCount, mValues.size());
- }
-
- public T getLatest() {
- if (hasBeenSet()) {
- return mValues.getFirst();
- }
- return mInitialValue;
- }
- }
-
/**
* A "fluent" class allows reuse of code in tests: initialization, simulation and verification
* logic.
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 7c7b1a296673..2aeab209162a 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -139,10 +139,13 @@ public class AppStandbyControllerTests {
private AppStandbyController mController;
private CountDownLatch mStateChangedLatch = new CountDownLatch(1);
+ private String mLatchPkgName = null;
private AppIdleStateChangeListener mListener = new AppIdleStateChangeListener() {
@Override
public void onAppIdleStateChanged(String packageName, int userId,
boolean idle, int bucket, int reason) {
+ // Ignore events not related to mLatchPkgName, if set.
+ if (mLatchPkgName != null && !mLatchPkgName.equals(packageName)) return;
mStateChangedLatch.countDown();
}
};
@@ -374,6 +377,7 @@ public class AppStandbyControllerTests {
mInjector.mElapsedRealtime, false));
controller.addListener(mListener);
+ mLatchPkgName = null;
return controller;
}
@@ -1377,7 +1381,7 @@ public class AppStandbyControllerTests {
@Test
public void testUnexemptedSyncScheduled() throws Exception {
- mStateChangedLatch = new CountDownLatch(1);
+ rearmLatch(PACKAGE_1);
mController.addListener(mListener);
assertEquals("Test package did not start in the Never bucket", STANDBY_BUCKET_NEVER,
getStandbyBucket(mController, PACKAGE_1));
@@ -1389,7 +1393,7 @@ public class AppStandbyControllerTests {
setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM);
- mStateChangedLatch = new CountDownLatch(1);
+ rearmLatch(PACKAGE_1);
mController.postReportSyncScheduled(PACKAGE_1, USER_ID, false);
mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS);
assertEquals("Unexempted sync scheduled should not elevate a non Never bucket",
@@ -1400,7 +1404,7 @@ public class AppStandbyControllerTests {
public void testExemptedSyncScheduled() throws Exception {
setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM);
mInjector.mDeviceIdleMode = true;
- mStateChangedLatch = new CountDownLatch(1);
+ rearmLatch(PACKAGE_1);
mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true);
mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS);
assertEquals("Exempted sync scheduled in doze should set bucket to working set",
@@ -1408,7 +1412,7 @@ public class AppStandbyControllerTests {
setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM);
mInjector.mDeviceIdleMode = false;
- mStateChangedLatch = new CountDownLatch(1);
+ rearmLatch(PACKAGE_1);
mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true);
mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS);
assertEquals("Exempted sync scheduled while not in doze should set bucket to active",
@@ -1558,10 +1562,19 @@ public class AppStandbyControllerTests {
}
private void setAndAssertBucket(String pkg, int user, int bucket, int reason) throws Exception {
- mStateChangedLatch = new CountDownLatch(1);
+ rearmLatch(pkg);
mController.setAppStandbyBucket(pkg, user, bucket, reason);
mStateChangedLatch.await(100, TimeUnit.MILLISECONDS);
assertEquals("Failed to set package bucket", bucket,
getStandbyBucket(mController, PACKAGE_1));
}
+
+ private void rearmLatch(String pkgName) {
+ mLatchPkgName = pkgName;
+ mStateChangedLatch = new CountDownLatch(1);
+ }
+
+ private void rearmLatch() {
+ rearmLatch(null);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 99433a6603c9..d7e431f3bb51 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -978,6 +978,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
assertFalse(services.isSameUser(service, 0));
assertTrue(services.isSameUser(service, 10));
+ assertTrue(services.isSameUser(service, UserHandle.USER_ALL));
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index ab4dc476ff20..5796e848ff6e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -103,7 +103,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
}
when(mUm.getUsers()).thenReturn(users);
- when(mUm.getUsers(anyBoolean())).thenReturn(users);
+ when(mUm.getAliveUsers()).thenReturn(users);
IntArray profileIds = new IntArray();
profileIds.add(0);
profileIds.add(11);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9319bea497fb..86447192a441 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5058,7 +5058,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
10, 10, r.getKey(), actionIndex, action, notificationVisibility,
generatedByAssistant);
verify(mAssistants).notifyAssistantActionClicked(
- eq(r.getSbn()), eq(actionIndex), eq(action), eq(generatedByAssistant));
+ eq(r.getSbn()), eq(action), eq(generatedByAssistant));
assertEquals(1, mNotificationRecordLogger.numCalls());
assertEquals(
@@ -5082,7 +5082,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
10, 10, r.getKey(), actionIndex, action, notificationVisibility,
generatedByAssistant);
verify(mAssistants).notifyAssistantActionClicked(
- eq(r.getSbn()), eq(actionIndex), eq(action), eq(generatedByAssistant));
+ eq(r.getSbn()), eq(action), eq(generatedByAssistant));
assertEquals(1, mNotificationRecordLogger.numCalls());
assertEquals(
@@ -6948,4 +6948,63 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1,
mService.getNotificationRecordCount());
}
+
+ @Test
+ public void testIsVisibleToListener_notEnabled() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 10;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(assistant.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(false);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
+
+ assertFalse(mService.isVisibleToListener(sbn, info));
+ }
+
+ @Test
+ public void testIsVisibleToListener_noAssistant() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 10;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null);
+
+ assertTrue(mService.isVisibleToListener(sbn, info));
+ }
+
+ @Test
+ public void testIsVisibleToListener_assistant_differentUser() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 0;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(assistant.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
+
+ assertFalse(mService.isVisibleToListener(sbn, info));
+ }
+
+ @Test
+ public void testIsVisibleToListener_assistant_sameUser() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 10;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(assistant.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
+
+ assertTrue(mService.isVisibleToListener(sbn, info));
+ }
+
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 1eb45d587d33..cf07183a007d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -67,7 +67,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
final TaskDisplayArea taskDisplayAreas =
mRootWindowContainer.getDefaultDisplay().getDefaultTaskDisplayArea();
final Task stack =
- new StackBuilder(mRootWindowContainer).setOnTop(!ON_TOP).build();
+ new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build();
final Task prevFocusedStack = taskDisplayAreas.getFocusedStack();
stack.moveToFront("moveStackToFront");
@@ -90,7 +90,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
final Task pinnedStack = mRootWindowContainer.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task pinnedTask = new TaskBuilder(mAtm.mStackSupervisor)
- .setStack(pinnedStack).build();
+ .setParentTask(pinnedStack).build();
new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
.setTask(pinnedTask).build();
pinnedStack.moveToFront("movePinnedStackToFront");
@@ -144,7 +144,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
doReturn(false).when(display).shouldDestroyContentOnRemove();
// Put home stack on the display.
- final Task homeStack = new StackBuilder(mRootWindowContainer)
+ final Task homeStack = new TaskBuilder(mSupervisor)
.setDisplay(display).setActivityType(ACTIVITY_TYPE_HOME).build();
// Put a finishing standard activity which will be reparented.
@@ -163,7 +163,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
final Task fullscreenStack = display.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task fullscreenTask = new TaskBuilder(mAtm.mStackSupervisor)
- .setStack(fullscreenStack).build();
+ .setParentTask(fullscreenStack).build();
new ActivityBuilder(mAtm).setTask(fullscreenTask).build();
return fullscreenStack;
}
@@ -175,12 +175,11 @@ public class ActivityDisplayTests extends WindowTestsBase {
public void testTopRunningActivity() {
final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
final KeyguardController keyguard = mSupervisor.getKeyguardController();
- final Task stack = new StackBuilder(mRootWindowContainer).build();
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = stack.getTopNonFinishingActivity();
// Create empty stack on top.
- final Task emptyStack =
- new StackBuilder(mRootWindowContainer).setCreateActivity(false).build();
+ final Task emptyStack = new TaskBuilder(mSupervisor).build();
// Make sure the top running activity is not affected when keyguard is not locked.
assertTopRunningActivity(activity, display);
@@ -322,10 +321,10 @@ public class ActivityDisplayTests extends WindowTestsBase {
ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task stack4 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task task1 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack1).build();
- final Task task2 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack2).build();
- final Task task3 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack3).build();
- final Task task4 = new TaskBuilder(mAtm.mStackSupervisor).setStack(stack4).build();
+ final Task task1 = new TaskBuilder(mAtm.mStackSupervisor).setParentTask(stack1).build();
+ final Task task2 = new TaskBuilder(mAtm.mStackSupervisor).setParentTask(stack2).build();
+ final Task task3 = new TaskBuilder(mAtm.mStackSupervisor).setParentTask(stack3).build();
+ final Task task4 = new TaskBuilder(mAtm.mStackSupervisor).setParentTask(stack4).build();
// Reordering stacks while removing stacks.
doAnswer(invocation -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index eb78172cd562..e860f2508983 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -341,9 +341,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
public void testConsecutiveLaunchOnDifferentDisplay() {
onActivityLaunched(mTopActivity);
- final Task stack = new StackBuilder(mRootWindowContainer)
+ final Task stack = new TaskBuilder(mSupervisor)
.setDisplay(addNewDisplayContentAt(DisplayContent.POSITION_BOTTOM))
- .setCreateActivity(false)
.build();
final ActivityRecord activityOnNewDisplay = new ActivityBuilder(mAtm)
.setStack(stack)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 59f0a7987bda..09375db01888 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -131,7 +131,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Before
public void setUp() throws Exception {
- mStack = new StackBuilder(mRootWindowContainer).build();
+ mStack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
mTask = mStack.getBottomMostTask();
mActivity = mTask.getTopNonFinishingActivity();
@@ -172,7 +172,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testNoCleanupMovingActivityInSameStack() {
- final Task newTask = new TaskBuilder(mAtm.mStackSupervisor).setStack(mStack).build();
+ final Task newTask = new TaskBuilder(mAtm.mStackSupervisor).setParentTask(mStack).build();
mActivity.reparent(newTask, 0, null /*reason*/);
verify(mStack, times(0)).cleanUpActivityReferences(any());
}
@@ -262,7 +262,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
// Pending options should be cleared for only ActivityRecord that was applied
- Task task2 = new TaskBuilder(mAtm.mStackSupervisor).setStack(mStack).build();
+ Task task2 = new TaskBuilder(mAtm.mStackSupervisor).setParentTask(mStack).build();
activity2 = new ActivityBuilder(mAtm).setTask(task2).build();
activity2.updateOptionsLocked(activityOptions);
mActivity.updateOptionsLocked(activityOptions);
@@ -415,12 +415,12 @@ public class ActivityRecordTests extends WindowTestsBase {
public void ignoreRequestedOrientationInFreeformWindows() {
mStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
final Rect stableRect = new Rect();
- mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
+ mStack.mDisplayContent.getStableRect(stableRect);
// Carve out non-decor insets from stableRect
final Rect insets = new Rect();
- final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
- final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
+ final DisplayInfo displayInfo = mStack.mDisplayContent.getDisplayInfo();
+ final DisplayPolicy policy = mStack.mDisplayContent.getDisplayPolicy();
policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.displayCutout, insets);
policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
@@ -454,12 +454,12 @@ public class ActivityRecordTests extends WindowTestsBase {
public void ignoreRequestedOrientationInSplitWindows() {
mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final Rect stableRect = new Rect();
- mStack.getDisplay().getStableRect(stableRect);
+ mStack.mDisplayContent.getStableRect(stableRect);
// Carve out non-decor insets from stableRect
final Rect insets = new Rect();
- final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
- final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
+ final DisplayInfo displayInfo = mStack.mDisplayContent.getDisplayInfo();
+ final DisplayPolicy policy = mStack.mDisplayContent.getDisplayPolicy();
policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.displayCutout, insets);
policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
@@ -548,7 +548,7 @@ public class ActivityRecordTests extends WindowTestsBase {
.build();
mActivity.setState(Task.ActivityState.STOPPED, "Testing");
- final Task stack = new StackBuilder(mRootWindowContainer).build();
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
try {
doReturn(false).when(stack).isTranslucent(any());
assertFalse(mStack.shouldBeVisible(null /* starting */));
@@ -756,14 +756,14 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testFinishActivityIfPossible_adjustStackOrder() {
// Prepare the stacks with order (top to bottom): mStack, stack1, stack2.
- final Task stack1 = new StackBuilder(mRootWindowContainer).build();
+ final Task stack1 = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
mStack.moveToFront("test");
// The stack2 is needed here for moving back to simulate the
// {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so
// {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible
// stacks. Then when mActivity is finishing, its stack will be invisible (no running
// activities in the stack) that is the key condition to verify.
- final Task stack2 = new StackBuilder(mRootWindowContainer).build();
+ final Task stack2 = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
stack2.moveToBack("test", stack2.getBottomMostTask());
assertTrue(mStack.isTopStackInDisplayArea());
@@ -844,7 +844,7 @@ public class ActivityRecordTests extends WindowTestsBase {
FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
assertEquals(PAUSING, mActivity.getState());
verify(mActivity).setVisibility(eq(false));
- verify(mActivity.getDisplay().mDisplayContent)
+ verify(mActivity.mDisplayContent)
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
}
@@ -888,9 +888,9 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishIfPossible("test", false /* oomAdj */);
verify(mActivity).setVisibility(eq(false));
- verify(mActivity.getDisplay().mDisplayContent)
+ verify(mActivity.mDisplayContent)
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
- verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
+ verify(mActivity.mDisplayContent, never()).executeAppTransition();
}
/**
@@ -904,9 +904,9 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishIfPossible("test", false /* oomAdj */);
verify(mActivity, atLeast(1)).setVisibility(eq(false));
- verify(mActivity.getDisplay().mDisplayContent)
+ verify(mActivity.mDisplayContent)
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
- verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
+ verify(mActivity.mDisplayContent).executeAppTransition();
}
/**
@@ -922,7 +922,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishIfPossible("test", false /* oomAdj */);
- verify(mActivity.getDisplay().mDisplayContent, never())
+ verify(mActivity.mDisplayContent, never())
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
}
@@ -973,7 +973,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Simulates that {@code currentTop} starts an existing activity from background (so its
// state is stopped) and the starting flow just goes to place it at top.
- final Task nextStack = new StackBuilder(mRootWindowContainer).build();
+ final Task nextStack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
nextTop.setState(STOPPED, "test");
@@ -1095,7 +1095,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Add another stack to become focused and make the activity there visible. This way it
// simulates finishing in non-focused stack in split-screen.
- final Task stack = new StackBuilder(mRootWindowContainer).build();
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord focusedActivity = stack.getTopMostActivity();
focusedActivity.nowVisible = true;
focusedActivity.mVisibleRequested = true;
@@ -1166,7 +1166,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Finish the second activity
secondActivity.finishing = true;
secondActivity.completeFinishing("test");
- verify(secondActivity.getDisplay()).ensureActivitiesVisible(null /* starting */,
+ verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
true /* notifyClients */);
@@ -1174,7 +1174,7 @@ public class ActivityRecordTests extends WindowTestsBase {
firstActivity.finishing = true;
firstActivity.mVisibleRequested = true;
firstActivity.completeFinishing("test");
- verify(firstActivity.getDisplay(), times(2)).ensureActivitiesVisible(null /* starting */,
+ verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
true /* notifyClients */);
}
@@ -1581,7 +1581,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Create a new task with custom config to reparent the activity to.
final Task newTask =
- new TaskBuilder(mSupervisor).setStack(initialTask.getRootTask()).build();
+ new TaskBuilder(mSupervisor).setParentTask(initialTask.getRootTask()).build();
final Configuration newConfig = newTask.getConfiguration();
newConfig.densityDpi += 100;
newTask.onRequestedOverrideConfigurationChanged(newConfig);
@@ -1613,7 +1613,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Create a new task with custom config to reparent the second activity to.
final Task newTask =
- new TaskBuilder(mSupervisor).setStack(initialTask.getRootTask()).build();
+ new TaskBuilder(mSupervisor).setParentTask(initialTask.getRootTask()).build();
final Configuration newConfig = newTask.getConfiguration();
newConfig.densityDpi += 100;
newTask.onRequestedOverrideConfigurationChanged(newConfig);
@@ -1750,7 +1750,7 @@ public class ActivityRecordTests extends WindowTestsBase {
}
final Task stack = display.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
return new ActivityBuilder(mAtm).setTask(task).setUseProcess(process).build();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 27e2d1370fae..f9ad49bb5034 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -115,8 +115,8 @@ public class ActivityStackSupervisorTests extends WindowTestsBase {
public void testHandleNonResizableTaskOnSecondaryDisplay() {
// Create an unresizable task on secondary display.
final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
- final Task stack = new StackBuilder(mRootWindowContainer)
- .setDisplay(newDisplay).build();
+ final Task stack = new TaskBuilder(mSupervisor)
+ .setDisplay(newDisplay).setCreateActivity(true).build();
final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity();
final Task task = unresizableActivity.getTask();
unresizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index e2948a724acd..4951658bbd78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -100,7 +100,7 @@ public class ActivityStackTests extends WindowTestsBase {
mStack = mDefaultTaskDisplayArea.createStack(WINDOWING_MODE_UNDEFINED,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
spyOn(mStack);
- mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
+ mTask = new TaskBuilder(mSupervisor).setParentTask(mStack).build();
}
@Test
@@ -330,7 +330,7 @@ public class ActivityStackTests extends WindowTestsBase {
targetActivity);
final ComponentName alias = new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME,
aliasActivity);
- final Task task = new TaskBuilder(mAtm.mStackSupervisor).setStack(mStack).build();
+ final Task task = new TaskBuilder(mAtm.mStackSupervisor).setParentTask(mStack).build();
task.origActivity = alias;
task.realActivity = target;
new ActivityBuilder(mAtm).setComponent(target).setTask(task).setTargetActivity(
@@ -995,7 +995,7 @@ public class ActivityStackTests extends WindowTestsBase {
mDefaultTaskDisplayArea.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, task,
false /* includingParents */);
} else {
- task = new StackBuilder(mRootWindowContainer)
+ task = new TaskBuilder(mSupervisor)
.setTaskDisplayArea(taskDisplayArea)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
@@ -1202,19 +1202,22 @@ public class ActivityStackTests extends WindowTestsBase {
@Test
public void testShouldSleepActivities() {
// When focused activity and keyguard is going away, we should not sleep regardless
- // of the display state
+ // of the display state, but keyguard-going-away should only take effects on default
+ // display since there is no keyguard on secondary displays (yet).
verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/,
- true /* displaySleeping */, false /* expected*/);
+ true /* displaySleeping */, true /* isDefaultDisplay */, false /* expected */);
+ verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/,
+ true /* displaySleeping */, false /* isDefaultDisplay */, true /* expected */);
// When not the focused stack, defer to display sleeping state.
verifyShouldSleepActivities(false /* focusedStack */, true /*keyguardGoingAway*/,
- true /* displaySleeping */, true /* expected*/);
+ true /* displaySleeping */, true /* isDefaultDisplay */, true /* expected */);
// If keyguard is going away, defer to the display sleeping state.
verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
- true /* displaySleeping */, true /* expected*/);
+ true /* displaySleeping */, true /* isDefaultDisplay */, true /* expected */);
verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
- false /* displaySleeping */, false /* expected*/);
+ false /* displaySleeping */, true /* isDefaultDisplay */, false /* expected */);
}
@Test
@@ -1423,11 +1426,13 @@ public class ActivityStackTests extends WindowTestsBase {
}
private void verifyShouldSleepActivities(boolean focusedStack,
- boolean keyguardGoingAway, boolean displaySleeping, boolean expected) {
+ boolean keyguardGoingAway, boolean displaySleeping, boolean isDefaultDisplay,
+ boolean expected) {
final DisplayContent display = mock(DisplayContent.class);
final KeyguardController keyguardController = mSupervisor.getKeyguardController();
+ display.isDefaultDisplay = isDefaultDisplay;
- doReturn(display).when(mStack).getDisplay();
+ mStack.mDisplayContent = display;
doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway();
doReturn(displaySleeping).when(display).isSleeping();
doReturn(focusedStack).when(mStack).isFocusedStackOnDisplay();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index e5c9ecc7676d..076047b35604 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -217,7 +217,10 @@ public class ActivityStarterTests extends WindowTestsBase {
// Create source token
final ActivityBuilder builder = new ActivityBuilder(service).setTask(
- new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build());
+ new TaskBuilder(service.mStackSupervisor)
+ .setVoiceSession(voiceSession)
+ .setCreateParentTask(true)
+ .build());
if (aInfo != null) {
aInfo.applicationInfo = new ApplicationInfo();
@@ -706,7 +709,9 @@ public class ActivityStarterTests extends WindowTestsBase {
@Test
public void testBringTaskToFrontWhenFocusedStackIsFinising() {
// Put 2 tasks in the same stack (simulate the behavior of home stack).
+ final Task rootTask = new TaskBuilder(mSupervisor).build();
final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setStack(rootTask)
.setCreateTask(true).build();
new ActivityBuilder(mAtm)
.setStack(activity.getRootTask())
@@ -792,7 +797,7 @@ public class ActivityStarterTests extends WindowTestsBase {
// Create another activity on top of the secondary display.
final Task topStack = secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
+ final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build();
new ActivityBuilder(mAtm).setTask(topTask).build();
// Start activity with the same intent as {@code singleTaskActivity} on secondary display.
@@ -851,7 +856,7 @@ public class ActivityStarterTests extends WindowTestsBase {
DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
final Task task = new TaskBuilder(mSupervisor)
.setComponent(componentName)
- .setStack(stack)
+ .setParentTask(stack)
.build();
return new ActivityBuilder(mAtm)
.setComponent(componentName)
@@ -890,7 +895,7 @@ public class ActivityStarterTests extends WindowTestsBase {
.execute();
// Ensure the activity is moved to secondary display.
- assertEquals(secondaryDisplay, topActivity.getDisplay());
+ assertEquals(secondaryDisplay, topActivity.mDisplayContent);
}
/**
@@ -987,7 +992,7 @@ public class ActivityStarterTests extends WindowTestsBase {
final ActivityStarter starter = prepareStarter(0 /* flags */);
starter.mStartActivity = new ActivityBuilder(mAtm).build();
final Task task = new TaskBuilder(mAtm.mStackSupervisor)
- .setStack(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
+ .setParentTask(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
.setUserId(10)
.build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 567610018fc1..031165727207 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -73,7 +73,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
/** Verify that activity is finished correctly upon request. */
@Test
public void testActivityFinish() {
- final Task stack = new StackBuilder(mRootWindowContainer).build();
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
assertTrue("Activity must be finished", mAtm.finishActivity(activity.appToken,
0 /* resultCode */, null /* resultData */,
@@ -87,7 +87,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
@Test
public void testOnPictureInPictureRequested() throws RemoteException {
- final Task stack = new StackBuilder(mRootWindowContainer).build();
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
final ClientLifecycleManager mockLifecycleManager = mock(ClientLifecycleManager.class);
doReturn(mockLifecycleManager).when(mAtm).getLifecycleManager();
@@ -106,7 +106,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
@Test(expected = IllegalStateException.class)
public void testOnPictureInPictureRequested_cannotEnterPip() throws RemoteException {
- final Task stack = new StackBuilder(mRootWindowContainer).build();
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
doReturn(false).when(activity).inPinnedWindowingMode();
@@ -120,7 +120,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
@Test(expected = IllegalStateException.class)
public void testOnPictureInPictureRequested_alreadyInPIPMode() throws RemoteException {
- final Task stack = new StackBuilder(mRootWindowContainer).build();
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
doReturn(true).when(activity).inPinnedWindowingMode();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index f8baf8497069..7f904265de15 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -28,6 +28,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.FLAG_PRIVATE;
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
@@ -95,6 +96,7 @@ import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.view.DisplayCutout;
+import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IDisplayWindowRotationCallback;
import android.view.IDisplayWindowRotationController;
@@ -847,17 +849,17 @@ public class DisplayContentTests extends WindowTestsBase {
dc.getDisplayRotation().setFixedToUserRotation(
IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
- final Task stack =
- new StackBuilder(mWm.mAtmService.mRootWindowContainer)
- .setDisplay(dc)
- .build();
+ final Task stack = new TaskBuilder(mSupervisor)
+ .setDisplay(dc)
+ .setCreateActivity(true)
+ .build();
doReturn(true).when(stack).isVisible();
- final Task freeformStack =
- new StackBuilder(mWm.mAtmService.mRootWindowContainer)
- .setDisplay(dc)
- .setWindowingMode(WINDOWING_MODE_FREEFORM)
- .build();
+ final Task freeformStack = new TaskBuilder(mSupervisor)
+ .setDisplay(dc)
+ .setCreateActivity(true)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM)
+ .build();
doReturn(true).when(freeformStack).isVisible();
freeformStack.getTopChild().setBounds(100, 100, 300, 400);
@@ -879,8 +881,8 @@ public class DisplayContentTests extends WindowTestsBase {
IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
final int newOrientation = getRotatedOrientation(dc);
- final Task stack = new StackBuilder(mWm.mAtmService.mRootWindowContainer)
- .setDisplay(dc).build();
+ final Task stack = new TaskBuilder(mSupervisor)
+ .setDisplay(dc).setCreateActivity(true).build();
final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
activity.setRequestedOrientation(newOrientation);
@@ -898,8 +900,8 @@ public class DisplayContentTests extends WindowTestsBase {
IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
final int newOrientation = getRotatedOrientation(dc);
- final Task stack = new StackBuilder(mWm.mAtmService.mRootWindowContainer)
- .setDisplay(dc).build();
+ final Task stack = new TaskBuilder(mSupervisor)
+ .setDisplay(dc).setCreateActivity(true).build();
final ActivityRecord activity = stack.getTopMostTask().getTopNonFinishingActivity();
activity.setRequestedOrientation(newOrientation);
@@ -1209,8 +1211,8 @@ public class DisplayContentTests extends WindowTestsBase {
verify(t, never()).setPosition(any(), eq(0), eq(0));
// Launch another activity before the transition is finished.
- final ActivityRecord app2 = new StackBuilder(mWm.mRoot)
- .setDisplay(mDisplayContent).build().getTopMostActivity();
+ final ActivityRecord app2 = new TaskBuilder(mSupervisor)
+ .setDisplay(mDisplayContent).setCreateActivity(true).build().getTopMostActivity();
app2.setVisible(false);
mDisplayContent.mOpeningApps.add(app2);
app2.setRequestedOrientation(newOrientation);
@@ -1508,7 +1510,7 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testSetWindowingModeAtomicallyUpdatesWindoingModeAndDisplayWindowingMode() {
final DisplayContent dc = createNewDisplay();
- final Task stack = new StackBuilder(mWm.mAtmService.mRootWindowContainer)
+ final Task stack = new TaskBuilder(mSupervisor)
.setDisplay(dc)
.build();
doAnswer(invocation -> {
@@ -1522,6 +1524,28 @@ public class DisplayContentTests extends WindowTestsBase {
dc.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
+ @Test
+ public void testForceDesktopMode() {
+ mWm.mForceDesktopModeOnExternalDisplays = true;
+ // Not applicable for default display
+ assertFalse(mDefaultDisplay.forceDesktopMode());
+
+ // Not applicable for private secondary display.
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.copyFrom(mDisplayInfo);
+ displayInfo.flags = FLAG_PRIVATE;
+ final DisplayContent privateDc = createNewDisplay(displayInfo);
+ assertFalse(privateDc.forceDesktopMode());
+
+ // Applicable for public secondary display.
+ final DisplayContent publicDc = createNewDisplay();
+ assertTrue(publicDc.forceDesktopMode());
+
+ // Make sure forceDesktopMode() is false when the force config is disabled.
+ mWm.mForceDesktopModeOnExternalDisplays = false;
+ assertFalse(publicDc.forceDesktopMode());
+ }
+
private boolean isOptionsPanelAtRight(int displayId) {
return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 2d834ac57f51..94e40413f9f8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -26,8 +26,6 @@ import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
-import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -36,6 +34,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -371,6 +370,24 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
}
@Test
+ public void layoutWindowLw_insetParentFrameByIme() {
+ final InsetsState state =
+ mDisplayContent.getInsetsStateController().getRawInsetsState();
+ state.getSource(InsetsState.ITYPE_IME).setVisible(true);
+ state.getSource(InsetsState.ITYPE_IME).setFrame(
+ 0, DISPLAY_HEIGHT - IME_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+ mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
+ mWindow.mBehindIme = true;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, IME_HEIGHT);
+ }
+
+ @Test
public void layoutWindowLw_fitDisplayCutout() {
addDisplayCutout();
@@ -475,7 +492,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
addWindow(mWindow);
@@ -497,9 +513,9 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow)
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+ mWindow.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).setVisible(false);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -519,9 +535,9 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow)
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+ mWindow.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).setVisible(false);
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
addWindow(mWindow);
@@ -585,7 +601,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
addWindow(mWindow);
@@ -626,7 +641,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index b50530ed3059..b77d21c0f711 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -27,11 +27,9 @@ import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
@@ -39,7 +37,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
@@ -47,7 +44,6 @@ import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -235,18 +231,6 @@ public class DisplayPolicyTests extends WindowTestsBase {
assertEquals(mAppWindow, policy.getTopFullscreenOpaqueWindow());
}
- @Test
- public void testShouldShowToastWhenScreenLocked() {
- final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
- final WindowState activity = createApplicationWindow();
- final WindowState toast = createToastWindow();
-
- policy.adjustWindowParamsLw(toast, toast.mAttrs, 0 /* callingPid */, 0 /* callingUid */);
-
- assertTrue(policy.canToastShowWhenLocked(0 /* callingUid */));
- assertNotEquals(0, toast.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED);
- }
-
@Test(expected = RuntimeException.class)
public void testMainAppWindowDisallowFitSystemWindowTypes() {
final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
@@ -257,16 +241,6 @@ public class DisplayPolicyTests extends WindowTestsBase {
0 /* callingUid */);
}
- private WindowState createToastWindow() {
- final WindowState win = createWindow(null, TYPE_TOAST, "Toast");
- final WindowManager.LayoutParams attrs = win.mAttrs;
- attrs.width = WRAP_CONTENT;
- attrs.height = WRAP_CONTENT;
- attrs.flags = FLAG_KEEP_SCREEN_ON | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE;
- attrs.format = PixelFormat.TRANSLUCENT;
- return win;
- }
-
private WindowState createApplicationWindow() {
final WindowState win = createWindow(null, TYPE_APPLICATION, "Application");
final WindowManager.LayoutParams attrs = win.mAttrs;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index b4e1c375993d..af8cb02a86fe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -62,7 +62,7 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
static final int STATUS_BAR_HEIGHT = 10;
static final int NAV_BAR_HEIGHT = 15;
static final int DISPLAY_CUTOUT_HEIGHT = 8;
- static final int INPUT_METHOD_WINDOW_TOP = 585;
+ static final int IME_HEIGHT = 415;
DisplayPolicy mDisplayPolicy;
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 18a2d1337d4b..d701a9df7cb8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -116,7 +116,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase {
Task stack = mTestDisplay.getDefaultTaskDisplayArea()
.createStack(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true);
- mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT).setStack(stack)
+ mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT).setParentTask(stack)
.build();
mTestTask.mUserId = TEST_USER_ID;
mTestTask.mLastNonFullscreenBounds = TEST_BOUNDS;
@@ -342,7 +342,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase {
final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor)
.setComponent(ALTERNATIVE_COMPONENT)
.setUserId(TEST_USER_ID)
- .setStack(stack)
+ .setParentTask(stack)
.build();
anotherTaskOfTheSameUser.setWindowingMode(WINDOWING_MODE_FREEFORM);
anotherTaskOfTheSameUser.setBounds(200, 300, 400, 500);
@@ -354,7 +354,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase {
final Task anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor)
.setComponent(TEST_COMPONENT)
.setUserId(ALTERNATIVE_USER_ID)
- .setStack(stack)
+ .setParentTask(stack)
.build();
anotherTaskOfDifferentUser.setWindowingMode(WINDOWING_MODE_FREEFORM);
anotherTaskOfDifferentUser.setBounds(300, 400, 500, 600);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 54c7f271e81b..253fbae4579b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -28,6 +28,8 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -331,10 +333,10 @@ public class RecentTasksTest extends WindowTestsBase {
// other task
Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
- .setStack(mTaskContainer.getRootHomeTask()).build();
+ .setParentTask(mTaskContainer.getRootHomeTask()).build();
Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
- .setStack(mStack).build();
+ .setParentTask(mStack).build();
mRecentTasks.add(task1);
mRecentTasks.add(task2);
assertThat(mCallbacksRecorder.mAdded).hasSize(2);
@@ -350,7 +352,7 @@ public class RecentTasksTest extends WindowTestsBase {
// and we want to ensure that a new task will match a restored task
Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
- .setStack(mStack)
+ .setParentTask(mStack)
.build();
setTaskActivityType(task1, ACTIVITY_TYPE_UNDEFINED);
assertThat(task1.getActivityType()).isEqualTo(ACTIVITY_TYPE_UNDEFINED);
@@ -359,7 +361,7 @@ public class RecentTasksTest extends WindowTestsBase {
Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
- .setStack(mStack)
+ .setParentTask(mStack)
.build();
assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType());
mRecentTasks.add(task2);
@@ -374,7 +376,7 @@ public class RecentTasksTest extends WindowTestsBase {
public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() {
Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
- .setStack(mStack)
+ .setParentTask(mStack)
.setUserId(TEST_USER_0_ID)
.build();
setTaskActivityType(task1, ACTIVITY_TYPE_UNDEFINED);
@@ -384,7 +386,7 @@ public class RecentTasksTest extends WindowTestsBase {
Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
- .setStack(mStack)
+ .setParentTask(mStack)
.setUserId(TEST_USER_1_ID)
.build();
assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType());
@@ -399,7 +401,7 @@ public class RecentTasksTest extends WindowTestsBase {
public void testAddTaskCompatibleWindowingMode_expectRemove() {
Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
- .setStack(mStack)
+ .setParentTask(mStack)
.build();
setTaskWindowingMode(task1, WINDOWING_MODE_UNDEFINED);
assertEquals(WINDOWING_MODE_UNDEFINED, task1.getWindowingMode());
@@ -408,7 +410,7 @@ public class RecentTasksTest extends WindowTestsBase {
Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
- .setStack(mStack)
+ .setParentTask(mStack)
.build();
setTaskWindowingMode(task2, WINDOWING_MODE_FULLSCREEN);
assertEquals(WINDOWING_MODE_FULLSCREEN, task2.getWindowingMode());
@@ -425,7 +427,7 @@ public class RecentTasksTest extends WindowTestsBase {
public void testAddTaskIncompatibleWindowingMode_expectNoRemove() {
Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
- .setStack(mStack)
+ .setParentTask(mStack)
.build();
setTaskWindowingMode(task1, WINDOWING_MODE_FULLSCREEN);
assertEquals(WINDOWING_MODE_FULLSCREEN, task1.getWindowingMode());
@@ -433,7 +435,7 @@ public class RecentTasksTest extends WindowTestsBase {
Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
- .setStack(mStack)
+ .setParentTask(mStack)
.build();
setTaskWindowingMode(task2, WINDOWING_MODE_PINNED);
assertEquals(WINDOWING_MODE_PINNED, task2.getWindowingMode());
@@ -447,6 +449,31 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
+ public void testRemoveAffinityTask() {
+ // Add task to recents
+ final String taskAffinity = "affinity";
+ final int uid = 10123;
+ final Task task1 = createTaskBuilder(".Task1").setParentTask(mStack).build();
+ task1.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ mRecentTasks.add(task1);
+
+ // Add another task to recents, and make sure the previous task was removed.
+ final Task task2 = createTaskBuilder(".Task2").setParentTask(mStack).build();
+ task2.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ mRecentTasks.add(task2);
+ assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
+
+ // Add another single-instance task to recents, and make sure no task is removed.
+ final Task task3 = createTaskBuilder(".Task3").setParentTask(mStack).build();
+ task3.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid,
+ LAUNCH_SINGLE_INSTANCE);
+ mRecentTasks.add(task3);
+ assertEquals(2, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
+ }
+
+ @Test
public void testAddTasksHomeClearUntrackedTasks_expectFinish() {
// There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK |
// FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed
@@ -470,7 +497,7 @@ public class RecentTasksTest extends WindowTestsBase {
// tasks because their intents are identical.
mRecentTasks.add(task1);
// Go home to trigger the removal of untracked tasks.
- mRecentTasks.add(createTaskBuilder(".Home").setStack(mTaskContainer.getRootHomeTask())
+ mRecentTasks.add(createTaskBuilder(".Home").setParentTask(mTaskContainer.getRootHomeTask())
.build());
// The task was added into recents again so it is not hidden and shouldn't be removed.
@@ -856,10 +883,10 @@ public class RecentTasksTest extends WindowTestsBase {
// Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all
// the tasks belong in stacks above the home stack
- mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task1").setStack(aboveHomeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task2").setStack(aboveHomeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task3").setStack(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task3").setParentTask(aboveHomeStack).build());
assertNoTasksTrimmed();
}
@@ -877,11 +904,11 @@ public class RecentTasksTest extends WindowTestsBase {
// Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
// the home stack is trimmed once a new task is added
final Task behindHomeTask = createTaskBuilder(".Task1")
- .setStack(behindHomeStack)
+ .setParentTask(behindHomeStack)
.build();
mRecentTasks.add(behindHomeTask);
- mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task2").setStack(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build());
assertTrimmed(behindHomeTask);
}
@@ -897,10 +924,10 @@ public class RecentTasksTest extends WindowTestsBase {
// Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
// removed
- mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task1").setStack(otherDisplayStack).build());
- mRecentTasks.add(createTaskBuilder(".Task2").setStack(otherDisplayStack).build());
- mRecentTasks.add(createTaskBuilder(".HomeTask2").setStack(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(otherDisplayStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayStack).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeStack).build());
assertNoTasksTrimmed();
}
@@ -1187,7 +1214,7 @@ public class RecentTasksTest extends WindowTestsBase {
private TaskBuilder createTaskBuilder(String packageName, String className) {
return new TaskBuilder(mAtm.mStackSupervisor)
.setComponent(new ComponentName(packageName, className))
- .setStack(mStack)
+ .setParentTask(mStack)
.setUserId(TEST_USER_0_ID);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index b89d16807a6e..901ed36254ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -195,8 +195,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
public void testApplySleepTokens() {
final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
final KeyguardController keyguard = mSupervisor.getKeyguardController();
- final Task stack = new StackBuilder(mRootWindowContainer)
- .setCreateActivity(false)
+ final Task stack = new TaskBuilder(mSupervisor)
.setDisplay(display)
.setOnTop(false)
.build();
@@ -384,7 +383,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
final Task primaryStack = mRootWindowContainer.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final Task task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(primaryStack).build();
final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build();
// Find a launch stack for the top activity in split-screen primary, while requesting
@@ -404,14 +403,17 @@ public class RootActivityContainerTests extends WindowTestsBase {
@Test
public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
// Create stack/task on default display.
- final Task targetStack = new StackBuilder(mRootWindowContainer)
+ final Task targetStack = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
.setOnTop(false)
.build();
final Task targetTask = targetStack.getBottomMostTask();
// Create Recents on top of the display.
- final Task stack = new StackBuilder(mRootWindowContainer).setActivityType(
- ACTIVITY_TYPE_RECENTS).build();
+ final Task stack = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
+ .setActivityType(ACTIVITY_TYPE_RECENTS)
+ .build();
final String reason = "findTaskToMoveToFront";
mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
@@ -431,14 +433,14 @@ public class RootActivityContainerTests extends WindowTestsBase {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task targetStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final Task targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+ final Task targetTask = new TaskBuilder(mSupervisor).setParentTask(targetStack).build();
// Create Recents on secondary display.
final TestDisplayContent secondDisplay = addNewDisplayContentAt(
DisplayContent.POSITION_TOP);
final Task stack = secondDisplay.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */);
- final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
new ActivityBuilder(mAtm).setTask(task).build();
final String reason = "findTaskToMoveToFront";
@@ -458,7 +460,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
- final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
taskDisplayArea.positionChildAt(POSITION_BOTTOM, targetStack, false /*includingParents*/);
@@ -514,7 +516,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
DisplayContent.POSITION_TOP);
final Task stack = secondDisplay.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
new ActivityBuilder(mAtm).setTask(task).build();
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
@@ -538,7 +540,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
- final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
activity.setState(ActivityState.RESUMED, "test");
@@ -558,7 +560,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
- final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
activity.setState(ActivityState.RESUMED, "test");
taskDisplayArea.positionChildAt(POSITION_BOTTOM, targetStack, false /*includingParents*/);
@@ -884,7 +886,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
// Create a root task with an activity on secondary display.
final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mAtm, 300,
600).build();
- final Task task = new StackBuilder(mRootWindowContainer)
+ final Task task = new TaskBuilder(mSupervisor)
.setDisplay(secondaryDisplay).build();
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -915,24 +917,6 @@ public class RootActivityContainerTests extends WindowTestsBase {
assertEquals(taskDisplayArea.getTopStack(), taskDisplayArea.getRootHomeTask());
}
- @Test
- public void testResumeFocusedStackOnSleepingDisplay() {
- // Create an activity on secondary display.
- final TestDisplayContent secondDisplay = addNewDisplayContentAt(
- DisplayContent.POSITION_TOP);
- final Task stack = secondDisplay.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setStack(stack).build();
- spyOn(activity);
- spyOn(stack);
-
- // Cannot resumed activities on secondary display if the display should sleep.
- doReturn(true).when(secondDisplay).shouldSleep();
- mRootWindowContainer.resumeFocusedStacksTopActivities();
- verify(stack, never()).resumeTopActivityUncheckedLocked(any(), any());
- verify(activity, never()).makeActiveIfNeeded(any());
- }
-
/**
* Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
* info for test cases.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 191c33c61aca..3053fe6ec55f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -174,7 +174,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
@Test
public void testForceStopPackage() {
- final Task task = new StackBuilder(mWm.mRoot).build();
+ final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = task.getTopMostActivity();
final WindowProcessController wpc = activity.app;
final ActivityRecord[] activities = {
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index 341509310e26..8a5b13c0bdce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -62,8 +62,7 @@ public class RunningTasksTest extends WindowTestsBase {
final int numStacks = 2;
for (int stackIndex = 0; stackIndex < numStacks; stackIndex++) {
- final Task stack = new StackBuilder(mRootWindowContainer)
- .setCreateActivity(false)
+ final Task stack = new TaskBuilder(mSupervisor)
.setDisplay(display)
.setOnTop(false)
.build();
@@ -104,8 +103,7 @@ public class RunningTasksTest extends WindowTestsBase {
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
final int numTasks = 10;
for (int i = 0; i < numTasks; i++) {
- final Task stack = new StackBuilder(mRootWindowContainer)
- .setCreateActivity(false)
+ final Task stack = new TaskBuilder(mSupervisor)
.setDisplay(display)
.setOnTop(true)
.build();
@@ -135,7 +133,7 @@ public class RunningTasksTest extends WindowTestsBase {
final Task task = new TaskBuilder(mAtm.mStackSupervisor)
.setComponent(new ComponentName(mContext.getPackageName(), className))
.setTaskId(taskId)
- .setStack(stack)
+ .setParentTask(stack)
.build();
task.lastActiveTime = lastActiveTime;
final ActivityRecord activity = new ActivityBuilder(mAtm)
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 982e469cba92..29081d389225 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -35,7 +35,9 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -70,7 +72,7 @@ public class SizeCompatTests extends WindowTestsBase {
private ActivityRecord mActivity;
private void setUpApp(DisplayContent display) {
- mStack = new StackBuilder(mRootWindowContainer).setDisplay(display).build();
+ mStack = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true).build();
mTask = mStack.getBottomMostTask();
mActivity = mTask.getTopNonFinishingActivity();
}
@@ -90,7 +92,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
- resizeDisplay(mStack.getDisplay(), 600, 1200);
+ resizeDisplay(mStack.mDisplayContent, 600, 1200);
// The visible activity should recompute configuration according to the last parent bounds.
mAtm.restartActivityProcessIfVisible(mActivity.appToken);
@@ -216,22 +218,50 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect origBounds = new Rect(mActivity.getBounds());
final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
+ final DisplayContent display = mActivity.mDisplayContent;
// Change the size of current display.
- resizeDisplay(mStack.getDisplay(), 1000, 2000);
-
+ resizeDisplay(display, 1000, 2000);
+ // The bounds should be [100, 0 - 1100, 2500].
assertEquals(origBounds.width(), currentBounds.width());
assertEquals(origBounds.height(), currentBounds.height());
assertScaled();
+ // The scale is 2000/2500=0.8. The horizontal centered offset is (1000-(1000*0.8))/2=100.
+ final float scale = (float) display.mBaseDisplayHeight / currentBounds.height();
+ final int offsetX = (int) (display.mBaseDisplayWidth - (origBounds.width() * scale)) / 2;
+ assertEquals(offsetX, currentBounds.left);
+
// The position of configuration bounds should be the same as compat bounds.
assertEquals(mActivity.getBounds().left, currentBounds.left);
assertEquals(mActivity.getBounds().top, currentBounds.top);
// Change display size to a different orientation
- resizeDisplay(mStack.getDisplay(), 2000, 1000);
+ resizeDisplay(display, 2000, 1000);
+ // The bounds should be [800, 0 - 1800, 2500].
assertEquals(origBounds.width(), currentBounds.width());
assertEquals(origBounds.height(), currentBounds.height());
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, display.getConfiguration().orientation);
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);
+
+ // The previous resize operation doesn't consider the rotation change after size changed.
+ // These setups apply the requested orientation to rotation as real case that the top fixed
+ // portrait activity will determine the display rotation.
+ final DisplayRotation displayRotation = display.getDisplayRotation();
+ doCallRealMethod().when(displayRotation).updateRotationUnchecked(anyBoolean());
+ // Skip unrelated layout procedures.
+ mAtm.deferWindowLayout();
+ display.reconfigureDisplayLocked();
+ displayRotation.updateOrientation(display.getOrientation(), true /* forceUpdate */);
+ display.sendNewConfiguration();
+
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, display.getConfiguration().orientation);
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);
+ // The size should still be in portrait [100, 0 - 1100, 2500] = 1000x2500.
+ assertEquals(origBounds.width(), currentBounds.width());
+ assertEquals(origBounds.height(), currentBounds.height());
+ assertEquals(offsetX, currentBounds.left);
+ assertScaled();
}
@Test
@@ -412,7 +442,7 @@ public class SizeCompatTests extends WindowTestsBase {
public void testResetNonVisibleActivity() {
setUpDisplaySizeWithApp(1000, 2500);
prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
- final DisplayContent display = mStack.getDisplay();
+ final DisplayContent display = mStack.mDisplayContent;
// Resize the display so the activity is in size compatibility mode.
resizeDisplay(display, 900, 1800);
@@ -464,7 +494,7 @@ public class SizeCompatTests extends WindowTestsBase {
});
// Resize the display so that the activity exercises size-compat mode.
- resizeDisplay(mStack.getDisplay(), 1000, 2500);
+ resizeDisplay(mStack.mDisplayContent, 1000, 2500);
// Expect the exact token when the activity is in size compatibility mode.
assertEquals(1, compatTokens.size());
@@ -477,7 +507,7 @@ public class SizeCompatTests extends WindowTestsBase {
activity.restartProcessIfVisible();
// The full lifecycle isn't hooked up so manually set state to resumed
activity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
- mStack.getDisplay().handleActivitySizeCompatModeIfNeeded(activity);
+ mStack.mDisplayContent.handleActivitySizeCompatModeIfNeeded(activity);
// Expect null token when switching to non-size-compat mode activity.
assertEquals(1, compatTokens.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 260f1e9a9259..bc3b3a4d7ad1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -218,7 +218,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
final Task rootHomeTask = defaultTaskDisplayArea.getRootHomeTask();
rootHomeTask.mResizeMode = RESIZE_MODE_UNRESIZEABLE;
- final Task primarySplitTask = new StackBuilder(rootWindowContainer)
+ final Task primarySplitTask = new TaskBuilder(mSupervisor)
.setTaskDisplayArea(defaultTaskDisplayArea)
.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
.setActivityType(ACTIVITY_TYPE_STANDARD)
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 42de5e6b429d..1d32e17dd5e1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1358,7 +1358,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
final Task stack = display.getDefaultTaskDisplayArea()
.createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
- final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
// Just work around the unnecessary adjustments for bounds.
task.getWindowConfiguration().setBounds(bounds);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 08537a4ea9c1..a908bfef98de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -176,7 +176,7 @@ public class TaskRecordTests extends WindowTestsBase {
TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
final Configuration parentConfig = stack.getConfiguration();
parentConfig.windowConfiguration.setBounds(parentBounds);
parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
@@ -212,7 +212,7 @@ public class TaskRecordTests extends WindowTestsBase {
@Test
public void testBoundsOnModeChangeFreeformToFullscreen() {
DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
- Task stack = new StackBuilder(mRootWindowContainer).setDisplay(display)
+ Task stack = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
Task task = stack.getBottomMostTask();
task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
@@ -253,7 +253,7 @@ public class TaskRecordTests extends WindowTestsBase {
dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
- final Task stack = new StackBuilder(mRootWindowContainer)
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
final Task task = stack.getBottomMostTask();
final ActivityRecord root = task.getTopNonFinishingActivity();
@@ -317,7 +317,7 @@ public class TaskRecordTests extends WindowTestsBase {
dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
- final Task stack = new StackBuilder(mRootWindowContainer)
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
final Task task = stack.getBottomMostTask();
ActivityRecord root = task.getTopNonFinishingActivity();
@@ -341,7 +341,7 @@ public class TaskRecordTests extends WindowTestsBase {
Configuration.ORIENTATION_LANDSCAPE;
display.onRequestedOverrideConfigurationChanged(
display.getRequestedOverrideConfiguration());
- Task stack = new StackBuilder(mRootWindowContainer)
+ Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
Task task = stack.getBottomMostTask();
ActivityRecord root = task.getTopNonFinishingActivity();
@@ -497,7 +497,7 @@ public class TaskRecordTests extends WindowTestsBase {
DisplayInfo displayInfo = new DisplayInfo();
mAtm.mContext.getDisplay().getDisplayInfo(displayInfo);
final int displayHeight = displayInfo.logicalHeight;
- final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
final Configuration inOutConfig = new Configuration();
final Configuration parentConfig = new Configuration();
final int longSide = 1200;
@@ -1029,7 +1029,7 @@ public class TaskRecordTests extends WindowTestsBase {
}
private Task getTestTask() {
- final Task stack = new StackBuilder(mRootWindowContainer).build();
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
return stack.getBottomMostTask();
}
@@ -1039,7 +1039,7 @@ public class TaskRecordTests extends WindowTestsBase {
TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
Task stack = taskDisplayArea.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
final Configuration parentConfig = stack.getConfiguration();
parentConfig.windowConfiguration.setAppBounds(parentBounds);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index bce1142c99be..ca3f815698e8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -53,7 +53,6 @@ import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.compatibility.common.util.SystemUtil;
-import com.android.internal.annotations.GuardedBy;
import org.junit.After;
import org.junit.Before;
@@ -76,14 +75,10 @@ public class TaskStackChangedListenerTest {
private static final int WAIT_TIMEOUT_MS = 5000;
private static final Object sLock = new Object();
- @GuardedBy("sLock")
- private static boolean sTaskStackChangedCalled;
- private static boolean sActivityBResumed;
@Before
public void setUp() throws Exception {
mService = ActivityManager.getService();
- sTaskStackChangedCalled = false;
}
@After
@@ -94,47 +89,33 @@ public class TaskStackChangedListenerTest {
@Test
@Presubmit
- @FlakyTest(bugId = 130388819)
public void testTaskStackChanged_afterFinish() throws Exception {
+ final TestActivity activity = startTestActivity(ActivityA.class);
+ final CountDownLatch latch = new CountDownLatch(1);
registerTaskStackChangedListener(new TaskStackListener() {
@Override
public void onTaskStackChanged() throws RemoteException {
- synchronized (sLock) {
- sTaskStackChangedCalled = true;
- }
+ latch.countDown();
}
});
- Context context = getInstrumentation().getContext();
- context.startActivity(
- new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
- UiDevice.getInstance(getInstrumentation()).waitForIdle();
- synchronized (sLock) {
- assertTrue(sTaskStackChangedCalled);
- }
- assertTrue(sActivityBResumed);
+ activity.finish();
+ waitForCallback(latch);
}
@Test
@Presubmit
public void testTaskStackChanged_resumeWhilePausing() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
registerTaskStackChangedListener(new TaskStackListener() {
@Override
public void onTaskStackChanged() throws RemoteException {
- synchronized (sLock) {
- sTaskStackChangedCalled = true;
- }
+ latch.countDown();
}
});
- final Context context = getInstrumentation().getContext();
- context.startActivity(new Intent(context, ResumeWhilePausingActivity.class).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK));
- UiDevice.getInstance(getInstrumentation()).waitForIdle();
-
- synchronized (sLock) {
- assertTrue(sTaskStackChangedCalled);
- }
+ startTestActivity(ResumeWhilePausingActivity.class);
+ waitForCallback(latch);
}
@Test
@@ -512,7 +493,7 @@ public class TaskStackChangedListenerTest {
try {
final boolean result = latch.await(WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (!result) {
- throw new RuntimeException("Timed out waiting for task stack change notification");
+ throw new AssertionError("Timed out waiting for task stack change notification");
}
} catch (InterruptedException e) {
}
@@ -569,19 +550,6 @@ public class TaskStackChangedListenerTest {
}
public static class ActivityA extends TestActivity {
-
- private boolean mActivityBLaunched = false;
-
- @Override
- protected void onPostResume() {
- super.onPostResume();
- if (mActivityBLaunched) {
- return;
- }
- mActivityBLaunched = true;
- finish();
- startActivity(new Intent(this, ActivityB.class));
- }
}
public static class ActivityB extends TestActivity {
@@ -589,10 +557,6 @@ public class TaskStackChangedListenerTest {
@Override
protected void onPostResume() {
super.onPostResume();
- synchronized (sLock) {
- sTaskStackChangedCalled = false;
- }
- sActivityBResumed = true;
finish();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 4163a9a546a0..36f3a21e38f1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -829,7 +829,7 @@ public class WindowContainerTests extends WindowTestsBase {
final DisplayContent displayContent = createNewDisplay();
// Do not reparent activity to default display when removing the display.
doReturn(true).when(displayContent).shouldDestroyContentOnRemove();
- final ActivityRecord r = new StackBuilder(mWm.mRoot)
+ final ActivityRecord r = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setDisplay(displayContent).build().getTopMostActivity();
// Add a window and make the activity animating so the removal of activity is deferred.
createWindow(null, TYPE_BASE_APPLICATION, r, "win");
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index f97dff3162c4..2510385f4580 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -114,11 +114,11 @@ public class WindowManagerServiceTests extends WindowTestsBase {
Task tappedStack = createTaskStackOnDisplay(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, display);
Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
- spyOn(mWm.mActivityTaskManager);
+ spyOn(mWm.mAtmService);
mWm.handleTaskFocusChange(tappedTask);
- verify(mWm.mActivityTaskManager).setFocusedTask(tappedTask.mTaskId);
+ verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId);
}
@Test
@@ -135,11 +135,11 @@ public class WindowManagerServiceTests extends WindowTestsBase {
Task tappedStack = createTaskStackOnDisplay(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, display);
Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
- spyOn(mWm.mActivityTaskManager);
+ spyOn(mWm.mAtmService);
mWm.handleTaskFocusChange(tappedTask);
- verify(mWm.mActivityTaskManager, never()).setFocusedTask(tappedTask.mTaskId);
+ verify(mWm.mAtmService, never()).setFocusedTask(tappedTask.mTaskId);
}
@Test
@@ -158,10 +158,10 @@ public class WindowManagerServiceTests extends WindowTestsBase {
Task tappedStack = createTaskStackOnTaskDisplayArea(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, secondTda);
Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
- spyOn(mWm.mActivityTaskManager);
+ spyOn(mWm.mAtmService);
mWm.handleTaskFocusChange(tappedTask);
- verify(mWm.mActivityTaskManager).setFocusedTask(tappedTask.mTaskId);
+ verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 289d54e967f5..38909f6a28d4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -290,7 +290,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testTaskTransaction() {
removeGlobalMinSizeRestriction();
- final Task stack = new StackBuilder(mWm.mRoot)
+ final Task stack = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
final Task task = stack.getTopMostTask();
testTransaction(task);
@@ -299,7 +299,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testStackTransaction() {
removeGlobalMinSizeRestriction();
- final Task stack = new StackBuilder(mWm.mRoot)
+ final Task stack = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
StackInfo info =
mWm.mAtmService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
@@ -324,7 +324,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testSetWindowingMode() {
- final Task stack = new StackBuilder(mWm.mRoot)
+ final Task stack = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
testSetWindowingMode(stack);
@@ -358,7 +358,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testContainerFocusableChanges() {
removeGlobalMinSizeRestriction();
- final Task stack = new StackBuilder(mWm.mRoot)
+ final Task stack = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
final Task task = stack.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
@@ -374,7 +374,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testContainerHiddenChanges() {
removeGlobalMinSizeRestriction();
- final Task stack = new StackBuilder(mWm.mRoot)
+ final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
WindowContainerTransaction t = new WindowContainerTransaction();
assertTrue(stack.shouldBeVisible(null));
@@ -389,7 +389,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testOverrideConfigSize() {
removeGlobalMinSizeRestriction();
- final Task stack = new StackBuilder(mWm.mRoot)
+ final Task stack = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
final Task task = stack.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
@@ -930,23 +930,36 @@ public class WindowOrganizerTests extends WindowTestsBase {
final Task stack = createStack();
final Task task = createTask(stack);
final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task);
+ final Task stack2 = createStack();
+ final Task task2 = createTask(stack2);
+ final ActivityRecord activity2 = createActivityRecordInTask(stack.mDisplayContent, task2);
final ITaskOrganizer organizer = registerMockOrganizer();
// Setup the task to be controlled by the MW mode organizer
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
assertTrue(stack.isOrganized());
+ assertTrue(stack2.isOrganized());
// Verify a back pressed does not call the organizer
mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
verify(organizer, never()).onBackPressedOnTaskRoot(any());
// Enable intercepting back
- mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(organizer,
- true);
+ mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(
+ stack.mRemoteToken.toWindowContainerToken(), true);
// Verify now that the back press does call the organizer
mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
+
+ // Disable intercepting back
+ mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(
+ stack.mRemoteToken.toWindowContainerToken(), false);
+
+ // Verify now that the back press no longer calls the organizer
+ mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
+ verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 9603d28c286b..3106ca26c8a1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -661,14 +661,14 @@ public class WindowStateTests extends WindowTestsBase {
RecentsAnimationController recentsController = mock(RecentsAnimationController.class);
when(recentsController.shouldApplyInputConsumer(win0.mActivityRecord)).thenReturn(true);
mWm.setRecentsAnimationController(recentsController);
- assertTrue(win0.cantReceiveTouchInput());
+ assertFalse(win0.canReceiveTouchInput());
}
@Test
public void testCantReceiveTouchWhenAppTokenHiddenRequested() {
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
win0.mActivityRecord.mVisibleRequested = false;
- assertTrue(win0.cantReceiveTouchInput());
+ assertFalse(win0.canReceiveTouchInput());
}
@Test
@@ -676,7 +676,7 @@ public class WindowStateTests extends WindowTestsBase {
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
win0.mActivityRecord.getStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
win0.mActivityRecord.getStack().setFocusable(false);
- assertTrue(win0.cantReceiveTouchInput());
+ assertFalse(win0.canReceiveTouchInput());
}
@UseTestDisplay(addWindows = W_ACTIVITY)
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 38c4e0a7de02..7daddd8720ab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -90,6 +90,7 @@ import com.android.server.AttributeCache;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.Description;
+import org.mockito.Mockito;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -398,22 +399,20 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
Task createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
- return new StackBuilder(dc.mWmService.mRoot)
+ return new TaskBuilder(dc.mAtmService.mStackSupervisor)
.setDisplay(dc)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
- .setCreateActivity(false)
.setIntent(new Intent())
.build();
}
Task createTaskStackOnTaskDisplayArea(int windowingMode, int activityType,
TaskDisplayArea tda) {
- return new StackBuilder(tda.mWmService.mRoot)
+ return new TaskBuilder(tda.mDisplayContent.mAtmService.mStackSupervisor)
.setTaskDisplayArea(tda)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
- .setCreateActivity(false)
.setIntent(new Intent())
.build();
}
@@ -422,7 +421,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
Task createTaskInStack(Task stack, int userId) {
final Task task = new TaskBuilder(stack.mStackSupervisor)
.setUserId(userId)
- .setStack(stack)
+ .setParentTask(stack)
.build();
return task;
}
@@ -733,7 +732,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
if (mCreateTask) {
mTask = new TaskBuilder(mService.mStackSupervisor)
.setComponent(mComponent)
- .setStack(mStack).build();
+ .setParentTask(mStack).build();
} else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack(
mStack.getWindowingMode(), mStack.getActivityType())) {
// The stack can be the task root.
@@ -813,43 +812,51 @@ class WindowTestsBase extends SystemServiceTestsBase {
protected static class TaskBuilder {
private final ActivityStackSupervisor mSupervisor;
+ private TaskDisplayArea mTaskDisplayArea;
private ComponentName mComponent;
private String mPackage;
private int mFlags = 0;
- // Task id 0 is reserved in ARC for the home app.
- private int mTaskId = SystemServicesTestRule.sNextTaskId++;
+ private int mTaskId = -1;
private int mUserId = 0;
+ private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ private int mActivityType = ACTIVITY_TYPE_STANDARD;
+ private ActivityInfo mActivityInfo;
+ private Intent mIntent;
+ private boolean mOnTop = true;
private IVoiceInteractionSession mVoiceSession;
- private boolean mCreateStack = true;
- private Task mStack;
- private TaskDisplayArea mTaskDisplayArea;
+ private boolean mCreateParentTask = false;
+ private Task mParentTask;
+
+ private boolean mCreateActivity = false;
TaskBuilder(ActivityStackSupervisor supervisor) {
mSupervisor = supervisor;
+ mTaskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
}
- TaskBuilder setComponent(ComponentName component) {
- mComponent = component;
+ /**
+ * Set the parent {@link DisplayContent} and use the default task display area. Overrides
+ * the task display area, if was set before.
+ */
+ TaskBuilder setDisplay(DisplayContent display) {
+ mTaskDisplayArea = display.getDefaultTaskDisplayArea();
return this;
}
- TaskBuilder setPackage(String packageName) {
- mPackage = packageName;
+ /** Set the parent {@link TaskDisplayArea}. Overrides the display, if was set before. */
+ TaskBuilder setTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
+ mTaskDisplayArea = taskDisplayArea;
return this;
}
- /**
- * Set to {@code true} by default, set to {@code false} to prevent the task from
- * automatically creating a parent stack.
- */
- TaskBuilder setCreateStack(boolean createStack) {
- mCreateStack = createStack;
+ TaskBuilder setComponent(ComponentName component) {
+ mComponent = component;
return this;
}
- TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
- mVoiceSession = session;
+ TaskBuilder setPackage(String packageName) {
+ mPackage = packageName;
return this;
}
@@ -868,156 +875,117 @@ class WindowTestsBase extends SystemServiceTestsBase {
return this;
}
- TaskBuilder setStack(Task stack) {
- mStack = stack;
- return this;
- }
-
- TaskBuilder setDisplay(DisplayContent display) {
- mTaskDisplayArea = display.getDefaultTaskDisplayArea();
- return this;
- }
-
- Task build() {
- SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
-
- if (mStack == null && mCreateStack) {
- TaskDisplayArea displayArea = mTaskDisplayArea != null ? mTaskDisplayArea
- : mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
- mStack = displayArea.createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- spyOn(mStack);
- }
-
- final ActivityInfo aInfo = new ActivityInfo();
- aInfo.applicationInfo = new ApplicationInfo();
- aInfo.applicationInfo.packageName = mPackage;
-
- Intent intent = new Intent();
- if (mComponent == null) {
- mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
- DEFAULT_COMPONENT_CLASS_NAME);
- }
-
- intent.setComponent(mComponent);
- intent.setFlags(mFlags);
-
- final Task task = new Task(mSupervisor.mService, mTaskId, aInfo,
- intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
- null /*taskDescription*/, mStack);
- spyOn(task);
- task.mUserId = mUserId;
-
- if (mStack != null) {
- mStack.moveToFront("test");
- mStack.addChild(task, true, true);
- }
-
- return task;
- }
- }
-
- static class StackBuilder {
- private final RootWindowContainer mRootWindowContainer;
- private DisplayContent mDisplay;
- private TaskDisplayArea mTaskDisplayArea;
- private int mStackId = -1;
- private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
- private int mActivityType = ACTIVITY_TYPE_STANDARD;
- private boolean mOnTop = true;
- private boolean mCreateActivity = true;
- private ActivityInfo mInfo;
- private Intent mIntent;
-
- StackBuilder(RootWindowContainer root) {
- mRootWindowContainer = root;
- mDisplay = mRootWindowContainer.getDefaultDisplay();
- mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
- }
-
- StackBuilder setWindowingMode(int windowingMode) {
+ TaskBuilder setWindowingMode(int windowingMode) {
mWindowingMode = windowingMode;
return this;
}
- StackBuilder setActivityType(int activityType) {
+ TaskBuilder setActivityType(int activityType) {
mActivityType = activityType;
return this;
}
- StackBuilder setStackId(int stackId) {
- mStackId = stackId;
+ TaskBuilder setActivityInfo(ActivityInfo info) {
+ mActivityInfo = info;
return this;
}
- /**
- * Set the parent {@link DisplayContent} and use the default task display area. Overrides
- * the task display area, if was set before.
- */
- StackBuilder setDisplay(DisplayContent display) {
- mDisplay = display;
- mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
+ TaskBuilder setIntent(Intent intent) {
+ mIntent = intent;
return this;
}
- /** Set the parent {@link TaskDisplayArea}. Overrides the display, if was set before. */
- StackBuilder setTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
- mTaskDisplayArea = taskDisplayArea;
- mDisplay = mTaskDisplayArea.mDisplayContent;
+ TaskBuilder setOnTop(boolean onTop) {
+ mOnTop = onTop;
return this;
}
- StackBuilder setOnTop(boolean onTop) {
- mOnTop = onTop;
+ TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
+ mVoiceSession = session;
return this;
}
- StackBuilder setCreateActivity(boolean createActivity) {
- mCreateActivity = createActivity;
+ TaskBuilder setCreateParentTask(boolean createParentTask) {
+ mCreateParentTask = createParentTask;
return this;
}
- StackBuilder setActivityInfo(ActivityInfo info) {
- mInfo = info;
+ TaskBuilder setParentTask(Task parentTask) {
+ mParentTask = parentTask;
return this;
}
- StackBuilder setIntent(Intent intent) {
- mIntent = intent;
+ TaskBuilder setCreateActivity(boolean createActivity) {
+ mCreateActivity = createActivity;
return this;
}
Task build() {
- SystemServicesTestRule.checkHoldsLock(mRootWindowContainer.mWmService.mGlobalLock);
+ SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
+
+ // Create parent task.
+ if (mParentTask == null && mCreateParentTask) {
+ mParentTask = mTaskDisplayArea.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ }
+ if (mParentTask != null && !Mockito.mockingDetails(mParentTask).isSpy()) {
+ spyOn(mParentTask);
+ }
+
+ // Create task.
+ if (mActivityInfo == null) {
+ mActivityInfo = new ActivityInfo();
+ mActivityInfo.applicationInfo = new ApplicationInfo();
+ mActivityInfo.applicationInfo.packageName = mPackage;
+ }
- final int stackId = mStackId >= 0 ? mStackId : mTaskDisplayArea.getNextStackId();
- final Task stack = mTaskDisplayArea.createStackUnchecked(
- mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent,
- false /* createdByOrganizer */);
- final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor;
+ if (mIntent == null) {
+ mIntent = new Intent();
+ if (mComponent == null) {
+ mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_CLASS_NAME);
+ }
+ mIntent.setComponent(mComponent);
+ mIntent.setFlags(mFlags);
+ }
+ Task task;
+ final int taskId = mTaskId >= 0 ? mTaskId : mTaskDisplayArea.getNextStackId();
+ if (mParentTask == null) {
+ task = mTaskDisplayArea.createStackUnchecked(
+ mWindowingMode, mActivityType, taskId, mOnTop, mActivityInfo,
+ mIntent, false /* createdByOrganizer */);
+ } else {
+ task = new Task(mSupervisor.mService, taskId, mActivityInfo,
+ mIntent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
+ null /*taskDescription*/, mParentTask);
+ mParentTask.moveToFront("build-task");
+ mParentTask.addChild(task, true, true);
+ }
+ spyOn(task);
+ task.mUserId = mUserId;
+ Task rootTask = task.getRootTask();
+ doNothing().when(rootTask).startActivityLocked(
+ any(), any(), anyBoolean(), anyBoolean(), any());
+
+ // Create child task with activity.
if (mCreateActivity) {
- new ActivityBuilder(supervisor.mService)
+ new ActivityBuilder(mSupervisor.mService)
.setCreateTask(true)
- .setStack(stack)
+ .setStack(task)
.build();
if (mOnTop) {
// We move the task to front again in order to regain focus after activity
- // added to the stack. Or {@link DisplayContent#mPreferredTopFocusableStack}
+ // added to the stack. Or {@link TaskDisplayArea#mPreferredTopFocusableStack}
// could be other stacks (e.g. home stack).
- stack.moveToFront("createActivityStack");
+ task.moveToFront("createActivityTask");
} else {
- stack.moveToBack("createActivityStack", null);
+ task.moveToBack("createActivityTask", null);
}
}
- spyOn(stack);
-
- doNothing().when(stack).startActivityLocked(
- any(), any(), anyBoolean(), anyBoolean(), any());
- return stack;
+ return task;
}
-
}
static class TestSplitOrganizer extends ITaskOrganizer.Stub {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 81aad972898e..f151d9ca2420 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -183,6 +183,7 @@ public class UsageStatsService extends SystemService implements
private static class ActivityData {
private final String mTaskRootPackage;
private final String mTaskRootClass;
+ public int lastEvent = Event.NONE;
private ActivityData(String taskRootPackage, String taskRootClass) {
mTaskRootPackage = taskRootPackage;
mTaskRootClass = taskRootClass;
@@ -785,6 +786,7 @@ public class UsageStatsService extends SystemService implements
switch (event.mEventType) {
case Event.ACTIVITY_RESUMED:
case Event.ACTIVITY_PAUSED:
+ case Event.ACTIVITY_STOPPED:
uid = mPackageManagerInternal.getPackageUid(event.mPackage, 0, userId);
break;
default:
@@ -817,8 +819,10 @@ public class UsageStatsService extends SystemService implements
.APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_FOREGROUND);
// check if this activity has already been resumed
if (mVisibleActivities.get(event.mInstanceId) != null) break;
- mVisibleActivities.put(event.mInstanceId,
- new ActivityData(event.mTaskRootPackage, event.mTaskRootClass));
+ final ActivityData resumedData = new ActivityData(event.mTaskRootPackage,
+ event.mTaskRootClass);
+ resumedData.lastEvent = Event.ACTIVITY_RESUMED;
+ mVisibleActivities.put(event.mInstanceId, resumedData);
try {
switch(mUsageSource) {
case USAGE_SOURCE_CURRENT_ACTIVITY:
@@ -834,16 +838,17 @@ public class UsageStatsService extends SystemService implements
}
break;
case Event.ACTIVITY_PAUSED:
- if (event.mTaskRootPackage == null) {
- // Task Root info is missing. Repair the event based on previous data
- final ActivityData prevData = mVisibleActivities.get(event.mInstanceId);
- if (prevData == null) {
- Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
- + "/" + event.mClass + " event : " + event.mEventType
- + " instanceId : " + event.mInstanceId + ")");
- } else {
- event.mTaskRootPackage = prevData.mTaskRootPackage;
- event.mTaskRootClass = prevData.mTaskRootClass;
+ final ActivityData pausedData = mVisibleActivities.get(event.mInstanceId);
+ if (pausedData == null) {
+ Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
+ + "/" + event.mClass + " event : " + event.mEventType
+ + " instanceId : " + event.mInstanceId + ")");
+ } else {
+ pausedData.lastEvent = Event.ACTIVITY_PAUSED;
+ if (event.mTaskRootPackage == null) {
+ // Task Root info is missing. Repair the event based on previous data
+ event.mTaskRootPackage = pausedData.mTaskRootPackage;
+ event.mTaskRootClass = pausedData.mTaskRootClass;
}
}
FrameworkStatsLog.write(
@@ -866,6 +871,16 @@ public class UsageStatsService extends SystemService implements
return;
}
+ if (prevData.lastEvent != Event.ACTIVITY_PAUSED) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.APP_USAGE_EVENT_OCCURRED,
+ uid,
+ event.mPackage,
+ event.mClass,
+ FrameworkStatsLog
+ .APP_USAGE_EVENT_OCCURRED__EVENT_TYPE__MOVE_TO_BACKGROUND);
+ }
+
ArraySet<String> tokens;
synchronized (mUsageReporters) {
tokens = mUsageReporters.removeReturnOld(event.mInstanceId);