summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp4
-rw-r--r--apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java276
-rw-r--r--apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java2
-rw-r--r--apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java4
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java8
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java75
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/Stats.java6
-rw-r--r--apex/jobscheduler/README_js-mainline.md51
-rw-r--r--apex/jobscheduler/service/Android.bp15
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java (renamed from services/core/java/com/android/server/job/GrantedUriPermissions.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java (renamed from services/core/java/com/android/server/job/JobCompletedListener.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java (renamed from services/core/java/com/android/server/job/JobConcurrencyManager.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java (renamed from services/core/java/com/android/server/job/JobPackageTracker.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java (renamed from services/core/java/com/android/server/job/JobSchedulerService.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java (renamed from services/core/java/com/android/server/job/JobSchedulerShellCommand.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java (renamed from services/core/java/com/android/server/job/JobServiceContext.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java (renamed from services/core/java/com/android/server/job/JobStore.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java (renamed from services/core/java/com/android/server/job/StateChangedListener.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java (renamed from services/core/java/com/android/server/job/controllers/BackgroundJobsController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java (renamed from services/core/java/com/android/server/job/controllers/BatteryController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java (renamed from services/core/java/com/android/server/job/controllers/ConnectivityController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java (renamed from services/core/java/com/android/server/job/controllers/ContentObserverController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java (renamed from services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java (renamed from services/core/java/com/android/server/job/controllers/IdleController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java (renamed from services/core/java/com/android/server/job/controllers/JobStatus.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java (renamed from services/core/java/com/android/server/job/controllers/QuotaController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java (renamed from services/core/java/com/android/server/job/controllers/StateController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java (renamed from services/core/java/com/android/server/job/controllers/StorageController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java (renamed from services/core/java/com/android/server/job/controllers/TimeController.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java (renamed from services/core/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java (renamed from services/core/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessListener.java (renamed from services/core/java/com/android/server/job/controllers/idle/IdlenessListener.java)0
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java (renamed from services/core/java/com/android/server/job/controllers/idle/IdlenessTracker.java)0
-rw-r--r--api/current.txt25
-rw-r--r--api/test-current.txt9
-rw-r--r--cmds/locksettings/TEST_MAPPING15
-rw-r--r--config/boot-profile.txt0
-rw-r--r--config/preloaded-classes1
-rw-r--r--config/preloaded-classes-extra3
-rw-r--r--core/java/android/accessibilityservice/AccessibilityGestureInfo.aidl (renamed from tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java)26
-rw-r--r--core/java/android/accessibilityservice/AccessibilityGestureInfo.java155
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java53
-rw-r--r--core/java/android/accessibilityservice/GestureDescription.java40
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl3
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl2
-rw-r--r--core/java/android/app/ActivityOptions.java33
-rw-r--r--core/java/android/app/ActivityView.java8
-rw-r--r--core/java/android/app/AppOpsManager.java15
-rw-r--r--core/java/android/app/JobSchedulerImpl.java5
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/app/PendingIntent.java11
-rw-r--r--core/java/android/app/SystemServiceRegistry.java31
-rw-r--r--core/java/android/app/UiAutomation.java3
-rw-r--r--core/java/android/app/assist/AssistStructure.java52
-rw-r--r--core/java/android/app/job/JobSchedulerFrameworkInitializer.java35
-rw-r--r--core/java/android/bluetooth/BluetoothCodecConfig.java91
-rw-r--r--core/java/android/bluetooth/BluetoothCodecStatus.java37
-rw-r--r--core/java/android/bluetooth/BluetoothHeadsetClient.java58
-rw-r--r--core/java/android/content/pm/PackageManager.java24
-rw-r--r--core/java/android/content/pm/PackageParser.java82
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java19
-rw-r--r--core/java/android/hardware/biometrics/IBiometricService.aidl3
-rw-r--r--core/java/android/hardware/radio/ProgramList.java46
-rw-r--r--core/java/android/hardware/radio/RadioMetadata.java5
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java14
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/view/IRecentsAnimationController.aidl44
-rw-r--r--core/java/android/view/IRecentsAnimationRunner.aidl2
-rw-r--r--core/java/android/view/MotionEvent.java111
-rw-r--r--core/java/android/view/ThreadedRenderer.java11
-rw-r--r--core/java/android/view/View.java17
-rw-r--r--core/java/android/view/ViewStructure.java10
-rw-r--r--core/java/android/view/contentcapture/ViewNode.java23
-rw-r--r--core/java/android/widget/NumberPicker.java15
-rw-r--r--core/java/android/widget/TextView.java14
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java35
-rw-r--r--core/java/com/android/internal/os/KernelWakelockReader.java134
-rw-r--r--core/java/com/android/internal/policy/DecorView.java4
-rw-r--r--core/java/com/android/internal/policy/DividerSnapAlgorithm.java6
-rw-r--r--core/java/com/android/internal/widget/MediaNotificationView.java47
-rw-r--r--core/java/com/android/server/job/JobSchedulerInternal.java (renamed from services/core/java/com/android/server/job/JobSchedulerInternal.java)0
-rw-r--r--core/jni/android_view_MotionEvent.cpp24
-rw-r--r--core/proto/OWNERS2
-rw-r--r--core/proto/android/app/settings_enums.proto7
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--core/res/res/values/attrs_manifest.xml14
-rw-r--r--core/res/res/values/config.xml11
-rw-r--r--core/res/res/values/strings.xml3
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java98
-rw-r--r--core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java353
-rw-r--r--core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java42
-rw-r--r--core/tests/coretests/src/android/view/MotionEventTest.java61
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java57
-rw-r--r--libs/hwui/SkiaCanvas.cpp139
-rw-r--r--libs/hwui/SkiaCanvas.h69
-rw-r--r--libs/hwui/VectorDrawable.cpp9
-rw-r--r--libs/hwui/hwui/Canvas.cpp6
-rw-r--r--libs/hwui/hwui/Canvas.h40
-rw-r--r--libs/hwui/hwui/Paint.h7
-rw-r--r--libs/hwui/hwui/PaintImpl.cpp4
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp12
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp61
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h8
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp24
-rw-r--r--libs/hwui/renderthread/ReliableSurface.cpp15
-rw-r--r--libs/hwui/renderthread/ReliableSurface.h10
-rw-r--r--libs/hwui/tests/common/scenes/BitmapShaders.cpp3
-rw-r--r--libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/ListViewAnimation.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/OvalAnimation.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/RectGridAnimation.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/ShapeAnimation.cpp18
-rw-r--r--libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/TestSceneBase.h1
-rw-r--r--libs/hwui/tests/common/scenes/TvApp.cpp2
-rw-r--r--libs/hwui/tests/microbench/DisplayListCanvasBench.cpp3
-rw-r--r--libs/hwui/tests/unit/RenderNodeDrawableTests.cpp33
-rw-r--r--libs/hwui/tests/unit/SkiaCanvasTests.cpp3
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp5
-rw-r--r--libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp3
-rw-r--r--libs/hwui/utils/PaintUtils.h23
-rw-r--r--packages/CtsShim/build/Android.mk3
-rw-r--r--packages/DynamicSystemInstallationService/Android.bp14
-rw-r--r--packages/DynamicSystemInstallationService/Android.mk19
-rw-r--r--packages/InputDevices/Android.bp42
-rw-r--r--packages/InputDevices/Android.mk50
-rw-r--r--packages/MtpDocumentsProvider/Android.bp11
-rw-r--r--packages/MtpDocumentsProvider/Android.mk18
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml10
-rw-r--r--packages/SettingsLib/tests/Android.mk19
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java43
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java60
-rw-r--r--packages/SimAppDialog/Android.bp15
-rw-r--r--packages/SimAppDialog/Android.mk19
-rw-r--r--packages/SystemUI/plugin/ExamplePlugin/Android.bp1
-rw-r--r--packages/SystemUI/res/values/attrs.xml5
-rw-r--r--packages/SystemUI/res/values/colors.xml3
-rw-r--r--packages/SystemUI/res/values/styles.xml2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java18
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java9
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java (renamed from packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java)27
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/CornerHandleView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/DumpController.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/ImageWallpaper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeHost.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt65
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java3
-rw-r--r--proto/src/wifi.proto25
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java25
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java32
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java19
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java31
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java8
-rw-r--r--services/accessibility/java/com/android/server/accessibility/TouchExplorer.java5
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java8
-rw-r--r--services/core/Android.bp10
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java46
-rw-r--r--services/core/java/com/android/server/DynamicSystemService.java7
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java10
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java18
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java15
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java9
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java17
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricServiceBase.java12
-rw-r--r--services/core/java/com/android/server/biometrics/EnrollClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/LoggableMonitor.java2
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java59
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java4
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/Convert.java1
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java109
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java158
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java53
-rw-r--r--services/core/java/com/android/server/compat/CompatChange.java12
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java64
-rw-r--r--services/core/java/com/android/server/compat/IPlatformCompat.aidl57
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java52
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java15
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecKeycode.java3
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java6
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java2
-rw-r--r--services/core/java/com/android/server/locksettings/TEST_MAPPING15
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java33
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java380
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java14
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java44
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java372
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java75
-rw-r--r--services/core/java/com/android/server/pm/InstantAppRegistry.java48
-rw-r--r--services/core/java/com/android/server/pm/InstructionSets.java13
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelper.java135
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelperImpl.java528
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java1599
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java15
-rw-r--r--services/core/java/com/android/server/pm/Settings.java4
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java13
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING14
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java16
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java85
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyInternal.java27
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java25
-rw-r--r--services/core/java/com/android/server/slice/PinnedSliceState.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java19
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java37
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java9
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettings.java28
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java35
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java16
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java188
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java10
-rw-r--r--services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java7
-rw-r--r--services/core/xsd/Android.bp8
-rw-r--r--services/core/xsd/platform-compat-config.xsd51
-rw-r--r--services/core/xsd/platform-compat-schema/current.txt31
-rw-r--r--services/core/xsd/platform-compat-schema/last_current.txt0
-rw-r--r--services/core/xsd/platform-compat-schema/last_removed.txt0
-rw-r--r--services/core/xsd/platform-compat-schema/removed.txt1
-rw-r--r--services/java/com/android/server/SystemServer.java20
-rw-r--r--services/robotests/Android.bp53
-rw-r--r--services/robotests/Android.mk89
-rw-r--r--services/robotests/AndroidManifest.xml24
-rw-r--r--services/robotests/backup/Android.bp53
-rw-r--r--services/robotests/backup/Android.mk84
-rw-r--r--services/robotests/backup/AndroidManifest.xml24
-rw-r--r--services/tests/mockingservicestests/Android.bp1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java68
-rw-r--r--services/tests/servicestests/Android.bp2
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java86
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java70
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java340
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java176
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java162
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java105
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanTests.java551
-rw-r--r--services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java47
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java16
-rw-r--r--startop/apps/test/Android.bp1
-rwxr-xr-xstartop/scripts/iorap/compiler.py2
-rw-r--r--startop/view_compiler/dex_builder.cc60
-rw-r--r--startop/view_compiler/dex_builder.h65
-rw-r--r--startop/view_compiler/dex_builder_test/Android.bp1
-rw-r--r--startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java23
-rw-r--r--startop/view_compiler/dex_builder_test/src/android/startop/test/TestClass.java23
-rw-r--r--startop/view_compiler/dex_testcase_generator.cc31
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java99
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthGsm.java7
-rw-r--r--telephony/java/android/telephony/ims/ImsException.java14
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java179
-rw-r--r--telephony/java/android/telephony/ims/ImsRcsManager.java234
-rw-r--r--telephony/java/android/telephony/ims/ProvisioningManager.java18
-rw-r--r--telephony/java/android/telephony/ims/RcsContactUceCapability.aidl (renamed from tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java)15
-rw-r--r--telephony/java/android/telephony/ims/RcsContactUceCapability.java291
-rw-r--r--telephony/java/android/telephony/ims/RcsUceAdapter.java276
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsConfig.aidl3
-rw-r--r--telephony/java/android/telephony/ims/feature/RcsFeature.java161
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java24
-rw-r--r--telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java89
-rw-r--r--telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java191
-rw-r--r--telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java169
-rw-r--r--test-base/Android.mk29
-rwxr-xr-xtests/Codegen/runTest.sh2
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleDataClass.java8
-rw-r--r--tests/JobSchedulerPerfTests/Android.bp1
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp3
-rw-r--r--tools/codegen/Android.bp2
-rw-r--r--tools/codegen/src/com/android/codegen/SharedConstants.kt2
-rw-r--r--tools/dump-coverage/README.md6
-rw-r--r--tools/dump-coverage/dump_coverage.cc52
-rw-r--r--tools/preload2/Android.bp50
-rw-r--r--tools/preload2/preload-tool37
-rw-r--r--tools/preload2/src/com/android/preload/ClientUtils.java224
-rw-r--r--tools/preload2/src/com/android/preload/DeviceUtils.java420
-rw-r--r--tools/preload2/src/com/android/preload/DumpData.java91
-rw-r--r--tools/preload2/src/com/android/preload/DumpDataIO.java141
-rw-r--r--tools/preload2/src/com/android/preload/DumpTableModel.java93
-rw-r--r--tools/preload2/src/com/android/preload/Main.java341
-rw-r--r--tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java39
-rw-r--r--tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java45
-rw-r--r--tools/preload2/src/com/android/preload/actions/ClearTableAction.java37
-rw-r--r--tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java148
-rw-r--r--tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java41
-rw-r--r--tools/preload2/src/com/android/preload/actions/DeviceSpecific.java38
-rw-r--r--tools/preload2/src/com/android/preload/actions/ExportAction.java62
-rw-r--r--tools/preload2/src/com/android/preload/actions/ImportAction.java68
-rw-r--r--tools/preload2/src/com/android/preload/actions/ReloadListAction.java68
-rw-r--r--tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java124
-rw-r--r--tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java63
-rw-r--r--tools/preload2/src/com/android/preload/actions/ScanPackageAction.java97
-rw-r--r--tools/preload2/src/com/android/preload/actions/ShowDataAction.java94
-rw-r--r--tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java60
-rw-r--r--tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java70
-rw-r--r--tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java228
-rw-r--r--tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java221
-rw-r--r--tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java40
-rw-r--r--tools/preload2/src/com/android/preload/ui/IUI.java45
-rw-r--r--tools/preload2/src/com/android/preload/ui/SequenceUI.java222
-rw-r--r--tools/preload2/src/com/android/preload/ui/SwingUI.java291
-rw-r--r--tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt3
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java8
376 files changed, 10639 insertions, 6370 deletions
diff --git a/Android.bp b/Android.bp
index 7693a66fc1f7..7687270fc6f7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1417,10 +1417,6 @@ stubs_defaults {
srcs_lib: "framework",
srcs_lib_whitelist_dirs: frameworks_base_subdirs,
srcs_lib_whitelist_pkgs: packages_to_document,
- libs: [
- "ext",
- "framework",
- ],
local_sourcepaths: frameworks_base_subdirs,
installable: false,
annotations_enabled: true,
diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
new file mode 100644
index 000000000000..4e2b281da1b4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2019 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 android.wm;
+
+import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_COEFFICIENT_VAR;
+import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_ITERATION;
+import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_MEAN;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.hamcrest.core.AnyOf.anyOf;
+import static org.hamcrest.core.Is.is;
+
+import android.app.Activity;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
+import android.perftests.utils.PerfManualStatusReporter;
+import android.perftests.utils.StubActivity;
+import android.util.Pair;
+import android.view.IRecentsAnimationController;
+import android.view.IRecentsAnimationRunner;
+import android.view.RemoteAnimationTarget;
+import android.view.WindowManager;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.lifecycle.ActivityLifecycleCallback;
+import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
+import androidx.test.runner.lifecycle.Stage;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
+ private static Intent sRecentsIntent;
+
+ @Rule
+ public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
+
+ @Rule
+ public final ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule<>(
+ StubActivity.class, false /* initialTouchMode */, false /* launchActivity */);
+
+ private long mMeasuredTimeNs;
+ private LifecycleListener mLifecycleListener;
+
+ @Parameterized.Parameter(0)
+ public int intervalBetweenOperations;
+
+ @Parameterized.Parameters(name = "interval{0}ms")
+ public static Collection<Object[]> getParameters() {
+ return Arrays.asList(new Object[][] {
+ { 0 },
+ { 100 },
+ { 300 },
+ });
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ // Get the permission to invoke startRecentsActivity.
+ sUiAutomation.adoptShellPermissionIdentity();
+
+ final Context context = getInstrumentation().getContext();
+ final PackageManager pm = context.getPackageManager();
+ final ComponentName defaultHome = pm.getHomeActivities(new ArrayList<>());
+
+ try {
+ final ComponentName recentsComponent =
+ ComponentName.unflattenFromString(context.getResources().getString(
+ com.android.internal.R.string.config_recentsComponentName));
+ final int enabledState = pm.getComponentEnabledSetting(recentsComponent);
+ Assume.assumeThat(enabledState, anyOf(
+ is(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
+ is(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)));
+
+ final boolean homeIsRecents =
+ recentsComponent.getPackageName().equals(defaultHome.getPackageName());
+ sRecentsIntent =
+ new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent);
+ } catch (Exception e) {
+ Assume.assumeNoException(e);
+ }
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ sUiAutomation.dropShellPermissionIdentity();
+ }
+
+ @Before
+ @Override
+ public void setUp() {
+ super.setUp();
+ final Activity testActivity = mActivityRule.launchActivity(null /* intent */);
+ try {
+ mActivityRule.runOnUiThread(() -> testActivity.getWindow()
+ .addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
+ } catch (Throwable ignored) { }
+ mLifecycleListener = new LifecycleListener(testActivity);
+ ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(mLifecycleListener);
+ }
+
+ @After
+ public void tearDown() {
+ ActivityLifecycleMonitorRegistry.getInstance().removeLifecycleCallback(mLifecycleListener);
+ }
+
+ /** Simulate the timing of touch. */
+ private void makeInterval() {
+ SystemClock.sleep(intervalBetweenOperations);
+ }
+
+ /**
+ * <pre>
+ * Steps:
+ * (1) Start recents activity (only make it visible).
+ * (2) Finish animation, take turns to execute (a), (b).
+ * (a) Move recents activity to top.
+ * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_TOP})
+ * Move test app to top by startActivityFromRecents.
+ * (b) Cancel (it is similar to swipe a little distance and give up to enter recents).
+ * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_ORIGINAL_POSITION})
+ * (3) Loop (1).
+ * </pre>
+ */
+ @Test
+ @ManualBenchmarkTest(
+ warmupDurationNs = TIME_1_S_IN_NS,
+ targetTestDurationNs = TIME_5_S_IN_NS,
+ statsReportFlags =
+ STATS_REPORT_ITERATION | STATS_REPORT_MEAN | STATS_REPORT_COEFFICIENT_VAR)
+ public void testRecentsAnimation() throws Throwable {
+ final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final IActivityTaskManager atm = ActivityTaskManager.getService();
+
+ final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>();
+ // Real launch the recents activity.
+ finishCases.add(new Pair<>("finishMoveToTop", true));
+ // Return to the original top.
+ finishCases.add(new Pair<>("finishCancel", false));
+
+ // Ensure startRecentsActivity won't be called before finishing the animation.
+ final Semaphore recentsSemaphore = new Semaphore(1);
+
+ final int testActivityTaskId = mActivityRule.getActivity().getTaskId();
+ final IRecentsAnimationRunner.Stub anim = new IRecentsAnimationRunner.Stub() {
+ int mIteration;
+
+ @Override
+ public void onAnimationStart(IRecentsAnimationController controller,
+ RemoteAnimationTarget[] apps, Rect homeContentInsets,
+ Rect minimizedHomeBounds) throws RemoteException {
+ final Pair<String, Boolean> finishCase = finishCases.get(mIteration++ % 2);
+ final boolean moveRecentsToTop = finishCase.second;
+ makeInterval();
+
+ long startTime = SystemClock.elapsedRealtimeNanos();
+ controller.finish(moveRecentsToTop, false /* sendUserLeaveHint */);
+ final long elapsedTimeNsOfFinish = SystemClock.elapsedRealtimeNanos() - startTime;
+ mMeasuredTimeNs += elapsedTimeNsOfFinish;
+ state.addExtraResult(finishCase.first, elapsedTimeNsOfFinish);
+
+ if (moveRecentsToTop) {
+ mLifecycleListener.waitForIdleSync(Stage.STOPPED);
+
+ startTime = SystemClock.elapsedRealtimeNanos();
+ atm.startActivityFromRecents(testActivityTaskId, null /* options */);
+ final long elapsedTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
+ mMeasuredTimeNs += elapsedTimeNs;
+ state.addExtraResult("startFromRecents", elapsedTimeNs);
+
+ mLifecycleListener.waitForIdleSync(Stage.RESUMED);
+ }
+
+ makeInterval();
+ recentsSemaphore.release();
+ }
+
+ @Override
+ public void onAnimationCanceled(boolean deferredWithScreenshot) throws RemoteException {
+ Assume.assumeNoException(
+ new AssertionError("onAnimationCanceled should not be called"));
+ }
+ };
+
+ while (state.keepRunning(mMeasuredTimeNs)) {
+ Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS));
+
+ final long startTime = SystemClock.elapsedRealtimeNanos();
+ atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim);
+ final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime;
+ mMeasuredTimeNs += elapsedTimeNsOfStart;
+ state.addExtraResult("start", elapsedTimeNsOfStart);
+ }
+
+ // Ensure the last round of animation callback is done.
+ recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS);
+ recentsSemaphore.release();
+ }
+
+ private static class LifecycleListener implements ActivityLifecycleCallback {
+ private final Activity mTargetActivity;
+ private Stage mWaitingStage;
+ private Stage mReceivedStage;
+
+ LifecycleListener(Activity activity) {
+ mTargetActivity = activity;
+ }
+
+ void waitForIdleSync(Stage state) {
+ synchronized (this) {
+ if (state != mReceivedStage) {
+ mWaitingStage = state;
+ try {
+ wait(TimeUnit.NANOSECONDS.toMillis(TIME_5_S_IN_NS));
+ } catch (InterruptedException impossible) { }
+ }
+ mWaitingStage = mReceivedStage = null;
+ }
+ getInstrumentation().waitForIdleSync();
+ }
+
+ @Override
+ public void onActivityLifecycleChanged(Activity activity, Stage stage) {
+ if (mTargetActivity != activity) {
+ return;
+ }
+
+ synchronized (this) {
+ mReceivedStage = stage;
+ if (mWaitingStage == mReceivedStage) {
+ notifyAll();
+ }
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
index a95186916cea..27790e649a26 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
@@ -60,7 +60,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
}
@Test
- @ManualBenchmarkTest(warmupDurationNs = WARMUP_DURATION, targetTestDurationNs = TEST_DURATION)
+ @ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS)
public void testAddRemoveWindow() throws Throwable {
new TestWindow().runBenchmark(mPerfStatusReporter.getBenchmarkState());
}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
index b2c61688ef59..4864da4b0195 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
@@ -25,8 +25,8 @@ import org.junit.Before;
public class WindowManagerPerfTestBase {
static final UiAutomation sUiAutomation = getInstrumentation().getUiAutomation();
static final long NANOS_PER_S = 1000L * 1000 * 1000;
- static final long WARMUP_DURATION = 1 * NANOS_PER_S;
- static final long TEST_DURATION = 5 * NANOS_PER_S;
+ static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
+ static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S;
@Before
public void setUp() {
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index e2ef7a11b3a0..2fe0ee7cab57 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -530,10 +530,10 @@ public class UserLifecycleTests {
*/
private void startApp(int userId, String packageName) throws RemoteException {
final Context context = InstrumentationRegistry.getContext();
- final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null, null,
- context.getPackageManager().getLaunchIntentForPackage(packageName),
- null, null, null, 0, 0, null, null,
- userId);
+ final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null,
+ context.getPackageName(),
+ context.getPackageManager().getLaunchIntentForPackage(packageName), null, null,
+ null, 0, 0, null, null, userId);
attestTrue("User " + userId + " failed to start " + packageName,
result.result == ActivityManager.START_SUCCESS);
}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
index dd43ae70cc5c..ffe39e8679e1 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
@@ -16,6 +16,7 @@
package android.perftests.utils;
+import android.annotation.IntDef;
import android.app.Activity;
import android.app.Instrumentation;
import android.os.Bundle;
@@ -58,6 +59,28 @@ import java.util.concurrent.TimeUnit;
public final class ManualBenchmarkState {
private static final String TAG = ManualBenchmarkState.class.getSimpleName();
+ @IntDef(prefix = {"STATS_REPORT"}, value = {
+ STATS_REPORT_MEDIAN,
+ STATS_REPORT_MEAN,
+ STATS_REPORT_MIN,
+ STATS_REPORT_MAX,
+ STATS_REPORT_PERCENTILE90,
+ STATS_REPORT_PERCENTILE95,
+ STATS_REPORT_STDDEV,
+ STATS_REPORT_ITERATION,
+ })
+ public @interface StatsReport {}
+
+ public static final int STATS_REPORT_MEDIAN = 0x00000001;
+ public static final int STATS_REPORT_MEAN = 0x00000002;
+ public static final int STATS_REPORT_MIN = 0x00000004;
+ public static final int STATS_REPORT_MAX = 0x00000008;
+ public static final int STATS_REPORT_PERCENTILE90 = 0x00000010;
+ public static final int STATS_REPORT_PERCENTILE95 = 0x00000020;
+ public static final int STATS_REPORT_STDDEV = 0x00000040;
+ public static final int STATS_REPORT_COEFFICIENT_VAR = 0x00000080;
+ public static final int STATS_REPORT_ITERATION = 0x00000100;
+
// TODO: Tune these values.
// warm-up for duration
private static final long WARMUP_DURATION_NS = TimeUnit.SECONDS.toNanos(5);
@@ -93,6 +116,13 @@ public final class ManualBenchmarkState {
// The computation needs double precision, but long int is fine for final reporting.
private Stats mStats;
+ private int mStatsReportFlags = STATS_REPORT_MEDIAN | STATS_REPORT_MEAN
+ | STATS_REPORT_PERCENTILE90 | STATS_REPORT_PERCENTILE95 | STATS_REPORT_STDDEV;
+
+ private boolean shouldReport(int statsReportFlag) {
+ return (mStatsReportFlags & statsReportFlag) != 0;
+ }
+
void configure(ManualBenchmarkTest testAnnotation) {
if (testAnnotation == null) {
return;
@@ -106,6 +136,10 @@ public final class ManualBenchmarkState {
if (targetTestDurationNs >= 0) {
mTargetTestDurationNs = targetTestDurationNs;
}
+ final int statsReportFlags = testAnnotation.statsReportFlags();
+ if (statsReportFlags >= 0) {
+ mStatsReportFlags = statsReportFlags;
+ }
}
private void beginBenchmark(long warmupDuration, int iterations) {
@@ -186,12 +220,35 @@ public final class ManualBenchmarkState {
return sb.toString();
}
- private static void fillStatus(Bundle status, String key, Stats stats) {
- status.putLong(key + "_median", stats.getMedian());
- status.putLong(key + "_mean", (long) stats.getMean());
- status.putLong(key + "_percentile90", stats.getPercentile90());
- status.putLong(key + "_percentile95", stats.getPercentile95());
- status.putLong(key + "_stddev", (long) stats.getStandardDeviation());
+ private void fillStatus(Bundle status, String key, Stats stats) {
+ if (shouldReport(STATS_REPORT_ITERATION)) {
+ status.putLong(key + "_iteration", stats.getSize());
+ }
+ if (shouldReport(STATS_REPORT_MEDIAN)) {
+ status.putLong(key + "_median", stats.getMedian());
+ }
+ if (shouldReport(STATS_REPORT_MEAN)) {
+ status.putLong(key + "_mean", Math.round(stats.getMean()));
+ }
+ if (shouldReport(STATS_REPORT_MIN)) {
+ status.putLong(key + "_min", stats.getMin());
+ }
+ if (shouldReport(STATS_REPORT_MAX)) {
+ status.putLong(key + "_max", stats.getMax());
+ }
+ if (shouldReport(STATS_REPORT_PERCENTILE90)) {
+ status.putLong(key + "_percentile90", stats.getPercentile90());
+ }
+ if (shouldReport(STATS_REPORT_PERCENTILE95)) {
+ status.putLong(key + "_percentile95", stats.getPercentile95());
+ }
+ if (shouldReport(STATS_REPORT_STDDEV)) {
+ status.putLong(key + "_stddev", Math.round(stats.getStandardDeviation()));
+ }
+ if (shouldReport(STATS_REPORT_COEFFICIENT_VAR)) {
+ status.putLong(key + "_cv",
+ Math.round((100 * stats.getStandardDeviation() / stats.getMean())));
+ }
}
public void sendFullStatusReport(Instrumentation instrumentation, String key) {
@@ -204,8 +261,9 @@ public final class ManualBenchmarkState {
if (mExtraResults != null) {
for (int i = 0; i < mExtraResults.size(); i++) {
final String subKey = key + "_" + mExtraResults.keyAt(i);
- final Stats stats = new Stats(mExtraResults.valueAt(i));
- Log.i(TAG, summaryLine(subKey, mStats, mResults));
+ final ArrayList<Long> results = mExtraResults.valueAt(i);
+ final Stats stats = new Stats(results);
+ Log.i(TAG, summaryLine(subKey, stats, results));
fillStatus(status, subKey, stats);
}
}
@@ -218,5 +276,6 @@ public final class ManualBenchmarkState {
public @interface ManualBenchmarkTest {
long warmupDurationNs() default -1;
long targetTestDurationNs() default -1;
+ @StatsReport int statsReportFlags() default -1;
}
}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java b/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java
index 5e50073c0674..f650e810c6de 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java
@@ -23,6 +23,7 @@ import java.util.List;
public class Stats {
private long mMedian, mMin, mMax, mPercentile90, mPercentile95;
private double mMean, mStandardDeviation;
+ private final int mSize;
/* Calculate stats in constructor. */
public Stats(List<Long> values) {
@@ -35,6 +36,7 @@ public class Stats {
Collections.sort(values);
+ mSize = size;
mMin = values.get(0);
mMax = values.get(values.size() - 1);
@@ -56,6 +58,10 @@ public class Stats {
mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1));
}
+ public int getSize() {
+ return mSize;
+ }
+
public double getMean() {
return mMean;
}
diff --git a/apex/jobscheduler/README_js-mainline.md b/apex/jobscheduler/README_js-mainline.md
new file mode 100644
index 000000000000..b5fea5e0a4df
--- /dev/null
+++ b/apex/jobscheduler/README_js-mainline.md
@@ -0,0 +1,51 @@
+# Making Job Scheduler into a Mainline Module
+
+## TODOs
+
+See also:
+- http://go/moving-js-code-for-mainline
+- http://go/jobscheduler-code-dependencies-2019-07
+
+- [ ] Move client code
+ - [ ] Move code
+ - [ ] Make build file
+ - [ ] "m jobscheduler-framework" pass
+ - [ ] "m framework" pass
+ - [ ] "m service" pass
+- [ ] Move proto
+ - No, couldn't do it, because it's referred to by incidentd_proto
+- [ ] Move service
+ - [X] Move code (done, but it won't compile yet)
+ - [X] Make build file
+ - [X] "m service" pass
+ - [X] "m jobscheduler-service" pass
+ - To make it pass, jobscheduler-service has to link services.jar too. Many dependencies.
+- [ ] Move this into `frameworks/apex/jobscheduler/...`. Currently it's in `frameworks/base/apex/...`
+because `frameworks/apex/` is not a part of any git projects. (and also working on multiple
+projects is a pain.)
+
+
+## Problems
+- Couldn't move dumpsys proto files. They are used by incidentd_proto, which is in the platform
+ (not updatable).
+ - One idea is *not* to move the proto files into apex but keep them in the platform.
+ Then we make sure to extend the proto files in a backward-compat way (which we do anyway)
+ and always use the latest file from the JS apex.
+
+- There are a lot of build tasks that use "framework.jar". (Examples: hiddenapi-greylist.txt check,
+ update-api / public API check and SDK stub (android.jar) creation)
+ To make the downstream build modules buildable, we need to include js-framework.jar in
+ framework.jar. However it turned out to be tricky because soong has special logic for "framework"
+ and "framework.jar".
+ i.e. Conceptually, we can do it by renaming `framework` to `framework-minus-jobscheduler`, build
+ `jobscheduler-framework` with `framework-minus-jobscheduler`, and create `framework` by merging
+ `framework-minus-jobscheduler` and `jobscheduler-framework`.
+ However it didn't quite work because of the special casing.
+
+- JS-service uses a lot of other code in `services`, so it needs to link services.core.jar e.g.
+ - Common system service code, e.g. `com.android.server.SystemService`
+ - Common utility code, e.g. `FgThread` and `IoThread`
+ - Other system services such as `DeviceIdleController` and `ActivityManagerService`
+ - Server side singleton. `AppStateTracker`
+ - `DeviceIdleController.LocalService`, which is a local service but there's no interface class.
+ - `XxxInternal` interfaces that are not in the framework side. -> We should be able to move them.
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
new file mode 100644
index 000000000000..ca6dc45a356a
--- /dev/null
+++ b/apex/jobscheduler/service/Android.bp
@@ -0,0 +1,15 @@
+// Job Scheduler Service jar, which will eventually be put in the jobscheduler mainline apex.
+// jobscheduler-service needs to be added to PRODUCT_SYSTEM_SERVER_JARS.
+java_library {
+ name: "jobscheduler-service",
+ installable: true,
+
+ srcs: [
+ "java/**/*.java",
+ ],
+
+ libs: [
+ "framework",
+ "services.core",
+ ],
+}
diff --git a/services/core/java/com/android/server/job/GrantedUriPermissions.java b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
index 005b1892f6a6..005b1892f6a6 100644
--- a/services/core/java/com/android/server/job/GrantedUriPermissions.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java
diff --git a/services/core/java/com/android/server/job/JobCompletedListener.java b/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
index 34ba753b3daa..34ba753b3daa 100644
--- a/services/core/java/com/android/server/job/JobCompletedListener.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
diff --git a/services/core/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index bec1947df228..bec1947df228 100644
--- a/services/core/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
index e28e5bd6c53d..e28e5bd6c53d 100644
--- a/services/core/java/com/android/server/job/JobPackageTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index e44e9022bf5d..e44e9022bf5d 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
index e3614413121a..e3614413121a 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 7da128f9d3ec..7da128f9d3ec 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
diff --git a/services/core/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index d69faf37397c..d69faf37397c 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
diff --git a/services/core/java/com/android/server/job/StateChangedListener.java b/apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java
index 87bfc27a715f..87bfc27a715f 100644
--- a/services/core/java/com/android/server/job/StateChangedListener.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/StateChangedListener.java
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index b698e5bf4403..b698e5bf4403 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
index 46658ad33b85..46658ad33b85 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index f8cf6ae04950..f8cf6ae04950 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
index a775cf5a671c..a775cf5a671c 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 127a5c876657..127a5c876657 100644
--- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index e3c311f9e327..e3c311f9e327 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 6f2b33453891..6f2b33453891 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index b8cfac4d4206..b8cfac4d4206 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
index 51be38be990d..51be38be990d 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
diff --git a/services/core/java/com/android/server/job/controllers/StorageController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
index 51187dff4d59..51187dff4d59 100644
--- a/services/core/java/com/android/server/job/controllers/StorageController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
index 4c11947212f9..4c11947212f9 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
diff --git a/services/core/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
index 82c33f548c15..82c33f548c15 100644
--- a/services/core/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/CarIdlenessTracker.java
diff --git a/services/core/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
index a85bd4066ad3..a85bd4066ad3 100644
--- a/services/core/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
diff --git a/services/core/java/com/android/server/job/controllers/idle/IdlenessListener.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessListener.java
index 7ffd7cd3e2e0..7ffd7cd3e2e0 100644
--- a/services/core/java/com/android/server/job/controllers/idle/IdlenessListener.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessListener.java
diff --git a/services/core/java/com/android/server/job/controllers/idle/IdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
index 09f01c2e4113..09f01c2e4113 100644
--- a/services/core/java/com/android/server/job/controllers/idle/IdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/IdlenessTracker.java
diff --git a/api/current.txt b/api/current.txt
index a7b38a5d5b10..870b6ae09d95 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -103,6 +103,7 @@ package android {
field public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field @Deprecated public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
+ field public static final String QUERY_ALL_PACKAGES = "android.permission.QUERY_ALL_PACKAGES";
field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
@@ -2810,6 +2811,14 @@ package android.accessibilityservice {
method public void onClicked(android.accessibilityservice.AccessibilityButtonController);
}
+ public final class AccessibilityGestureInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDisplayId();
+ method public int getGestureId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.accessibilityservice.AccessibilityGestureInfo> CREATOR;
+ }
+
public abstract class AccessibilityService extends android.app.Service {
ctor public AccessibilityService();
method public final void disableSelf();
@@ -2824,7 +2833,8 @@ package android.accessibilityservice {
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
- method protected boolean onGesture(int);
+ method @Deprecated protected boolean onGesture(int);
+ method public boolean onGesture(@NonNull android.accessibilityservice.AccessibilityGestureInfo);
method public abstract void onInterrupt();
method protected boolean onKeyEvent(android.view.KeyEvent);
method protected void onServiceConnected();
@@ -2966,6 +2976,7 @@ package android.accessibilityservice {
}
public final class GestureDescription {
+ method public int getDisplayId();
method public static long getMaxGestureDuration();
method public static int getMaxStrokeCount();
method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(@IntRange(from=0) int);
@@ -2976,6 +2987,7 @@ package android.accessibilityservice {
ctor public GestureDescription.Builder();
method public android.accessibilityservice.GestureDescription.Builder addStroke(@NonNull android.accessibilityservice.GestureDescription.StrokeDescription);
method public android.accessibilityservice.GestureDescription build();
+ method @NonNull public android.accessibilityservice.GestureDescription.Builder setDisplayId(int);
}
public static class GestureDescription.StrokeDescription {
@@ -7165,6 +7177,7 @@ package android.app.assist {
method public android.os.Bundle getExtras();
method public int getHeight();
method public String getHint();
+ method @Nullable public String getHintIdEntry();
method @Nullable public android.view.ViewStructure.HtmlInfo getHtmlInfo();
method public int getId();
method public String getIdEntry();
@@ -11757,6 +11770,9 @@ package android.content.pm {
field public static final String FEATURE_SENSOR_RELATIVE_HUMIDITY = "android.hardware.sensor.relative_humidity";
field public static final String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
field public static final String FEATURE_SENSOR_STEP_DETECTOR = "android.hardware.sensor.stepdetector";
+ field public static final String FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+ field public static final String FEATURE_SE_OMAPI_SD = "android.hardware.se.omapi.sd";
+ field public static final String FEATURE_SE_OMAPI_UICC = "android.hardware.se.omapi.uicc";
field public static final String FEATURE_SIP = "android.software.sip";
field public static final String FEATURE_SIP_VOIP = "android.software.sip.voip";
field public static final String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
@@ -43991,6 +44007,7 @@ package android.telephony {
public class CarrierConfigManager {
method @Nullable public android.os.PersistableBundle getConfig();
+ method @Nullable public android.os.PersistableBundle getConfigByComponentForSubId(String, int);
method @Nullable public android.os.PersistableBundle getConfigForSubId(int);
method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
method public void notifyConfigChangedForSubId(int);
@@ -44168,6 +44185,10 @@ package android.telephony {
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
+ public static final class CarrierConfigManager.Ims {
+ field public static final String KEY_PREFIX = "ims.";
+ }
+
public abstract class CellIdentity implements android.os.Parcelable {
method public int describeContents();
method @Nullable public CharSequence getOperatorAlphaLong();
@@ -44350,6 +44371,7 @@ package android.telephony {
method public int getBitErrorRate();
method public int getDbm();
method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
+ method public int getRssi();
method public int getTimingAdvance();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -51432,6 +51454,7 @@ package android.view {
method public abstract void setFocusable(boolean);
method public abstract void setFocused(boolean);
method public abstract void setHint(CharSequence);
+ method public void setHintIdEntry(@NonNull String);
method public abstract void setHtmlInfo(@NonNull android.view.ViewStructure.HtmlInfo);
method public abstract void setId(int, String, String, String);
method public void setImportantForAutofill(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index b393fccdb366..8e6ff3019b0a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -32,6 +32,14 @@ package android {
}
+package android.accessibilityservice {
+
+ public final class AccessibilityGestureInfo implements android.os.Parcelable {
+ ctor public AccessibilityGestureInfo(int, int);
+ }
+
+}
+
package android.animation {
public class ValueAnimator extends android.animation.Animator {
@@ -3028,6 +3036,7 @@ package android.util {
field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
+ field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
}
public class TimeUtils {
diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING
new file mode 100644
index 000000000000..c1cba5f7f22d
--- /dev/null
+++ b/cmds/locksettings/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsDevicePolicyManagerTestCases",
+ "options": [
+ {
+ "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/config/boot-profile.txt b/config/boot-profile.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/config/boot-profile.txt
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 03e3b82c75f7..ea50999e9d56 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -563,6 +563,7 @@ android.app.job.JobInfo
android.app.job.JobParameters$1
android.app.job.JobParameters
android.app.job.JobScheduler
+android.app.job.JobSchedulerFrameworkInitializer
android.app.job.JobService$1
android.app.job.JobService
android.app.job.JobServiceEngine$JobHandler
diff --git a/config/preloaded-classes-extra b/config/preloaded-classes-extra
index 09f393ad4844..94849fb97433 100644
--- a/config/preloaded-classes-extra
+++ b/config/preloaded-classes-extra
@@ -1,3 +1,6 @@
+# JobSchedulerFrameworkInitializer must always be preloaded because it registers the job scheduler
+# service wrapper to SystemServiceRegistry.
+android.app.job.JobSchedulerFrameworkInitializer
android.icu.impl.coll.CollationRoot
android.icu.impl.IDNA2003
android.icu.impl.number.Parse
diff --git a/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java b/core/java/android/accessibilityservice/AccessibilityGestureInfo.aidl
index f45aad06ac6b..2539051f4069 100644
--- a/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -14,26 +14,6 @@
* limitations under the License.
*/
-package com.android.preload.ui;
+package android.accessibilityservice;
-import com.android.ddmlib.SyncService.ISyncProgressMonitor;
-
-public class NullProgressMonitor implements ISyncProgressMonitor {
-
- @Override
- public void advance(int arg0) {}
-
- @Override
- public boolean isCanceled() {
- return false;
- }
-
- @Override
- public void start(int arg0) {}
-
- @Override
- public void startSubTask(String arg0) {}
-
- @Override
- public void stop() {}
-} \ No newline at end of file
+parcelable AccessibilityGestureInfo;
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureInfo.java b/core/java/android/accessibilityservice/AccessibilityGestureInfo.java
new file mode 100644
index 000000000000..dc50a4c6c633
--- /dev/null
+++ b/core/java/android/accessibilityservice/AccessibilityGestureInfo.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 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 android.accessibilityservice;
+
+
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT_AND_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT_AND_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_LEFT_AND_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT_AND_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT_AND_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_RIGHT_AND_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class describes the gesture information including gesture id and which display it happens
+ * on.
+ * <p>
+ * <strong>Note:</strong> Accessibility services setting the
+ * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
+ * flag can receive gestures.
+ *
+ * @see AccessibilityService#onGesture(AccessibilityGestureInfo)
+ */
+
+public final class AccessibilityGestureInfo implements Parcelable {
+
+ /** @hide */
+ @IntDef(prefix = { "GESTURE_" }, value = {
+ GESTURE_SWIPE_UP,
+ GESTURE_SWIPE_UP_AND_LEFT,
+ GESTURE_SWIPE_UP_AND_DOWN,
+ GESTURE_SWIPE_UP_AND_RIGHT,
+ GESTURE_SWIPE_DOWN,
+ GESTURE_SWIPE_DOWN_AND_LEFT,
+ GESTURE_SWIPE_DOWN_AND_UP,
+ GESTURE_SWIPE_DOWN_AND_RIGHT,
+ GESTURE_SWIPE_LEFT,
+ GESTURE_SWIPE_LEFT_AND_UP,
+ GESTURE_SWIPE_LEFT_AND_RIGHT,
+ GESTURE_SWIPE_LEFT_AND_DOWN,
+ GESTURE_SWIPE_RIGHT,
+ GESTURE_SWIPE_RIGHT_AND_UP,
+ GESTURE_SWIPE_RIGHT_AND_LEFT,
+ GESTURE_SWIPE_RIGHT_AND_DOWN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GestureType {}
+
+ @GestureType
+ private final int mGestureId;
+ private final int mDisplayId;
+
+ /** @hide */
+ @TestApi
+ public AccessibilityGestureInfo(int gestureId, int displayId) {
+ mGestureId = gestureId;
+ mDisplayId = displayId;
+ }
+
+ private AccessibilityGestureInfo(@NonNull Parcel parcel) {
+ mGestureId = parcel.readInt();
+ mDisplayId = parcel.readInt();
+ }
+
+ /**
+ * Returns the display id of the received-gesture display, for use with
+ * {@link android.hardware.display.DisplayManager#getDisplay(int)}.
+ *
+ * @return the display id.
+ */
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ /**
+ * Returns performed gesture id.
+ *
+ * @return the performed gesture id.
+ *
+ */
+ @GestureType public int getGestureId() {
+ return mGestureId;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder("AccessibilityGestureInfo[");
+ stringBuilder.append("gestureId: ").append(mGestureId);
+ stringBuilder.append(", ");
+ stringBuilder.append("displayId: ").append(mDisplayId);
+ stringBuilder.append(']');
+ return stringBuilder.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mGestureId);
+ parcel.writeInt(mDisplayId);
+ }
+
+ /**
+ * @see Parcelable.Creator
+ */
+ public static final @NonNull Parcelable.Creator<AccessibilityGestureInfo> CREATOR =
+ new Parcelable.Creator<AccessibilityGestureInfo>() {
+ public AccessibilityGestureInfo createFromParcel(Parcel parcel) {
+ return new AccessibilityGestureInfo(parcel);
+ }
+
+ public AccessibilityGestureInfo[] newArray(int size) {
+ return new AccessibilityGestureInfo[size];
+ }
+ };
+
+}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 4aafa53805e1..827e5408403a 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -309,7 +309,7 @@ public abstract class AccessibilityService extends Service {
* Name under which an AccessibilityService component publishes information
* about itself. This meta-data must reference an XML resource containing an
* <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
- * tag. This is a a sample XML file configuring an accessibility service:
+ * tag. This is a sample XML file configuring an accessibility service:
* <pre> &lt;accessibility-service
* android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
* android:packageNames="foo.bar, foo.baz"
@@ -381,7 +381,8 @@ public abstract class AccessibilityService extends Service {
void onInterrupt();
void onServiceConnected();
void init(int connectionId, IBinder windowToken);
- boolean onGesture(int gestureId);
+ /** The detected gesture information for different displays */
+ boolean onGesture(AccessibilityGestureInfo gestureInfo);
boolean onKeyEvent(KeyEvent event);
/** Magnification changed callbacks for different displays */
void onMagnificationChanged(int displayId, @NonNull Region region,
@@ -514,17 +515,18 @@ public abstract class AccessibilityService extends Service {
}
/**
- * Called by the system when the user performs a specific gesture on the
- * touch screen.
+ * Called by {@link #onGesture(AccessibilityGestureInfo)} when the user performs a specific
+ * gesture on the default display.
*
* <strong>Note:</strong> To receive gestures an accessibility service must
* request that the device is in touch exploration mode by setting the
- * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
* flag.
*
* @param gestureId The unique id of the performed gesture.
*
* @return Whether the gesture was handled.
+ * @deprecated Override {@link #onGesture(AccessibilityGestureInfo)} instead.
*
* @see #GESTURE_SWIPE_UP
* @see #GESTURE_SWIPE_UP_AND_LEFT
@@ -543,11 +545,36 @@ public abstract class AccessibilityService extends Service {
* @see #GESTURE_SWIPE_RIGHT_AND_LEFT
* @see #GESTURE_SWIPE_RIGHT_AND_DOWN
*/
+ @Deprecated
protected boolean onGesture(int gestureId) {
return false;
}
/**
+ * Called by the system when the user performs a specific gesture on the
+ * specific touch screen.
+ *<p>
+ * <strong>Note:</strong> To receive gestures an accessibility service must
+ * request that the device is in touch exploration mode by setting the
+ * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
+ * flag.
+ *<p>
+ * <strong>Note:</strong> The default implementation calls {@link #onGesture(int)} when the
+ * touch screen is default display.
+ *
+ * @param gestureInfo The information of gesture.
+ *
+ * @return Whether the gesture was handled.
+ *
+ */
+ public boolean onGesture(@NonNull AccessibilityGestureInfo gestureInfo) {
+ if (gestureInfo.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ onGesture(gestureInfo.getGestureId());
+ }
+ return false;
+ }
+
+ /**
* Callback that allows an accessibility service to observe the key events
* before they are passed to the rest of the system. This means that the events
* are first delivered here before they are passed to the device policy, the
@@ -777,8 +804,8 @@ public abstract class AccessibilityService extends Service {
callback, handler);
mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
}
- connection.sendGesture(mGestureStatusCallbackSequence,
- new ParceledListSlice<>(steps));
+ connection.dispatchGesture(mGestureStatusCallbackSequence,
+ new ParceledListSlice<>(steps), gesture.getDisplayId());
}
} catch (RemoteException re) {
throw new RuntimeException(re);
@@ -1673,8 +1700,8 @@ public abstract class AccessibilityService extends Service {
}
@Override
- public boolean onGesture(int gestureId) {
- return AccessibilityService.this.onGesture(gestureId);
+ public boolean onGesture(AccessibilityGestureInfo gestureInfo) {
+ return AccessibilityService.this.onGesture(gestureInfo);
}
@Override
@@ -1773,8 +1800,9 @@ public abstract class AccessibilityService extends Service {
mCaller.sendMessage(message);
}
- public void onGesture(int gestureId) {
- Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId);
+ @Override
+ public void onGesture(AccessibilityGestureInfo gestureInfo) {
+ Message message = mCaller.obtainMessageO(DO_ON_GESTURE, gestureInfo);
mCaller.sendMessage(message);
}
@@ -1887,8 +1915,7 @@ public abstract class AccessibilityService extends Service {
case DO_ON_GESTURE: {
if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
- final int gestureId = message.arg1;
- mCallback.onGesture(gestureId);
+ mCallback.onGesture((AccessibilityGestureInfo) message.obj);
}
} return;
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index a3e7ad5da9b1..3b79d217c513 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -23,6 +23,7 @@ import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.Display;
import com.android.internal.util.Preconditions;
@@ -33,7 +34,7 @@ import java.util.List;
* Accessibility services with the
* {@link android.R.styleable#AccessibilityService_canPerformGestures} property can dispatch
* gestures. This class describes those gestures. Gestures are made up of one or more strokes.
- * Gestures are immutable once built.
+ * Gestures are immutable once built and will be dispatched to the specified display.
* <p>
* Spatial dimensions throughout are in screen pixels. Time is measured in milliseconds.
*/
@@ -48,6 +49,7 @@ public final class GestureDescription {
private final List<StrokeDescription> mStrokes = new ArrayList<>();
private final float[] mTempPos = new float[2];
+ private final int mDisplayId;
/**
* Get the upper limit for the number of strokes a gesture may contain.
@@ -67,10 +69,17 @@ public final class GestureDescription {
return MAX_GESTURE_DURATION_MS;
}
- private GestureDescription() {}
+ private GestureDescription() {
+ this(new ArrayList<>());
+ }
private GestureDescription(List<StrokeDescription> strokes) {
+ this(strokes, Display.DEFAULT_DISPLAY);
+ }
+
+ private GestureDescription(List<StrokeDescription> strokes, int displayId) {
mStrokes.addAll(strokes);
+ mDisplayId = displayId;
}
/**
@@ -94,6 +103,16 @@ public final class GestureDescription {
}
/**
+ * Returns the ID of the display this gesture is sent on, for use with
+ * {@link android.hardware.display.DisplayManager#getDisplay(int)}.
+ *
+ * @return The logical display id.
+ */
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ /**
* Return the smallest key point (where a path starts or ends) that is at least a specified
* offset
* @param offset the minimum start time
@@ -160,9 +179,10 @@ public final class GestureDescription {
public static class Builder {
private final List<StrokeDescription> mStrokes = new ArrayList<>();
+ private int mDisplayId = Display.DEFAULT_DISPLAY;
/**
- * Add a stroke to the gesture description. Up to
+ * Adds a stroke to the gesture description. Up to
* {@link GestureDescription#getMaxStrokeCount()} paths may be
* added to a gesture, and the total gesture duration (earliest path start time to latest
* path end time) may not exceed {@link GestureDescription#getMaxGestureDuration()}.
@@ -187,11 +207,23 @@ public final class GestureDescription {
return this;
}
+ /**
+ * Sets the id of the display to dispatch gestures.
+ *
+ * @param displayId The logical display id
+ *
+ * @return this
+ */
+ public @NonNull Builder setDisplayId(int displayId) {
+ mDisplayId = displayId;
+ return this;
+ }
+
public GestureDescription build() {
if (mStrokes.size() == 0) {
throw new IllegalStateException("Gestures must have at least one stroke");
}
- return new GestureDescription(mStrokes);
+ return new GestureDescription(mStrokes, mDisplayId);
}
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 1dae4fca111e..407ba59c3297 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -20,6 +20,7 @@ import android.accessibilityservice.IAccessibilityServiceConnection;
import android.graphics.Region;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityWindowInfo;
+import android.accessibilityservice.AccessibilityGestureInfo;
import android.view.KeyEvent;
/**
@@ -35,7 +36,7 @@ import android.view.KeyEvent;
void onInterrupt();
- void onGesture(int gesture);
+ void onGesture(in AccessibilityGestureInfo gestureInfo);
void clearAccessibilityCache();
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index c8e01321812c..1ca07dd6ed23 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -95,6 +95,8 @@ interface IAccessibilityServiceConnection {
void sendGesture(int sequence, in ParceledListSlice gestureSteps);
+ void dispatchGesture(int sequence, in ParceledListSlice gestureSteps, int displayId);
+
boolean isFingerprintGestureDetectionAvailable();
IBinder getOverlayWindowToken(int displayid);
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 926044bffdd0..b8d9575f4b0f 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -177,6 +177,13 @@ public class ActivityOptions {
private static final String KEY_LAUNCH_DISPLAY_ID = "android.activity.launchDisplayId";
/**
+ * The id of the display where the caller was on.
+ * @see #setCallerDisplayId(int)
+ * @hide
+ */
+ private static final String KEY_CALLER_DISPLAY_ID = "android.activity.callerDisplayId";
+
+ /**
* The windowing mode the activity should be launched into.
* @hide
*/
@@ -269,6 +276,8 @@ public class ActivityOptions {
= "android:activity.remoteAnimationAdapter";
/** @hide */
+ public static final int ANIM_UNDEFINED = -1;
+ /** @hide */
public static final int ANIM_NONE = 0;
/** @hide */
public static final int ANIM_CUSTOM = 1;
@@ -299,7 +308,7 @@ public class ActivityOptions {
private String mPackageName;
private Rect mLaunchBounds;
- private int mAnimationType = ANIM_NONE;
+ private int mAnimationType = ANIM_UNDEFINED;
private int mCustomEnterResId;
private int mCustomExitResId;
private int mCustomInPlaceResId;
@@ -318,6 +327,7 @@ public class ActivityOptions {
private int mExitCoordinatorIndex;
private PendingIntent mUsageTimeReport;
private int mLaunchDisplayId = INVALID_DISPLAY;
+ private int mCallerDisplayId = INVALID_DISPLAY;
@WindowConfiguration.WindowingMode
private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
@WindowConfiguration.ActivityType
@@ -896,7 +906,7 @@ public class ActivityOptions {
Slog.w(TAG, e);
}
mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS);
- mAnimationType = opts.getInt(KEY_ANIM_TYPE);
+ mAnimationType = opts.getInt(KEY_ANIM_TYPE, ANIM_UNDEFINED);
switch (mAnimationType) {
case ANIM_CUSTOM:
mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
@@ -945,6 +955,7 @@ public class ActivityOptions {
}
mLockTaskMode = opts.getBoolean(KEY_LOCK_TASK_MODE, false);
mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
+ mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY);
mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
@@ -1204,6 +1215,17 @@ public class ActivityOptions {
}
/** @hide */
+ public int getCallerDisplayId() {
+ return mCallerDisplayId;
+ }
+
+ /** @hide */
+ public ActivityOptions setCallerDisplayId(int callerDisplayId) {
+ mCallerDisplayId = callerDisplayId;
+ return this;
+ }
+
+ /** @hide */
public int getLaunchWindowingMode() {
return mLaunchWindowingMode;
}
@@ -1447,7 +1469,9 @@ public class ActivityOptions {
if (mLaunchBounds != null) {
b.putParcelable(KEY_LAUNCH_BOUNDS, mLaunchBounds);
}
- b.putInt(KEY_ANIM_TYPE, mAnimationType);
+ if (mAnimationType != ANIM_UNDEFINED) {
+ b.putInt(KEY_ANIM_TYPE, mAnimationType);
+ }
if (mUsageTimeReport != null) {
b.putParcelable(KEY_USAGE_TIME_REPORT, mUsageTimeReport);
}
@@ -1506,6 +1530,9 @@ public class ActivityOptions {
if (mLaunchDisplayId != INVALID_DISPLAY) {
b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
}
+ if (mCallerDisplayId != INVALID_DISPLAY) {
+ b.putInt(KEY_CALLER_DISPLAY_ID, mCallerDisplayId);
+ }
if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 755f0476d9ba..415ec64dc126 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -386,9 +386,15 @@ public class ActivityView extends ViewGroup {
// Also report this geometry information to InputMethodManagerService.
// TODO(b/115693908): Unify this logic into the above WMS-based one.
+ // TODO(b/138175283): Address the location update when the host of this view is
+ // moving.
final Matrix matrix = new Matrix();
+ final int[] locationOnScreen = new int[2];
+ getLocationOnScreen(locationOnScreen);
+ final int dx = locationOnScreen[0];
+ final int dy = locationOnScreen[1];
matrix.set(getMatrix());
- matrix.postTranslate(x, y);
+ matrix.postTranslate(dx, dy);
mContext.getSystemService(InputMethodManager.class)
.reportActivityView(displayId, matrix);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index fb72e651cebd..d20cc4131261 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -834,9 +834,12 @@ public class AppOpsManager {
public static final int OP_ACCESS_ACCESSIBILITY = 88;
/** @hide Read the device identifiers (IMEI / MEID, IMSI, SIM / Build serial) */
public static final int OP_READ_DEVICE_IDENTIFIERS = 89;
+ /** @hide Query all apps on device, regardless of declarations in the calling app manifest */
+ public static final int OP_QUERY_ALL_PACKAGES = 90;
+
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 90;
+ public static final int _NUM_OP = 91;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1112,6 +1115,8 @@ public class AppOpsManager {
public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
/** @hide Read device identifiers */
public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
+ /** @hide Query all packages on device */
+ public static final String OPSTR_QUERY_ALL_PACKAGES = "android:query_all_packages";
// Warning: If an permission is added here it also has to be added to
// com.android.packageinstaller.permission.utils.EventLogger
@@ -1273,6 +1278,7 @@ public class AppOpsManager {
OP_LEGACY_STORAGE, // LEGACY_STORAGE
OP_ACCESS_ACCESSIBILITY, // ACCESS_ACCESSIBILITY
OP_READ_DEVICE_IDENTIFIERS, // READ_DEVICE_IDENTIFIERS
+ OP_QUERY_ALL_PACKAGES, // QUERY_ALL_PACKAGES
};
/**
@@ -1369,6 +1375,7 @@ public class AppOpsManager {
OPSTR_LEGACY_STORAGE,
OPSTR_ACCESS_ACCESSIBILITY,
OPSTR_READ_DEVICE_IDENTIFIERS,
+ OPSTR_QUERY_ALL_PACKAGES,
};
/**
@@ -1466,6 +1473,7 @@ public class AppOpsManager {
"LEGACY_STORAGE",
"ACCESS_ACCESSIBILITY",
"READ_DEVICE_IDENTIFIERS",
+ "QUERY_ALL_PACKAGES",
};
/**
@@ -1564,6 +1572,7 @@ public class AppOpsManager {
null, // no permission for OP_LEGACY_STORAGE
null, // no permission for OP_ACCESS_ACCESSIBILITY
null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS
+ null, // no permission for OP_QUERY_ALL_PACKAGES
};
/**
@@ -1662,6 +1671,7 @@ public class AppOpsManager {
null, // LEGACY_STORAGE
null, // ACCESS_ACCESSIBILITY
null, // READ_DEVICE_IDENTIFIERS
+ null, // QUERY_ALL_PACKAGES
};
/**
@@ -1759,6 +1769,7 @@ public class AppOpsManager {
false, // LEGACY_STORAGE
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
+ false, // QUERY_ALL_PACKAGES
};
/**
@@ -1855,6 +1866,7 @@ public class AppOpsManager {
AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE
AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY
AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS
+ AppOpsManager.MODE_DEFAULT, // QUERY_ALL_PACKAGES
};
/**
@@ -1955,6 +1967,7 @@ public class AppOpsManager {
false, // LEGACY_STORAGE
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
+ false, // QUERY_ALL_PACKAGES
};
/**
diff --git a/core/java/android/app/JobSchedulerImpl.java b/core/java/android/app/JobSchedulerImpl.java
index e8770185305c..924a70809747 100644
--- a/core/java/android/app/JobSchedulerImpl.java
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -26,6 +26,9 @@ import android.os.RemoteException;
import java.util.List;
+
+// APEX NOTE: Class path referred to by robolectric, so can't move it.
+
/**
* Concrete implementation of the JobScheduler interface
* @hide
@@ -33,7 +36,7 @@ import java.util.List;
public class JobSchedulerImpl extends JobScheduler {
IJobScheduler mBinder;
- /* package */ JobSchedulerImpl(IJobScheduler binder) {
+ public JobSchedulerImpl(IJobScheduler binder) {
mBinder = binder;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5aa1f8f07f60..372eab259f4c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5437,10 +5437,11 @@ public class Notification implements Parcelable
/**
* Construct a RemoteViews for the display in public contexts like on the lockscreen.
*
+ * @param isLowPriority is this notification low priority
* @hide
*/
@UnsupportedAppUsage
- public RemoteViews makePublicContentView() {
+ public RemoteViews makePublicContentView(boolean isLowPriority) {
if (mN.publicVersion != null) {
final Builder builder = recoverBuilder(mContext, mN.publicVersion);
return builder.createContentView();
@@ -5467,7 +5468,11 @@ public class Notification implements Parcelable
}
mN.extras = publicExtras;
RemoteViews view;
- view = makeNotificationHeader();
+ StandardTemplateParams params = mParams.reset().fillTextsFrom(this);
+ if (isLowPriority) {
+ params.forceDefaultColor();
+ }
+ view = makeNotificationHeader(params);
view.setBoolean(R.id.notification_header, "setExpandOnlyOnButton", true);
mN.extras = savedBundle;
mN.mLargeIcon = largeIcon;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 6f7a0607cbdb..4b4a071ecf72 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -893,6 +893,17 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ?
intent.resolveTypeIfNeeded(context.getContentResolver())
: null;
+
+ if (context != null && isActivity()) {
+ // Set the context display id as preferred for this activity launches, so that it
+ // can land on caller's display. Or just brought the task to front at the display
+ // where it was on since it has higher preference.
+ ActivityOptions activityOptions = options != null ? new ActivityOptions(options)
+ : ActivityOptions.makeBasic();
+ activityOptions.setCallerDisplayId(context.getDisplayId());
+ options = activityOptions.toBundle();
+ }
+
return ActivityManager.getService().sendIntentSender(
mTarget, mWhitelistToken, code, intent, resolvedType,
onFinished != null
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index cfe2cf09ae19..5034b535944c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -23,8 +23,6 @@ import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.app.contentsuggestions.ContentSuggestionsManager;
import android.app.contentsuggestions.IContentSuggestionsManager;
-import android.app.job.IJobScheduler;
-import android.app.job.JobScheduler;
import android.app.prediction.AppPredictionManager;
import android.app.role.RoleControllerManager;
import android.app.role.RoleManager;
@@ -198,12 +196,15 @@ import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.policy.PhoneLayoutInflater;
import java.util.Map;
+import java.util.function.Function;
/**
* Manages all of the system services that can be returned by {@link Context#getSystemService}.
* Used by {@link ContextImpl}.
+ *
+ * @hide
*/
-final class SystemServiceRegistry {
+public final class SystemServiceRegistry {
private static final String TAG = "SystemServiceRegistry";
// Service registry information.
@@ -979,14 +980,6 @@ final class SystemServiceRegistry {
return new NetworkStatsManager(ctx.getOuterContext());
}});
- registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
- new StaticServiceFetcher<JobScheduler>() {
- @Override
- public JobScheduler createService() throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(Context.JOB_SCHEDULER_SERVICE);
- return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
- }});
-
registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class,
new StaticServiceFetcher<PersistentDataBlockManager>() {
@Override
@@ -1324,6 +1317,22 @@ final class SystemServiceRegistry {
}
/**
+ * APEX modules will use it to register their service wrapper.
+ *
+ * @hide
+ */
+ public static <T> void registerStaticService(String serviceName, Class<T> serviceClass,
+ Function<IBinder, T> serviceFetcher) {
+ registerService(serviceName, serviceClass,
+ new StaticServiceFetcher<T>() {
+ @Override
+ public T createService() throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(serviceName);
+ return serviceFetcher.apply(b);
+ }});
+ }
+
+ /**
* Base interface for classes that fetch services.
* These objects must only be created during static initialization.
*/
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 3935628b707f..2b74b99c8071 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -16,6 +16,7 @@
package android.app;
+import android.accessibilityservice.AccessibilityGestureInfo;
import android.accessibilityservice.AccessibilityService.Callbacks;
import android.accessibilityservice.AccessibilityService.IAccessibilityServiceClientWrapper;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -1232,7 +1233,7 @@ public final class UiAutomation {
}
@Override
- public boolean onGesture(int gestureId) {
+ public boolean onGesture(AccessibilityGestureInfo gestureInfo) {
/* do nothing */
return false;
}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 3fca3118c9a0..86e768db3c52 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -641,6 +641,7 @@ public class AssistStructure implements Parcelable {
int mMaxEms = -1;
int mMaxLength = -1;
@Nullable String mTextIdEntry;
+ @Nullable String mHintIdEntry;
@AutofillImportance int mImportantForAutofill;
// POJO used to override some autofill-related values when the node is parcelized.
@@ -688,18 +689,19 @@ public class AssistStructure implements Parcelable {
static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
static final int FLAGS_ALL_CONTROL = 0xfff00000;
- static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID = 0x001;
- static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID = 0x002;
- static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE = 0x004;
- static final int AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE = 0x008;
- static final int AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS = 0x010;
- static final int AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS = 0x020;
- static final int AUTOFILL_FLAGS_HAS_HTML_INFO = 0x040;
- static final int AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY = 0x080;
- static final int AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS = 0x100;
- static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS = 0x200;
- static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH = 0x400;
- static final int AUTOFILL_FLAGS_HAS_AUTOFILL_SESSION_ID = 0x800;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID = 0x0001;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID = 0x0002;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE = 0x0004;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE = 0x0008;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS = 0x0010;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS = 0x0020;
+ static final int AUTOFILL_FLAGS_HAS_HTML_INFO = 0x0040;
+ static final int AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY = 0x0080;
+ static final int AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS = 0x0100;
+ static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS = 0x0200;
+ static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH = 0x0400;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_SESSION_ID = 0x0800;
+ static final int AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY = 0x1000;
int mFlags;
int mAutofillFlags;
@@ -786,6 +788,9 @@ public class AssistStructure implements Parcelable {
if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
mTextIdEntry = preader.readString();
}
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY) != 0) {
+ mHintIdEntry = preader.readString();
+ }
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
mX = in.readInt();
@@ -934,6 +939,9 @@ public class AssistStructure implements Parcelable {
if (mTextIdEntry != null) {
autofillFlags |= AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY;
}
+ if (mHintIdEntry != null) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY;
+ }
pwriter.writeString(mClassName);
@@ -1011,6 +1019,9 @@ public class AssistStructure implements Parcelable {
if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
pwriter.writeString(mTextIdEntry);
}
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_HINT_ID_ENTRY) != 0) {
+ pwriter.writeString(mHintIdEntry);
+ }
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
out.writeInt(mX);
@@ -1586,6 +1597,17 @@ public class AssistStructure implements Parcelable {
}
/**
+ * Gets the identifier used to set the hint associated with this view.
+ *
+ * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
+ * not for assist purposes.
+ */
+ @Nullable
+ public String getHintIdEntry() {
+ return mHintIdEntry;
+ }
+
+ /**
* Return a Bundle containing optional vendor-specific extension information.
*/
public Bundle getExtras() {
@@ -1853,6 +1875,11 @@ public class AssistStructure implements Parcelable {
}
@Override
+ public void setHintIdEntry(@NonNull String entryName) {
+ mNode.mHintIdEntry = Preconditions.checkNotNull(entryName);
+ }
+
+ @Override
public CharSequence getText() {
return mNode.mText != null ? mNode.mText.mText : null;
}
@@ -2266,6 +2293,7 @@ public class AssistStructure implements Parcelable {
String hint = node.getHint();
if (hint != null) {
Log.i(TAG, prefix + " Hint: " + hint);
+ Log.i(TAG, prefix + " Resource id: " + node.getHintIdEntry());
}
Bundle extras = node.getExtras();
if (extras != null) {
diff --git a/core/java/android/app/job/JobSchedulerFrameworkInitializer.java b/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
new file mode 100644
index 000000000000..cf2979c96191
--- /dev/null
+++ b/core/java/android/app/job/JobSchedulerFrameworkInitializer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 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 android.app.job;
+
+import android.app.JobSchedulerImpl;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+
+/**
+ * This class needs to be pre-loaded by zygote. This is where the job scheduler service wrapper
+ * is registered.
+ *
+ * @hide
+ */
+public class JobSchedulerFrameworkInitializer {
+ static {
+ SystemServiceRegistry.registerStaticService(
+ Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
+ (b) -> new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b)));
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 591c418c936e..36f3a1eeba79 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -441,6 +441,43 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
+ * Checks whether a value set presented by a bitmask has zero or single bit
+ *
+ * @param valueSet the value set presented by a bitmask
+ * @return true if the valueSet contains zero or single bit, otherwise false.
+ */
+ private static boolean hasSingleBit(int valueSet) {
+ return (valueSet == 0 || (valueSet & (valueSet - 1)) == 0);
+ }
+
+ /**
+ * Checks whether the object contains none or single sample rate.
+ *
+ * @return true if the object contains none or single sample rate, otherwise false.
+ */
+ public boolean hasSingleSampleRate() {
+ return hasSingleBit(mSampleRate);
+ }
+
+ /**
+ * Checks whether the object contains none or single bits per sample.
+ *
+ * @return true if the object contains none or single bits per sample, otherwise false.
+ */
+ public boolean hasSingleBitsPerSample() {
+ return hasSingleBit(mBitsPerSample);
+ }
+
+ /**
+ * Checks whether the object contains none or single channel mode.
+ *
+ * @return true if the object contains none or single channel mode, otherwise false.
+ */
+ public boolean hasSingleChannelMode() {
+ return hasSingleBit(mChannelMode);
+ }
+
+ /**
* Checks whether the audio feeding parameters are same.
*
* @param other the codec config to compare against
@@ -451,4 +488,58 @@ public final class BluetoothCodecConfig implements Parcelable {
&& other.mBitsPerSample == mBitsPerSample
&& other.mChannelMode == mChannelMode);
}
+
+ /**
+ * Checks whether another codec config has the similar feeding parameters.
+ * Any parameters with NONE value will be considered to be a wildcard matching.
+ *
+ * @param other the codec config to compare against
+ * @return true if the audio feeding parameters are similar, otherwise false.
+ */
+ public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) {
+ if (other == null || mCodecType != other.mCodecType) {
+ return false;
+ }
+ int sampleRate = other.mSampleRate;
+ if (mSampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE
+ || sampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE) {
+ sampleRate = mSampleRate;
+ }
+ int bitsPerSample = other.mBitsPerSample;
+ if (mBitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE
+ || bitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
+ bitsPerSample = mBitsPerSample;
+ }
+ int channelMode = other.mChannelMode;
+ if (mChannelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE
+ || channelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE) {
+ channelMode = mChannelMode;
+ }
+ return sameAudioFeedingParameters(new BluetoothCodecConfig(
+ mCodecType, /* priority */ 0, sampleRate, bitsPerSample, channelMode,
+ /* specific1 */ 0, /* specific2 */ 0, /* specific3 */ 0,
+ /* specific4 */ 0));
+ }
+
+ /**
+ * Checks whether the codec specific parameters are the same.
+ *
+ * @param other the codec config to compare against
+ * @return true if the codec specific parameters are the same, otherwise false.
+ */
+ public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) {
+ if (other == null && mCodecType != other.mCodecType) {
+ return false;
+ }
+ // Currently we only care about the LDAC Playback Quality at CodecSpecific1
+ switch (mCodecType) {
+ case SOURCE_CODEC_TYPE_LDAC:
+ if (mCodecSpecific1 != other.mCodecSpecific1) {
+ return false;
+ }
+ // fall through
+ default:
+ return true;
+ }
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
index 58b6aeae6398..58a764a85bed 100644
--- a/core/java/android/bluetooth/BluetoothCodecStatus.java
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -89,6 +89,43 @@ public final class BluetoothCodecStatus implements Parcelable {
return Arrays.asList(c1).containsAll(Arrays.asList(c2));
}
+ /**
+ * Checks whether the codec config matches the selectable capabilities.
+ * Any parameters of the codec config with NONE value will be considered a wildcard matching.
+ *
+ * @param codecConfig the codec config to compare against
+ * @return true if the codec config matches, otherwise false
+ */
+ public boolean isCodecConfigSelectable(BluetoothCodecConfig codecConfig) {
+ if (codecConfig == null || !codecConfig.hasSingleSampleRate()
+ || !codecConfig.hasSingleBitsPerSample() || !codecConfig.hasSingleChannelMode()) {
+ return false;
+ }
+ for (BluetoothCodecConfig selectableConfig : mCodecsSelectableCapabilities) {
+ if (codecConfig.getCodecType() != selectableConfig.getCodecType()) {
+ continue;
+ }
+ int sampleRate = codecConfig.getSampleRate();
+ if ((sampleRate & selectableConfig.getSampleRate()) == 0
+ && sampleRate != BluetoothCodecConfig.SAMPLE_RATE_NONE) {
+ continue;
+ }
+ int bitsPerSample = codecConfig.getBitsPerSample();
+ if ((bitsPerSample & selectableConfig.getBitsPerSample()) == 0
+ && bitsPerSample != BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
+ continue;
+ }
+ int channelMode = codecConfig.getChannelMode();
+ if ((channelMode & selectableConfig.getChannelMode()) == 0
+ && channelMode != BluetoothCodecConfig.CHANNEL_MODE_NONE) {
+ continue;
+ }
+ return true;
+ }
+ return false;
+ }
+
+
@Override
public int hashCode() {
return Objects.hash(mCodecConfig, mCodecsLocalCapabilities,
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 05833b5f571d..5d00f09501b0 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -126,6 +126,17 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
"android.bluetooth.headsetclient.profile.action.RESULT";
/**
+ * Intent that notifies about vendor specific event arrival. Events not defined in
+ * HFP spec will be matched with supported vendor event list and this intent will
+ * be broadcasted upon a match. Supported vendor events are of format of
+ * of "+eventCode" or "+eventCode=xxxx" or "+eventCode:=xxxx".
+ * Vendor event can be a response to an vendor specific command or unsolicited.
+ *
+ */
+ public static final String ACTION_VENDOR_SPECIFIC_HEADSETCLIENT_EVENT =
+ "android.bluetooth.headsetclient.profile.action.VENDOR_SPECIFIC_EVENT";
+
+ /**
* Intent that notifies about the number attached to the last voice tag
* recorded on AG.
*
@@ -243,6 +254,28 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
public static final String EXTRA_CME_CODE =
"android.bluetooth.headsetclient.extra.CME_CODE";
+ /**
+ * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
+ * indicates vendor ID.
+ */
+ public static final String EXTRA_VENDOR_ID =
+ "android.bluetooth.headsetclient.extra.VENDOR_ID";
+
+ /**
+ * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
+ * indicates vendor event code.
+ */
+ public static final String EXTRA_VENDOR_EVENT_CODE =
+ "android.bluetooth.headsetclient.extra.VENDOR_EVENT_CODE";
+
+ /**
+ * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
+ * contains full vendor event including event code and full arguments.
+ */
+ public static final String EXTRA_VENDOR_EVENT_FULL_ARGS =
+ "android.bluetooth.headsetclient.extra.VENDOR_EVENT_FULL_ARGS";
+
+
/* Extras for AG_FEATURES, extras type is boolean */
// TODO verify if all of those are actually useful
/**
@@ -588,6 +621,31 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
}
/**
+ * Send vendor specific AT command.
+ *
+ * @param device remote device
+ * @param vendorId vendor number by Bluetooth SIG
+ * @param atCommand command to be sent. It start with + prefix and only one command at one time.
+ * @return <code>true</code> if command has been issued successfully; <code>false</code>
+ * otherwise.
+ */
+ public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId,
+ String atCommand) {
+ if (DBG) log("sendVendorSpecificCommand()");
+ final IBluetoothHeadsetClient service =
+ getService();
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return service.sendVendorAtCommand(device, vendorId, atCommand);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
* Stops voice recognition.
*
* @param device remote device
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4d8a0c46508e..895eba6cdec2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2044,6 +2044,30 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports Open Mobile API capable UICC-based secure
+ * elements.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SE_OMAPI_UICC = "android.hardware.se.omapi.uicc";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports Open Mobile API capable eSE-based secure
+ * elements.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports Open Mobile API capable SD-based secure
+ * elements.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SE_OMAPI_SD = "android.hardware.se.omapi.sd";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports the OpenGL ES
* <a href="http://www.khronos.org/registry/gles/extensions/ANDROID/ANDROID_extension_pack_es31a.txt">
* Android Extension Pack</a>.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e690a7fd783b..a4933ef1703f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -66,6 +66,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
@@ -2445,6 +2446,8 @@ public class PackageParser {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
+ } else if (tagName.equals("queries")) {
+ parseQueries(pkg, res, parser, flags, outError);
} else {
Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+ " at " + mArchiveSourcePath + " "
@@ -3538,6 +3541,9 @@ public class PackageParser {
owner.mRequiredAccountType = requiredAccountType;
}
+ owner.mForceQueryable =
+ sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false);
+
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
false)) {
@@ -3953,7 +3959,6 @@ public class PackageParser {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL;
}
XmlUtils.skipCurrentTag(parser);
-
} else {
if (!RIGID_PARSER) {
Slog.w(TAG, "Unknown element under <application>: " + tagName
@@ -4000,6 +4005,67 @@ public class PackageParser {
return true;
}
+ private boolean parseQueries(Package owner, Resources res, XmlResourceParser parser, int flags,
+ String[] outError)
+ throws IOException, XmlPullParserException {
+
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (parser.getName().equals("intent")) {
+ QueriesIntentInfo intentInfo = new QueriesIntentInfo();
+ if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
+ intentInfo, outError)) {
+ return false;
+ }
+ Intent intent = new Intent();
+ if (intentInfo.countActions() != 1) {
+ outError[0] = "intent tags must contain exactly one action.";
+ return false;
+ }
+ intent.setAction(intentInfo.getAction(0));
+ for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
+ intent.addCategory(intentInfo.getCategory(i));
+ }
+ Uri data = null;
+ String dataType = null;
+ if (intentInfo.countDataTypes() > 1) {
+ outError[0] = "intent tag may have at most one data type.";
+ return false;
+ }
+ if (intentInfo.countDataSchemes() > 1) {
+ outError[0] = "intent tag may have at most one data scheme.";
+ return false;
+ }
+ if (intentInfo.countDataTypes() == 1) {
+ data = Uri.fromParts(intentInfo.getDataType(0), "", null);
+ }
+ if (intentInfo.countDataSchemes() == 1) {
+ dataType = intentInfo.getDataScheme(0);
+ }
+ intent.setDataAndType(data, dataType);
+ owner.mQueriesIntents = ArrayUtils.add(owner.mQueriesIntents, intent);
+ } else if (parser.getName().equals("package")) {
+ final TypedArray sa = res.obtainAttributes(parser,
+ com.android.internal.R.styleable.AndroidManifestQueriesPackage);
+ final String packageName =
+ sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
+ if (TextUtils.isEmpty(packageName)) {
+ outError[0] = "Package name is missing from package tag.";
+ return false;
+ }
+ owner.mQueriesPackages =
+ ArrayUtils.add(owner.mQueriesPackages, packageName.intern());
+ }
+ }
+ return true;
+ }
+
/**
* Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
*/
@@ -6514,6 +6580,9 @@ public class PackageParser {
// The major version code declared for this package.
public int mVersionCodeMajor;
+ // Whether the package declares that it should be queryable by all normal apps on device.
+ public boolean mForceQueryable;
+
// Return long containing mVersionCode and mVersionCodeMajor.
public long getLongVersionCode() {
return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
@@ -6619,6 +6688,9 @@ public class PackageParser {
/** Whether or not the package is a stub and must be replaced by the full version. */
public boolean isStub;
+ public ArrayList<String> mQueriesPackages;
+ public ArrayList<Intent> mQueriesIntents;
+
@UnsupportedAppUsage
public Package(String packageName) {
this.packageName = packageName;
@@ -7122,6 +7194,9 @@ public class PackageParser {
use32bitAbi = (dest.readInt() == 1);
restrictUpdateHash = dest.createByteArray();
visibleToInstantApps = dest.readInt() == 1;
+ mForceQueryable = dest.readBoolean();
+ mQueriesIntents = dest.createTypedArrayList(Intent.CREATOR);
+ mQueriesPackages = dest.createStringArrayList();
}
private static void internStringArrayList(List<String> list) {
@@ -7247,6 +7322,9 @@ public class PackageParser {
dest.writeInt(use32bitAbi ? 1 : 0);
dest.writeByteArray(restrictUpdateHash);
dest.writeInt(visibleToInstantApps ? 1 : 0);
+ dest.writeBoolean(mForceQueryable);
+ dest.writeTypedList(mQueriesIntents);
+ dest.writeList(mQueriesPackages);
}
@@ -8257,6 +8335,8 @@ public class PackageParser {
}
}
+ public static final class QueriesIntentInfo extends IntentInfo {}
+
public final static class ActivityIntentInfo extends IntentInfo {
@UnsupportedAppUsage
public Activity activity;
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index af66dc161343..d8110f33d723 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -129,6 +129,25 @@ public class BiometricManager {
}
/**
+ * @hide
+ * @param userId
+ * @return
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public boolean hasEnrolledBiometrics(int userId) {
+ if (mService != null) {
+ try {
+ return mService.hasEnrolledBiometrics(userId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Remote exception in hasEnrolledBiometrics(): " + e);
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Listens for changes to biometric eligibility on keyguard from user settings.
* @param callback
* @hide
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 18c14cb835a8..f0a0b2f0235f 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -42,6 +42,9 @@ interface IBiometricService {
// Checks if biometrics can be used.
int canAuthenticate(String opPackageName, int userId);
+ // Checks if any biometrics are enrolled.
+ boolean hasEnrolledBiometrics(int userId);
+
// Register callback for when keyguard biometric eligibility changes.
void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index 623d5ec434fe..f4fd1b6fb75f 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -369,6 +369,33 @@ public final class ProgramList implements AutoCloseable {
public boolean areModificationsExcluded() {
return mExcludeModifications;
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIdentifierTypes, mIdentifiers, mIncludeCategories,
+ mExcludeModifications);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof Filter)) return false;
+ Filter other = (Filter) obj;
+
+ if (mIncludeCategories != other.mIncludeCategories) return false;
+ if (mExcludeModifications != other.mExcludeModifications) return false;
+ if (!Objects.equals(mIdentifierTypes, other.mIdentifierTypes)) return false;
+ if (!Objects.equals(mIdentifiers, other.mIdentifiers)) return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "Filter [mIdentifierTypes=" + mIdentifierTypes
+ + ", mIdentifiers=" + mIdentifiers
+ + ", mIncludeCategories=" + mIncludeCategories
+ + ", mExcludeModifications=" + mExcludeModifications + "]";
+ }
}
/**
@@ -436,5 +463,24 @@ public final class ProgramList implements AutoCloseable {
public @NonNull Set<ProgramSelector.Identifier> getRemoved() {
return mRemoved;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof Chunk)) return false;
+ Chunk other = (Chunk) obj;
+
+ if (mPurge != other.mPurge) return false;
+ if (mComplete != other.mComplete) return false;
+ if (!Objects.equals(mModified, other.mModified)) return false;
+ if (!Objects.equals(mRemoved, other.mRemoved)) return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "Chunk [mPurge=" + mPurge + ", mComplete=" + mComplete
+ + ", mModified=" + mModified + ", mRemoved=" + mRemoved + "]";
+ }
}
}
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index b60c13631edd..c135c8a73abc 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -258,6 +258,11 @@ public final class RadioMetadata implements Parcelable {
private final Bundle mBundle;
@Override
+ public int hashCode() {
+ return mBundle.hashCode();
+ }
+
+ @Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof RadioMetadata)) return false;
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 8355e08b6aa8..2a4576adf192 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -581,12 +581,16 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
if (data == null) return null;
MemoryFile file = new MemoryFile(name, data.length);
- if (data.length > 0) {
- file.writeBytes(data, 0, 0, data.length);
+ try {
+ if (data.length > 0) {
+ file.writeBytes(data, 0, 0, data.length);
+ }
+ file.deactivate();
+ FileDescriptor fd = file.getFileDescriptor();
+ return fd != null ? ParcelFileDescriptor.dup(fd) : null;
+ } finally {
+ file.close();
}
- file.deactivate();
- FileDescriptor fd = file.getFileDescriptor();
- return fd != null ? ParcelFileDescriptor.dup(fd) : null;
}
/**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 5a9ab3811498..6aef5a5cf2a5 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -40,6 +40,7 @@ public class FeatureFlagUtils {
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
+ public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -56,6 +57,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true");
+ DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
}
/**
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 956161acd762..955be8d40c47 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -77,6 +77,21 @@ interface IRecentsAnimationController {
void hideCurrentInputMethod();
/**
+ * This call is deprecated, use #setDeferCancelUntilNextTransition() instead
+ * TODO(138144750): Remove this method once there are no callers
+ * @deprecated
+ */
+ void setCancelWithDeferredScreenshot(boolean screenshot);
+
+ /**
+ * Clean up the screenshot of previous task which was created during recents animation that
+ * was cancelled by a stack order change.
+ *
+ * @see {@link IRecentsAnimationRunner#onAnimationCanceled}
+ */
+ void cleanupScreenshot();
+
+ /**
* Set a state for controller whether would like to cancel recents animations with deferred
* task screenshot presentation.
*
@@ -86,22 +101,23 @@ interface IRecentsAnimationController {
* screenshot, so that Launcher can still control the leash lifecycle & make the next app
* transition animate smoothly without flickering.
*
- * @param screenshot When set {@code true}, means recents animation will be canceled when the
- * next app launch. System will take previous task's screenshot when the next
- * app transition starting, and skip previous task's animation.
- * Set {@code false} means will not take screenshot & skip animation
- * for previous task.
+ * @param defer When set {@code true}, means that the recents animation will defer canceling the
+ * animation when a stack order change is triggered until the subsequent app
+ * transition start and skip previous task's animation.
+ * When set to {@code false}, means that the recents animation will be canceled
+ * immediately when the stack order changes.
+ * @param screenshot When set {@code true}, means that the system will take previous task's
+ * screenshot and replace the contents of the leash with it when the next app
+ * transition starting. The runner must call #cleanupScreenshot() to end the
+ * recents animation.
+ * When set to {@code false}, means that the system will simply wait for the
+ * next app transition start to immediately cancel the recents animation. This
+ * can be useful when you want an immediate transition into a state where the
+ * task is shown in the home/recents activity (without waiting for a
+ * screenshot).
*
* @see #cleanupScreenshot()
* @see IRecentsAnimationRunner#onCancelled
*/
- void setCancelWithDeferredScreenshot(boolean screenshot);
-
- /**
- * Clean up the screenshot of previous task which was created during recents animation that
- * was cancelled by a stack order change.
- *
- * @see {@link IRecentsAnimationRunner#onAnimationCanceled}
- */
- void cleanupScreenshot();
+ void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot);
}
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 9c652a8d990b..6cda60c80b7d 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -36,7 +36,7 @@ oneway interface IRecentsAnimationRunner {
* @param deferredWithScreenshot If set to {@code true}, the contents of the task will be
* replaced with a screenshot, such that the runner's leash is
* still active. As soon as the runner doesn't need the leash
- * anymore, it can call
+ * anymore, it must call
* {@link IRecentsAnimationController#cleanupScreenshot).
*
* @see {@link RecentsAnimationController#cleanupScreenshot}
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index bff3a1dba3f4..bd865c063055 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1471,6 +1471,10 @@ public final class MotionEvent extends InputEvent implements Parcelable {
@UnsupportedAppUsage
private static final int HISTORY_CURRENT = -0x80000000;
+ // This is essentially the same as native AMOTION_EVENT_INVALID_CURSOR_POSITION as they're all
+ // NaN and we use isnan() everywhere to check validity.
+ private static final float INVALID_CURSOR_POSITION = Float.NaN;
+
private static final int MAX_RECYCLED = 10;
private static final Object gRecyclerLock = new Object();
private static int gRecyclerUsed;
@@ -1590,6 +1594,12 @@ public final class MotionEvent extends InputEvent implements Parcelable {
@CriticalNative
private static native float nativeGetYPrecision(long nativePtr);
@CriticalNative
+ private static native float nativeGetXCursorPosition(long nativePtr);
+ @CriticalNative
+ private static native float nativeGetYCursorPosition(long nativePtr);
+ @CriticalNative
+ private static native void nativeSetCursorPosition(long nativePtr, float x, float y);
+ @CriticalNative
private static native long nativeGetDownTimeNanos(long nativePtr);
@CriticalNative
private static native void nativeSetDownTimeNanos(long nativePtr, long downTime);
@@ -1674,12 +1684,11 @@ public final class MotionEvent extends InputEvent implements Parcelable {
float xPrecision, float yPrecision, int deviceId,
int edgeFlags, int source, int displayId, int flags) {
MotionEvent ev = obtain();
- ev.mNativePtr = nativeInitialize(ev.mNativePtr,
- deviceId, source, displayId, action, flags, edgeFlags, metaState, buttonState,
- CLASSIFICATION_NONE, 0, 0, xPrecision, yPrecision,
+ final boolean success = ev.initialize(deviceId, source, displayId, action, flags, edgeFlags,
+ metaState, buttonState, CLASSIFICATION_NONE, 0, 0, xPrecision, yPrecision,
downTime * NS_PER_MS, eventTime * NS_PER_MS,
pointerCount, pointerProperties, pointerCoords);
- if (ev.mNativePtr == 0) {
+ if (!success) {
Log.e(TAG, "Could not initialize MotionEvent");
ev.recycle();
return null;
@@ -1859,8 +1868,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
pc[0].pressure = pressure;
pc[0].size = size;
- ev.mNativePtr = nativeInitialize(ev.mNativePtr,
- deviceId, source, displayId,
+ ev.initialize(deviceId, source, displayId,
action, 0, edgeFlags, metaState, 0 /*buttonState*/, CLASSIFICATION_NONE,
0, 0, xPrecision, yPrecision,
downTime * NS_PER_MS, eventTime * NS_PER_MS,
@@ -1958,6 +1966,22 @@ public final class MotionEvent extends InputEvent implements Parcelable {
return ev;
}
+ private boolean initialize(int deviceId, int source, int displayId, int action, int flags,
+ int edgeFlags, int metaState, int buttonState, @Classification int classification,
+ float xOffset, float yOffset, float xPrecision, float yPrecision,
+ long downTimeNanos, long eventTimeNanos,
+ int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords) {
+ mNativePtr = nativeInitialize(mNativePtr, deviceId, source, displayId, action, flags,
+ edgeFlags, metaState, buttonState, classification, xOffset, yOffset,
+ xPrecision, yPrecision, downTimeNanos, eventTimeNanos, pointerCount, pointerIds,
+ pointerCoords);
+ if (mNativePtr == 0) {
+ return false;
+ }
+ updateCursorPosition();
+ return true;
+ }
+
/** @hide */
@Override
@UnsupportedAppUsage
@@ -2015,7 +2039,11 @@ public final class MotionEvent extends InputEvent implements Parcelable {
/** {@inheritDoc} */
@Override
public final void setSource(int source) {
+ if (source == getSource()) {
+ return;
+ }
nativeSetSource(mNativePtr, source);
+ updateCursorPosition();
}
/** @hide */
@@ -2670,6 +2698,39 @@ public final class MotionEvent extends InputEvent implements Parcelable {
}
/**
+ * Returns the x coordinate of mouse cursor position when this event is
+ * reported. This value is only valid if {@link #getSource()} returns
+ * {@link InputDevice#SOURCE_MOUSE}.
+ *
+ * @hide
+ */
+ public float getXCursorPosition() {
+ return nativeGetXCursorPosition(mNativePtr);
+ }
+
+ /**
+ * Returns the y coordinate of mouse cursor position when this event is
+ * reported. This value is only valid if {@link #getSource()} returns
+ * {@link InputDevice#SOURCE_MOUSE}.
+ *
+ * @hide
+ */
+ public float getYCursorPosition() {
+ return nativeGetYCursorPosition(mNativePtr);
+ }
+
+ /**
+ * Sets cursor position to given coordinates. The coordinate in parameters should be after
+ * offsetting. In other words, the effect of this function is {@link #getXCursorPosition()} and
+ * {@link #getYCursorPosition()} will return the same value passed in the parameters.
+ *
+ * @hide
+ */
+ private void setCursorPosition(float x, float y) {
+ nativeSetCursorPosition(mNativePtr, x, y);
+ }
+
+ /**
* Returns the number of historical points in this event. These are
* movements that have occurred between this event and the previous event.
* This only applies to ACTION_MOVE events -- all other actions will have
@@ -3305,8 +3366,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
pc[i].x = clamp(pc[i].x, left, right);
pc[i].y = clamp(pc[i].y, top, bottom);
}
- ev.mNativePtr = nativeInitialize(ev.mNativePtr,
- nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr),
+ ev.initialize(nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr),
nativeGetDisplayId(mNativePtr),
nativeGetAction(mNativePtr), nativeGetFlags(mNativePtr),
nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr),
@@ -3399,8 +3459,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
final long eventTimeNanos = nativeGetEventTimeNanos(mNativePtr, historyPos);
if (h == 0) {
- ev.mNativePtr = nativeInitialize(ev.mNativePtr,
- nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr),
+ ev.initialize(nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr),
nativeGetDisplayId(mNativePtr),
newAction, nativeGetFlags(mNativePtr),
nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr),
@@ -3417,6 +3476,38 @@ public final class MotionEvent extends InputEvent implements Parcelable {
}
}
+ /**
+ * Calculate new cursor position for events from mouse. This is used to split, clamp and inject
+ * events.
+ *
+ * <p>If the source is mouse, it sets cursor position to the centroid of all pointers because
+ * InputReader maps multiple fingers on a touchpad to locations around cursor position in screen
+ * coordinates so that the mouse cursor is at the centroid of all pointers.
+ *
+ * <p>If the source is not mouse it sets cursor position to NaN.
+ */
+ private void updateCursorPosition() {
+ if (getSource() != InputDevice.SOURCE_MOUSE) {
+ setCursorPosition(INVALID_CURSOR_POSITION, INVALID_CURSOR_POSITION);
+ return;
+ }
+
+ float x = 0;
+ float y = 0;
+
+ final int pointerCount = getPointerCount();
+ for (int i = 0; i < pointerCount; ++i) {
+ x += getX(i);
+ y += getY(i);
+ }
+
+ // If pointer count is 0, divisions below yield NaN, which is an acceptable result for this
+ // corner case.
+ x /= pointerCount;
+ y /= pointerCount;
+ setCursorPosition(x, y);
+ }
+
@Override
public String toString() {
StringBuilder msg = new StringBuilder();
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index a01e15e7ce46..aa29c5f77602 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -28,6 +28,7 @@ import android.graphics.Rect;
import android.graphics.RenderNode;
import android.os.SystemProperties;
import android.os.Trace;
+import android.util.Log;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
import android.view.animation.AnimationUtils;
@@ -674,11 +675,11 @@ public final class ThreadedRenderer extends HardwareRenderer {
int syncResult = syncAndDrawFrame(choreographer.mFrameInfo);
if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
- setEnabled(false);
- attachInfo.mViewRootImpl.mSurface.release();
- // Invalidate since we failed to draw. This should fetch a Surface
- // if it is still needed or do nothing if we are no longer drawing
- attachInfo.mViewRootImpl.invalidate();
+ Log.w("OpenGLRenderer", "Surface lost, forcing relayout");
+ // We lost our surface. For a relayout next frame which should give us a new
+ // surface from WindowManager, which hopefully will work.
+ attachInfo.mViewRootImpl.mForceNextWindowRelayout = true;
+ attachInfo.mViewRootImpl.requestLayout();
}
if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) {
attachInfo.mViewRootImpl.invalidate();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 69884dc62fb3..e1984894a85a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -967,6 +967,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
static boolean sBrokenInsetsDispatch;
+ /**
+ * Prior to Q, calling
+ * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)}
+ * did not call update the window format so the opacity of the background was not correctly
+ * applied to the window. Some applications rely on this misbehavior to work properly.
+ * <p>
+ * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is
+ * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)}
+ * which updates the window format.
+ * @hide
+ */
+ protected static boolean sBrokenWindowBackground;
+
/** @hide */
@IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO})
@Retention(RetentionPolicy.SOURCE)
@@ -5208,6 +5221,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
sBrokenInsetsDispatch = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
|| targetSdkVersion < Build.VERSION_CODES.Q;
+ sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q;
+
sCompatibilityDone = true;
}
}
@@ -8486,7 +8501,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* </ul>
*
* <p>It's also recommended to set the following properties - the more properties the structure
- * has, the higher the changes of an {@link android.service.autofill.AutofillService} properly
+ * has, the higher the chances of an {@link android.service.autofill.AutofillService} properly
* using the structure:
*
* <ul>
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 6efb6f38d118..5f3ce33db19d 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -228,6 +228,16 @@ public abstract class ViewStructure {
public abstract void setHint(CharSequence hint);
/**
+ * Sets the identifier used to set the hint associated with this view.
+ *
+ * <p>Should only be set when the node is used for autofill purposes - it will be ignored
+ * when used for Assist.
+ */
+ public void setHintIdEntry(@NonNull String entryName) {
+ Preconditions.checkNotNull(entryName);
+ }
+
+ /**
* Retrieve the last {@link #setText(CharSequence)}.
*/
public abstract CharSequence getText();
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index 8d6245458d62..0dd2587feed5 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -81,6 +81,7 @@ public final class ViewNode extends AssistStructure.ViewNode {
private static final long FLAGS_HAS_AUTOFILL_VALUE = 1L << 32;
private static final long FLAGS_HAS_AUTOFILL_HINTS = 1L << 33;
private static final long FLAGS_HAS_AUTOFILL_OPTIONS = 1L << 34;
+ private static final long FLAGS_HAS_HINT_ID_ENTRY = 1L << 35;
/** Flags used to optimize what's written to the parcel */
private long mFlags;
@@ -108,6 +109,7 @@ public final class ViewNode extends AssistStructure.ViewNode {
private int mMaxEms = -1;
private int mMaxLength = -1;
private String mTextIdEntry;
+ private String mHintIdEntry;
private @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
private String[] mAutofillHints;
private AutofillValue mAutofillValue;
@@ -195,6 +197,9 @@ public final class ViewNode extends AssistStructure.ViewNode {
if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
mAutofillOptions = parcel.readCharSequenceArray();
}
+ if ((nodeFlags & FLAGS_HAS_HINT_ID_ENTRY) != 0) {
+ mHintIdEntry = parcel.readString();
+ }
}
/**
@@ -352,6 +357,11 @@ public final class ViewNode extends AssistStructure.ViewNode {
}
@Override
+ public String getHintIdEntry() {
+ return mHintIdEntry;
+ }
+
+ @Override
public int getTextSelectionStart() {
return mText != null ? mText.mTextSelectionStart : -1;
}
@@ -512,6 +522,9 @@ public final class ViewNode extends AssistStructure.ViewNode {
if (mAutofillOptions != null) {
nodeFlags |= FLAGS_HAS_AUTOFILL_OPTIONS;
}
+ if (mHintIdEntry != null) {
+ nodeFlags |= FLAGS_HAS_HINT_ID_ENTRY;
+ }
parcel.writeLong(nodeFlags);
if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) {
@@ -585,6 +598,9 @@ public final class ViewNode extends AssistStructure.ViewNode {
if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
parcel.writeCharSequenceArray(mAutofillOptions);
}
+ if ((nodeFlags & FLAGS_HAS_HINT_ID_ENTRY) != 0) {
+ parcel.writeString(mHintIdEntry);
+ }
}
/** @hide */
@@ -783,7 +799,7 @@ public final class ViewNode extends AssistStructure.ViewNode {
}
@Override
- public void setTextIdEntry(String entryName) {
+ public void setTextIdEntry(@NonNull String entryName) {
mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
}
@@ -793,6 +809,11 @@ public final class ViewNode extends AssistStructure.ViewNode {
}
@Override
+ public void setHintIdEntry(String entryName) {
+ mNode.mHintIdEntry = Preconditions.checkNotNull(entryName);
+ }
+
+ @Override
public CharSequence getText() {
return mNode.getText();
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index efd5daf0b455..a428feac8806 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -921,10 +921,12 @@ public class NumberPicker extends LinearLayout {
if (!mFlingScroller.isFinished()) {
mFlingScroller.forceFinished(true);
mAdjustScroller.forceFinished(true);
+ onScrollerFinished(mFlingScroller);
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
} else if (!mAdjustScroller.isFinished()) {
mFlingScroller.forceFinished(true);
mAdjustScroller.forceFinished(true);
+ onScrollerFinished(mAdjustScroller);
} else if (mLastDownEventY < mTopSelectionDividerTop) {
postChangeCurrentByOneFromLongPress(
false, ViewConfiguration.getLongPressTimeout());
@@ -2556,14 +2558,16 @@ public class NumberPicker extends LinearLayout {
}
return false;
}
- case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
+ case R.id.accessibilityActionScrollDown: {
if (NumberPicker.this.isEnabled()
&& (getWrapSelectorWheel() || getValue() < getMaxValue())) {
changeValueByOne(true);
return true;
}
} return false;
- case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
+ case R.id.accessibilityActionScrollUp: {
if (NumberPicker.this.isEnabled()
&& (getWrapSelectorWheel() || getValue() > getMinValue())) {
changeValueByOne(false);
@@ -2865,10 +2869,13 @@ public class NumberPicker extends LinearLayout {
}
if (NumberPicker.this.isEnabled()) {
if (getWrapSelectorWheel() || getValue() < getMaxValue()) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN);
}
if (getWrapSelectorWheel() || getValue() > getMinValue()) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ info.addAction(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a4844eaa612c..f997d6878a9c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -918,6 +918,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private boolean mTextSetFromXmlOrResourceId = false;
// Resource id used to set the text.
private @StringRes int mTextId = Resources.ID_NULL;
+ // Resource id used to set the hint.
+ private @StringRes int mHintId = Resources.ID_NULL;
//
// End of autofill-related attributes
@@ -1210,6 +1212,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
break;
case com.android.internal.R.styleable.TextView_hint:
+ mHintId = a.getResourceId(attr, Resources.ID_NULL);
hint = a.getText(attr);
break;
@@ -6446,6 +6449,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
@android.view.RemotableViewMethod
public final void setHint(@StringRes int resid) {
+ mHintId = resid;
setHint(getContext().getResources().getText(resid));
}
@@ -11598,6 +11602,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
structure.setMaxTextLength(maxLength);
}
}
+ if (mHintId != Resources.ID_NULL) {
+ try {
+ structure.setHintIdEntry(getResources().getResourceEntryName(mHintId));
+ } catch (Resources.NotFoundException e) {
+ if (android.view.autofill.Helper.sVerbose) {
+ Log.v(LOG_TAG, "onProvideAutofillStructure(): cannot set name for hint id "
+ + mHintId + ": " + e.getMessage());
+ }
+ }
+ }
structure.setHint(getHint());
structure.setInputType(getInputType());
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index ee4666ff368c..8fe23167755a 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -194,6 +194,38 @@ public final class SystemUiDeviceConfigFlags {
public static final String ASSIST_HANDLES_SHOW_WHEN_TAUGHT = "assist_handles_show_when_taught";
/**
+ * (long) Duration per pixel, in milliseconds, of scrolling text at fast speed.
+ */
+ public static final String ASSIST_TRANSCRIPTION_DURATION_PER_PX_FAST =
+ "assist_transcription_duration_per_px_fast";
+
+ /**
+ * (long) Duration per pixel, in milliseconds, of scrolling text at regular speed.
+ */
+ public static final String ASSIST_TRANSCRIPTION_DURATION_PER_PX_REGULAR =
+ "assist_transcription_duration_per_px_regular";
+
+ /**
+ * (long) Duration, in milliseconds, over which text fades in.
+ */
+ public static final String ASSIST_TRANSCRIPTION_FADE_IN_DURATION =
+ "assist_transcription_fade_in_duration";
+
+ /**
+ * (long) Maximum total duration, in milliseconds, for a given transcription.
+ */
+ public static final String ASSIST_TRANSCRIPTION_MAX_DURATION =
+ "assist_transcription_max_duration";
+
+ /**
+ * (long) Minimum total duration, in milliseconds, for a given transcription.
+ */
+ public static final String ASSIST_TRANSCRIPTION_MIN_DURATION =
+ "assist_transcription_min_duration";
+
+ // Flags related to brightline falsing
+
+ /**
* (bool) Whether to use the new BrightLineFalsingManager.
*/
public static final String BRIGHTLINE_FALSING_MANAGER_ENABLED =
@@ -282,5 +314,6 @@ public final class SystemUiDeviceConfigFlags {
"brightline_falsing_zigzag_y_secondary_deviance";
- private SystemUiDeviceConfigFlags() { }
+ private SystemUiDeviceConfigFlags() {
+ }
}
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index 3ac58e018a45..e09e0e609380 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -27,6 +27,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import java.io.File;
import java.io.FileInputStream;
import java.util.Iterator;
@@ -38,6 +39,7 @@ public class KernelWakelockReader {
private static int sKernelWakelockUpdateVersion = 0;
private static final String sWakelockFile = "/proc/wakelocks";
private static final String sWakeupSourceFile = "/d/wakeup_sources";
+ private static final String sSysClassWakeupDir = "/sys/class/wakeup";
private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
Process.PROC_TAB_TERM|Process.PROC_OUT_STRING| // 0: name
@@ -71,99 +73,125 @@ public class KernelWakelockReader {
* @return the updated data.
*/
public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
- byte[] buffer = new byte[32*1024];
- int len = 0;
- boolean wakeup_sources;
- final long startTime = SystemClock.uptimeMillis();
+ boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();
- final int oldMask = StrictMode.allowThreadDiskReadsMask();
- try {
- FileInputStream is;
+ if (useSystemSuspend) {
+ // Get both kernel and native wakelock stats from SystemSuspend
+ updateVersion(staleStats);
+ if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
+ Slog.w(TAG, "Failed to get wakelock stats from SystemSuspend");
+ return null;
+ }
+ return removeOldStats(staleStats);
+ } else {
+ byte[] buffer = new byte[32*1024];
+ int len = 0;
+ boolean wakeup_sources;
+ final long startTime = SystemClock.uptimeMillis();
+
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
try {
- is = new FileInputStream(sWakelockFile);
- wakeup_sources = false;
- } catch (java.io.FileNotFoundException e) {
+ FileInputStream is;
try {
- is = new FileInputStream(sWakeupSourceFile);
- wakeup_sources = true;
- } catch (java.io.FileNotFoundException e2) {
- Slog.wtf(TAG, "neither " + sWakelockFile + " nor " +
- sWakeupSourceFile + " exists");
- return null;
+ is = new FileInputStream(sWakelockFile);
+ wakeup_sources = false;
+ } catch (java.io.FileNotFoundException e) {
+ try {
+ is = new FileInputStream(sWakeupSourceFile);
+ wakeup_sources = true;
+ } catch (java.io.FileNotFoundException e2) {
+ Slog.wtf(TAG, "neither " + sWakelockFile + " nor " +
+ sWakeupSourceFile + " exists");
+ return null;
+ }
}
- }
- int cnt;
- while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
- len += cnt;
- }
-
- is.close();
- } catch (java.io.IOException e) {
- Slog.wtf(TAG, "failed to read kernel wakelocks", e);
- return null;
- } finally {
- StrictMode.setThreadPolicyMask(oldMask);
- }
+ int cnt;
+ while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
+ len += cnt;
+ }
- final long readTime = SystemClock.uptimeMillis() - startTime;
- if (readTime > 100) {
- Slog.w(TAG, "Reading wakelock stats took " + readTime + "ms");
- }
+ is.close();
+ } catch (java.io.IOException e) {
+ Slog.wtf(TAG, "failed to read kernel wakelocks", e);
+ return null;
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
- if (len > 0) {
- if (len >= buffer.length) {
- Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+ final long readTime = SystemClock.uptimeMillis() - startTime;
+ if (readTime > 100) {
+ Slog.w(TAG, "Reading wakelock stats took " + readTime + "ms");
}
- int i;
- for (i=0; i<len; i++) {
- if (buffer[i] == '\0') {
- len = i;
- break;
+
+ if (len > 0) {
+ if (len >= buffer.length) {
+ Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+ }
+ int i;
+ for (i=0; i<len; i++) {
+ if (buffer[i] == '\0') {
+ len = i;
+ break;
+ }
}
}
- }
-
- updateVersion(staleStats);
- parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
+ updateVersion(staleStats);
+ // Get native wakelock stats from SystemSuspend
+ if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
+ Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend");
+ }
+ // Get kernel wakelock stats
+ parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
+ return removeOldStats(staleStats);
+ }
+ }
+ /**
+ * On success, returns the updated stats from SystemSupend, else returns null.
+ */
+ private KernelWakelockStats getWakelockStatsFromSystemSuspend(
+ final KernelWakelockStats staleStats) {
+ WakeLockInfo[] wlStats = null;
if (mSuspendControlService == null) {
try {
mSuspendControlService = ISuspendControlService.Stub.asInterface(
ServiceManager.getServiceOrThrow("suspend_control"));
} catch (ServiceNotFoundException e) {
Slog.wtf(TAG, "Required service suspend_control not available", e);
+ return null;
}
}
try {
- WakeLockInfo[] wlStats = mSuspendControlService.getWakeLockStats();
- getNativeWakelockStats(wlStats, staleStats);
+ wlStats = mSuspendControlService.getWakeLockStats();
+ updateWakelockStats(wlStats, staleStats);
} catch (RemoteException e) {
Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
+ return null;
}
- return removeOldStats(staleStats);
+ return staleStats;
}
/**
- * Reads native wakelock stats from SystemSuspend and updates staleStats with the new
- * information.
+ * Updates statleStats with stats from SystemSuspend.
* @param staleStats Existing object to update.
* @return the updated stats.
*/
@VisibleForTesting
- public KernelWakelockStats getNativeWakelockStats(WakeLockInfo[] wlStats,
+ public KernelWakelockStats updateWakelockStats(WakeLockInfo[] wlStats,
final KernelWakelockStats staleStats) {
for (WakeLockInfo info : wlStats) {
if (!staleStats.containsKey(info.name)) {
staleStats.put(info.name, new KernelWakelockStats.Entry((int) info.activeCount,
- info.totalTime, sKernelWakelockUpdateVersion));
+ info.totalTime * 1000 /* ms to us */, sKernelWakelockUpdateVersion));
} else {
KernelWakelockStats.Entry kwlStats = staleStats.get(info.name);
kwlStats.mCount = (int) info.activeCount;
- kwlStats.mTotalTime = info.totalTime;
+ // Convert milliseconds to microseconds
+ kwlStats.mTotalTime = info.totalTime * 1000;
kwlStats.mVersion = sKernelWakelockUpdateVersion;
}
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 599c354f0a1a..981d0bb1cd69 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -989,7 +989,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
} else {
mBackgroundPadding.setEmpty();
}
- drawableChanged();
+ if (!View.sBrokenWindowBackground) {
+ drawableChanged();
+ }
}
}
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index c46f86792764..2779be6f9753 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -297,10 +297,10 @@ public class DividerSnapAlgorithm {
private void addNonDismissingTargets(boolean isHorizontalDivision, int topPosition,
int bottomPosition, int dividerMax) {
- maybeAddTarget(topPosition, topPosition - mInsets.top);
+ maybeAddTarget(topPosition, topPosition - getStartInset());
addMiddleTarget(isHorizontalDivision);
- maybeAddTarget(bottomPosition, dividerMax - mInsets.bottom
- - (bottomPosition + mDividerSize));
+ maybeAddTarget(bottomPosition,
+ dividerMax - getEndInset() - (bottomPosition + mDividerSize));
}
private void addFixedDivisionTargets(boolean isHorizontalDivision, int dividerMax) {
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index e7d240a1035e..0d87afa42e3e 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -26,6 +26,8 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RemoteViews;
+import java.util.ArrayList;
+
/**
* A TextView that can float around an image on the end.
*
@@ -42,6 +44,7 @@ public class MediaNotificationView extends FrameLayout {
private View mMainColumn;
private View mMediaContent;
private int mImagePushIn;
+ private ArrayList<VisibilityChangeListener> mListeners;
public MediaNotificationView(Context context) {
this(context, null);
@@ -168,4 +171,48 @@ public class MediaNotificationView extends FrameLayout {
mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
mMediaContent = findViewById(com.android.internal.R.id.notification_media_content);
}
+
+ @Override
+ public void onVisibilityAggregated(boolean isVisible) {
+ super.onVisibilityAggregated(isVisible);
+ for (int i = 0; i < mListeners.size(); i++) {
+ mListeners.get(i).onAggregatedVisibilityChanged(isVisible);
+ }
+ }
+
+ /**
+ * Add a listener to receive updates on the visibility of this view
+ *
+ * @param listener The listener to add.
+ */
+ public void addVisibilityListener(VisibilityChangeListener listener) {
+ if (mListeners == null) {
+ mListeners = new ArrayList<>();
+ }
+ if (!mListeners.contains(listener)) {
+ mListeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove the specified listener
+ *
+ * @param listener The listener to remove.
+ */
+ public void removeVisibilityListener(VisibilityChangeListener listener) {
+ if (mListeners != null) {
+ mListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Interface for receiving updates when the view's visibility changes
+ */
+ public interface VisibilityChangeListener {
+ /**
+ * Method called when the visibility of this view has changed
+ * @param isVisible true if the view is now visible
+ */
+ void onAggregatedVisibilityChanged(boolean isVisible);
+ }
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/core/java/com/android/server/job/JobSchedulerInternal.java
index 425ec473bc8e..425ec473bc8e 100644
--- a/services/core/java/com/android/server/job/JobSchedulerInternal.java
+++ b/core/java/com/android/server/job/JobSchedulerInternal.java
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 8ddbe724217c..f390930e17a5 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -701,6 +701,21 @@ static jfloat android_view_MotionEvent_nativeGetYPrecision(jlong nativePtr) {
return event->getYPrecision();
}
+static jfloat android_view_MotionEvent_nativeGetXCursorPosition(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getXCursorPosition();
+}
+
+static jfloat android_view_MotionEvent_nativeGetYCursorPosition(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getYCursorPosition();
+}
+
+static void android_view_MotionEvent_nativeSetCursorPosition(jlong nativePtr, jfloat x, jfloat y) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->setCursorPosition(x, y);
+}
+
static jlong android_view_MotionEvent_nativeGetDownTimeNanos(jlong nativePtr) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
return event->getDownTime();
@@ -871,6 +886,15 @@ static const JNINativeMethod gMotionEventMethods[] = {
{ "nativeGetYPrecision",
"(J)F",
(void*)android_view_MotionEvent_nativeGetYPrecision },
+ { "nativeGetXCursorPosition",
+ "(J)F",
+ (void*)android_view_MotionEvent_nativeGetXCursorPosition },
+ { "nativeGetYCursorPosition",
+ "(J)F",
+ (void*)android_view_MotionEvent_nativeGetYCursorPosition },
+ { "nativeSetCursorPosition",
+ "(JFF)V",
+ (void*)android_view_MotionEvent_nativeSetCursorPosition },
{ "nativeGetDownTimeNanos",
"(J)J",
(void*)android_view_MotionEvent_nativeGetDownTimeNanos },
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index a3d4798647be..71e386011253 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -7,7 +7,7 @@ yaochen@google.com
yro@google.com
# Settings UI
-per-file settings_enums.proto=zhfan@google.com
+per-file settings_enums.proto=tmfang@google.com
# Frameworks
ogunwale@google.com
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index c023438eecc2..3323095a6244 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2401,4 +2401,11 @@ enum PageId {
// OS: Q
// Note: Gear icon is shown next to gesture navigation preference and opens sensitivity dialog
SETTINGS_GESTURE_NAV_BACK_SENSITIVITY_DLG = 1748;
+
+ // ---- End Q Constants, all Q constants go above this line ----
+ // OPEN: Settings > Network & Internet > Wi-Fi > Click new network
+ // CATEGORY: SETTINGS
+ // OS: R
+ SETTINGS_WIFI_CONFIGURE_NETWORK = 1800;
+
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index df45ec5e3ae0..6a20484f6faa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4599,6 +4599,11 @@
<permission android:name="android.permission.MONITOR_INPUT"
android:protectionLevel="signature" />
+ <!-- Allows query of any normal app on the device, regardless of manifest declarations. -->
+ <permission android:name="android.permission.QUERY_ALL_PACKAGES"
+ android:protectionLevel="normal" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
@@ -4610,6 +4615,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
android:defaultToDeviceProtectedStorage="true"
+ android:forceQueryable="true"
android:directBootAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.DeviceDefault.Resolver"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index be6cdcf3f098..3ea8a778ba9b 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1743,6 +1743,13 @@
- {@code true} for apps with targetSdkVersion < 29.
-->
<attr name="requestLegacyExternalStorage" format="boolean" />
+
+ <!-- If {@code true} this app declares that it should be visible to all other apps on
+ device, regardless of what they declare via the {@code queries} tags in their
+ manifest.
+
+ The default value is {@code false}. -->
+ <attr name="forceQueryable" format="boolean" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
@@ -1977,6 +1984,12 @@
<attr name="name" />
</declare-styleable>
+ <declare-styleable name="AndroidManifestQueries" parent="AndroidManifest" />
+ <declare-styleable name="AndroidManifestQueriesPackage" parent="AndroidManifestQueries">
+ <attr name="name" />
+ </declare-styleable>
+ <declare-styleable name="AndroidManifestQueriesIntent" parent="AndroidManifestQueries" />
+
<!-- The <code>static-library</code> tag declares that this apk is providing itself
as a static shared library for other applications to use. Any app can declare such
@@ -2477,6 +2490,7 @@
<!-- High dynamic range color mode. -->
<enum name="hdr" value="2" />
</attr>
+ <attr name="forceQueryable" format="boolean" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3b1275354d1f..b34c422053df 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1700,6 +1700,17 @@
<!-- Add packages here -->
</string-array>
+ <!-- The set of system packages on device that are queryable regardless of the contents of their
+ manifest. -->
+ <string-array name="config_forceQueryablePackages" translatable="false">
+ <item>com.android.settings</item>
+ <!-- Add packages here -->
+ </string-array>
+
+ <!-- If true, will force all packages on any system partition as queryable regardless of the
+ contents of their manifest. -->
+ <bool name="config_forceSystemPackagesQueryable">false</bool>
+
<!-- Component name of the default wallpaper. This will be ImageWallpaper if not
specified -->
<string name="default_wallpaper_component" translatable="false">@null</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 913001c0eb94..40f20ab41b85 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -187,6 +187,9 @@
<string name="notification_channel_wfc">Wi-Fi calling</string>
<!-- Telephony notification channel name for a channel containing SIM notifications -->
<string name="notification_channel_sim">SIM status</string>
+ <!-- Telephony notification channel name for a channel containing high priority SIM notifications -->
+ <string name="notification_channel_sim_high_prio">High priority SIM status</string>
+
<!-- Displayed to tell the user that peer changed TTY mode -->
<string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d91bbd006318..ac32c95bcd5e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -653,6 +653,7 @@
<java-symbol type="string" name="notification_channel_voice_mail" />
<java-symbol type="string" name="notification_channel_wfc" />
<java-symbol type="string" name="notification_channel_sim" />
+ <java-symbol type="string" name="notification_channel_sim_high_prio" />
<java-symbol type="string" name="SetupCallDefault" />
<java-symbol type="string" name="accept" />
<java-symbol type="string" name="activity_chooser_view_see_all" />
@@ -786,6 +787,8 @@
<java-symbol type="string" name="widget_default_class_name" />
<java-symbol type="string" name="emergency_calls_only" />
<java-symbol type="array" name="config_ephemeralResolverPackage" />
+ <java-symbol type="array" name="config_forceQueryablePackages" />
+ <java-symbol type="bool" name="config_forceSystemPackagesQueryable" />
<java-symbol type="string" name="eventTypeAnniversary" />
<java-symbol type="string" name="eventTypeBirthday" />
<java-symbol type="string" name="eventTypeCustom" />
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
index b2254c5fe59e..eadf226b01ce 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
@@ -17,12 +17,10 @@ package com.android.server.broadcastradio.hal2;
import static org.junit.Assert.*;
-import android.hardware.broadcastradio.V2_0.ProgramInfo;
import android.hardware.broadcastradio.V2_0.ProgramListChunk;
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
-import android.hardware.radio.RadioMetadata;
import android.test.suitebuilder.annotation.MediumTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,7 +28,6 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -45,55 +42,58 @@ public class ProgramInfoCacheTest {
private final ProgramSelector.Identifier mAmFmIdentifier =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, 88500);
- private final RadioManager.ProgramInfo mAmFmInfo = makeProgramInfo(
+ private final RadioManager.ProgramInfo mAmFmInfo = TestUtils.makeProgramInfo(
ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
private final ProgramSelector.Identifier mRdsIdentifier =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI, 15019);
- private final RadioManager.ProgramInfo mRdsInfo = makeProgramInfo(
+ private final RadioManager.ProgramInfo mRdsInfo = TestUtils.makeProgramInfo(
ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 0);
private final ProgramSelector.Identifier mDabEnsembleIdentifier =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, 1337);
- private final RadioManager.ProgramInfo mDabEnsembleInfo = makeProgramInfo(
+ private final RadioManager.ProgramInfo mDabEnsembleInfo = TestUtils.makeProgramInfo(
ProgramSelector.PROGRAM_TYPE_DAB, mDabEnsembleIdentifier, 0);
private final ProgramSelector.Identifier mVendorCustomIdentifier =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, 9001);
- private final RadioManager.ProgramInfo mVendorCustomInfo = makeProgramInfo(
+ private final RadioManager.ProgramInfo mVendorCustomInfo = TestUtils.makeProgramInfo(
ProgramSelector.PROGRAM_TYPE_VENDOR_START, mVendorCustomIdentifier, 0);
// HAL-side ProgramInfoCache containing all of the above ProgramInfos.
- private final ProgramInfoCache mAllProgramInfos = new ProgramInfoCache(null, mAmFmInfo,
+ private final ProgramInfoCache mAllProgramInfos = new ProgramInfoCache(null, true, mAmFmInfo,
mRdsInfo, mDabEnsembleInfo, mVendorCustomInfo);
@Test
public void testUpdateFromHal() {
- // First test a purging chunk.
- ProgramInfoCache cache = new ProgramInfoCache(null, mAmFmInfo);
+ // First test updating an incomplete cache with a purging, complete chunk.
+ ProgramInfoCache cache = new ProgramInfoCache(null, false, mAmFmInfo);
ProgramListChunk chunk = new ProgramListChunk();
chunk.purge = true;
- chunk.modified.add(programInfoToHal(mRdsInfo));
- chunk.modified.add(programInfoToHal(mDabEnsembleInfo));
- cache.updateFromHalProgramListChunk(chunk);
chunk.complete = true;
+ chunk.modified.add(TestUtils.programInfoToHal(mRdsInfo));
+ chunk.modified.add(TestUtils.programInfoToHal(mDabEnsembleInfo));
+ cache.updateFromHalProgramListChunk(chunk);
assertTrue(cache.programInfosAreExactly(mRdsInfo, mDabEnsembleInfo));
+ assertTrue(cache.isComplete());
- // Then test a non-purging chunk.
+ // Then test a non-purging, incomplete chunk.
chunk.purge = false;
+ chunk.complete = false;
chunk.modified.clear();
- RadioManager.ProgramInfo updatedRdsInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_FM,
- mRdsIdentifier, 1);
- chunk.modified.add(programInfoToHal(updatedRdsInfo));
- chunk.modified.add(programInfoToHal(mVendorCustomInfo));
+ RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(
+ ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 1);
+ chunk.modified.add(TestUtils.programInfoToHal(updatedRdsInfo));
+ chunk.modified.add(TestUtils.programInfoToHal(mVendorCustomInfo));
chunk.removed.add(Convert.programIdentifierToHal(mDabEnsembleIdentifier));
cache.updateFromHalProgramListChunk(chunk);
assertTrue(cache.programInfosAreExactly(updatedRdsInfo, mVendorCustomInfo));
+ assertFalse(cache.isComplete());
}
@Test
public void testNullFilter() {
- ProgramInfoCache cache = new ProgramInfoCache(null);
+ ProgramInfoCache cache = new ProgramInfoCache(null, true);
cache.filterAndUpdateFrom(mAllProgramInfos, false);
assertTrue(cache.programInfosAreExactly(mAmFmInfo, mRdsInfo, mDabEnsembleInfo,
mVendorCustomInfo));
@@ -140,11 +140,11 @@ public class ProgramInfoCacheTest {
@Test
public void testPurgeUpdateChunks() {
- ProgramInfoCache cache = new ProgramInfoCache(null, mAmFmInfo);
+ ProgramInfoCache cache = new ProgramInfoCache(null, false, mAmFmInfo);
List<ProgramList.Chunk> chunks =
cache.filterAndUpdateFromInternal(mAllProgramInfos, true, 3, 3);
assertEquals(2, chunks.size());
- verifyChunkListFlags(chunks, true);
+ verifyChunkListFlags(chunks, true, true);
verifyChunkListModified(chunks, 3, mAmFmInfo, mRdsInfo, mDabEnsembleInfo,
mVendorCustomInfo);
verifyChunkListRemoved(chunks, 0);
@@ -154,23 +154,26 @@ public class ProgramInfoCacheTest {
public void testDeltaUpdateChunksModificationsIncluded() {
// Create a cache with a filter that allows modifications, and set its contents to
// mAmFmInfo, mRdsInfo, mDabEnsembleInfo, and mVendorCustomInfo.
- ProgramInfoCache cache = new ProgramInfoCache(null, mAmFmInfo, mRdsInfo, mDabEnsembleInfo,
- mVendorCustomInfo);
+ ProgramInfoCache cache = new ProgramInfoCache(null, true, mAmFmInfo, mRdsInfo,
+ mDabEnsembleInfo, mVendorCustomInfo);
// Create a HAL cache that:
+ // - Is complete.
// - Retains mAmFmInfo.
// - Replaces mRdsInfo with updatedRdsInfo.
// - Drops mDabEnsembleInfo and mVendorCustomInfo.
// - Introduces a new SXM info.
- RadioManager.ProgramInfo updatedRdsInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_FM,
- mRdsIdentifier, 1);
- RadioManager.ProgramInfo newSxmInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_SXM,
+ RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(
+ ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 1);
+ RadioManager.ProgramInfo newSxmInfo = TestUtils.makeProgramInfo(
+ ProgramSelector.PROGRAM_TYPE_SXM,
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL, 12345),
0);
- ProgramInfoCache halCache = new ProgramInfoCache(null, mAmFmInfo, updatedRdsInfo,
+ ProgramInfoCache halCache = new ProgramInfoCache(null, true, mAmFmInfo, updatedRdsInfo,
newSxmInfo);
// Update the cache and verify:
+ // - The final chunk's complete flag is set.
// - mAmFmInfo is retained and not reported in the chunks.
// - updatedRdsInfo should appear as an update to mRdsInfo.
// - newSxmInfo should appear as a new entry.
@@ -178,7 +181,7 @@ public class ProgramInfoCacheTest {
List<ProgramList.Chunk> chunks = cache.filterAndUpdateFromInternal(halCache, false, 5, 1);
assertTrue(cache.programInfosAreExactly(mAmFmInfo, updatedRdsInfo, newSxmInfo));
assertEquals(2, chunks.size());
- verifyChunkListFlags(chunks, false);
+ verifyChunkListFlags(chunks, false, true);
verifyChunkListModified(chunks, 5, updatedRdsInfo, newSxmInfo);
verifyChunkListRemoved(chunks, 1, mDabEnsembleIdentifier, mVendorCustomIdentifier);
}
@@ -188,63 +191,50 @@ public class ProgramInfoCacheTest {
// Create a cache with a filter that excludes modifications, and set its contents to
// mAmFmInfo, mRdsInfo, mDabEnsembleInfo, and mVendorCustomInfo.
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new HashSet<Integer>(),
- new HashSet<ProgramSelector.Identifier>(), true, true), mAmFmInfo, mRdsInfo,
+ new HashSet<ProgramSelector.Identifier>(), true, true), true, mAmFmInfo, mRdsInfo,
mDabEnsembleInfo, mVendorCustomInfo);
// Create a HAL cache that:
+ // - Is incomplete.
// - Retains mAmFmInfo.
// - Replaces mRdsInfo with updatedRdsInfo.
// - Drops mDabEnsembleInfo and mVendorCustomInfo.
// - Introduces a new SXM info.
- RadioManager.ProgramInfo updatedRdsInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_FM,
- mRdsIdentifier, 1);
- RadioManager.ProgramInfo newSxmInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_SXM,
+ RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(
+ ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 1);
+ RadioManager.ProgramInfo newSxmInfo = TestUtils.makeProgramInfo(
+ ProgramSelector.PROGRAM_TYPE_SXM,
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL, 12345),
0);
- ProgramInfoCache halCache = new ProgramInfoCache(null, mAmFmInfo, updatedRdsInfo,
+ ProgramInfoCache halCache = new ProgramInfoCache(null, false, mAmFmInfo, updatedRdsInfo,
newSxmInfo);
// Update the cache and verify:
+ // - All complete flags are false.
// - mAmFmInfo and mRdsInfo are retained and not reported in the chunks.
// - newSxmInfo should appear as a new entry.
// - mDabEnsembleInfo and mVendorCustomInfo should be reported as removed.
List<ProgramList.Chunk> chunks = cache.filterAndUpdateFromInternal(halCache, false, 5, 1);
assertTrue(cache.programInfosAreExactly(mAmFmInfo, mRdsInfo, newSxmInfo));
assertEquals(2, chunks.size());
- verifyChunkListFlags(chunks, false);
+ verifyChunkListFlags(chunks, false, false);
verifyChunkListModified(chunks, 5, newSxmInfo);
verifyChunkListRemoved(chunks, 1, mDabEnsembleIdentifier, mVendorCustomIdentifier);
}
- private static RadioManager.ProgramInfo makeProgramInfo(int programType,
- ProgramSelector.Identifier identifier, int signalQuality) {
- // Note: If you set new fields, check if programInfoToHal() needs to be updated as well.
- return new RadioManager.ProgramInfo(new ProgramSelector(programType, identifier, null,
- null), null, null, null, 0, signalQuality, new RadioMetadata.Builder().build(),
- new HashMap<String, String>());
- }
-
- private static ProgramInfo programInfoToHal(RadioManager.ProgramInfo info) {
- // Note that because Convert does not by design provide functions for all conversions, this
- // function only copies fields that are set by makeProgramInfo().
- ProgramInfo hwInfo = new ProgramInfo();
- hwInfo.selector = Convert.programSelectorToHal(info.getSelector());
- hwInfo.signalQuality = info.getSignalStrength();
- return hwInfo;
- }
-
// Verifies that:
// - The first chunk's purge flag matches expectPurge.
- // - The last chunk's complete flag is set.
+ // - The last chunk's complete flag matches expectComplete.
// - All other flags are false.
- private static void verifyChunkListFlags(List<ProgramList.Chunk> chunks, boolean expectPurge) {
+ private static void verifyChunkListFlags(List<ProgramList.Chunk> chunks, boolean expectPurge,
+ boolean expectComplete) {
if (chunks.isEmpty()) {
return;
}
for (int i = 0; i < chunks.size(); i++) {
ProgramList.Chunk chunk = chunks.get(i);
assertEquals(i == 0 && expectPurge, chunk.isPurge());
- assertEquals(i == chunks.size() - 1, chunk.isComplete());
+ assertEquals(i == chunks.size() - 1 && expectComplete, chunk.isComplete());
}
}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
new file mode 100644
index 000000000000..f9e37981fa6f
--- /dev/null
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2019 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.broadcastradio.hal2;
+
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
+import android.hardware.broadcastradio.V2_0.ITunerCallback;
+import android.hardware.broadcastradio.V2_0.ITunerSession;
+import android.hardware.broadcastradio.V2_0.ProgramFilter;
+import android.hardware.broadcastradio.V2_0.ProgramListChunk;
+import android.hardware.broadcastradio.V2_0.Result;
+import android.hardware.radio.ProgramList;
+import android.hardware.radio.ProgramSelector;
+import android.hardware.radio.RadioManager;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for v2 HAL RadioModule.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class StartProgramListUpdatesFanoutTest {
+ private static final String TAG = "BroadcastRadioTests.hal2.StartProgramListUpdatesFanout";
+
+ // Mocks
+ @Mock IBroadcastRadio mBroadcastRadioMock;
+ @Mock ITunerSession mHalTunerSessionMock;
+ private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
+
+ // RadioModule under test
+ private RadioModule mRadioModule;
+
+ // Objects created by mRadioModule
+ private ITunerCallback mHalTunerCallback;
+ private TunerSession[] mTunerSessions;
+
+ // Data objects used during tests
+ private final ProgramSelector.Identifier mAmFmIdentifier =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, 88500);
+ private final RadioManager.ProgramInfo mAmFmInfo = TestUtils.makeProgramInfo(
+ ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
+ private final RadioManager.ProgramInfo mModifiedAmFmInfo = TestUtils.makeProgramInfo(
+ ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 1);
+
+ private final ProgramSelector.Identifier mRdsIdentifier =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI, 15019);
+ private final RadioManager.ProgramInfo mRdsInfo = TestUtils.makeProgramInfo(
+ ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 0);
+
+ private final ProgramSelector.Identifier mDabEnsembleIdentifier =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, 1337);
+ private final RadioManager.ProgramInfo mDabEnsembleInfo = TestUtils.makeProgramInfo(
+ ProgramSelector.PROGRAM_TYPE_DAB, mDabEnsembleIdentifier, 0);
+
+ @Before
+ public void setup() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+
+ mRadioModule = new RadioModule(mBroadcastRadioMock, new RadioManager.ModuleProperties(0, "",
+ 0, "", "", "", "", 0, 0, false, false, null, false, new int[] {}, new int[] {},
+ null, null));
+
+ doAnswer((Answer) invocation -> {
+ mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
+ IBroadcastRadio.openSessionCallback cb = (IBroadcastRadio.openSessionCallback)
+ invocation.getArguments()[1];
+ cb.onValues(Result.OK, mHalTunerSessionMock);
+ return null;
+ }).when(mBroadcastRadioMock).openSession(any(), any());
+ when(mHalTunerSessionMock.startProgramListUpdates(any())).thenReturn(Result.OK);
+ }
+
+ @Test
+ public void testFanout() throws RemoteException {
+ // Open 3 clients that will all use the same filter, and start updates on two of them for
+ // now. The HAL TunerSession should only see 1 filter update.
+ openAidlClients(3);
+ ProgramList.Filter aidlFilter = new ProgramList.Filter(new HashSet<Integer>(),
+ new HashSet<ProgramSelector.Identifier>(), true, false);
+ ProgramFilter halFilter = Convert.programFilterToHal(aidlFilter);
+ for (int i = 0; i < 2; i++) {
+ mTunerSessions[i].startProgramListUpdates(aidlFilter);
+ }
+ verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+ // Initiate a program list update from the HAL side and verify both connected AIDL clients
+ // receive the update.
+ updateHalProgramInfo(true, Arrays.asList(mAmFmInfo, mRdsInfo), null);
+ for (int i = 0; i < 2; i++) {
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[i], true, Arrays.asList(
+ mAmFmInfo, mRdsInfo), null);
+ }
+
+ // Repeat with a non-purging update.
+ updateHalProgramInfo(false, Arrays.asList(mModifiedAmFmInfo),
+ Arrays.asList(mRdsIdentifier));
+ for (int i = 0; i < 2; i++) {
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[i], false,
+ Arrays.asList(mModifiedAmFmInfo), Arrays.asList(mRdsIdentifier));
+ }
+
+ // Now start updates on the 3rd client. Verify the HAL function has not been called again
+ // and client receives the appropriate update.
+ mTunerSessions[2].startProgramListUpdates(aidlFilter);
+ verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(any());
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[2], true,
+ Arrays.asList(mModifiedAmFmInfo), null);
+ }
+
+ @Test
+ public void testFiltering() throws RemoteException {
+ // Open 4 clients that will use the following filters:
+ // [0]: ID mRdsIdentifier, modifications excluded
+ // [1]: No categories, modifications excluded
+ // [2]: Type IDENTIFIER_TYPE_AMFM_FREQUENCY, modifications excluded
+ // [3]: Type IDENTIFIER_TYPE_AMFM_FREQUENCY, modifications included
+ openAidlClients(4);
+ ProgramList.Filter idFilter = new ProgramList.Filter(new HashSet<Integer>(),
+ new HashSet<ProgramSelector.Identifier>(Arrays.asList(mRdsIdentifier)), true, true);
+ ProgramList.Filter categoryFilter = new ProgramList.Filter(new HashSet<Integer>(),
+ new HashSet<ProgramSelector.Identifier>(), false, true);
+ ProgramList.Filter typeFilterWithoutModifications = new ProgramList.Filter(
+ new HashSet<Integer>(Arrays.asList(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)),
+ new HashSet<ProgramSelector.Identifier>(), true, true);
+ ProgramList.Filter typeFilterWithModifications = new ProgramList.Filter(
+ new HashSet<Integer>(Arrays.asList(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)),
+ new HashSet<ProgramSelector.Identifier>(), true, false);
+
+ // Start updates on the clients in order. The HAL filter should get updated after each
+ // client except [2].
+ mTunerSessions[0].startProgramListUpdates(idFilter);
+ ProgramFilter halFilter = Convert.programFilterToHal(idFilter);
+ verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+ mTunerSessions[1].startProgramListUpdates(categoryFilter);
+ halFilter.identifiers.clear();
+ verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+ mTunerSessions[2].startProgramListUpdates(typeFilterWithoutModifications);
+ verify(mHalTunerSessionMock, times(2)).startProgramListUpdates(any());
+
+ mTunerSessions[3].startProgramListUpdates(typeFilterWithModifications);
+ halFilter.excludeModifications = false;
+ verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+ // Adding mRdsInfo should update clients [0] and [1].
+ updateHalProgramInfo(false, Arrays.asList(mRdsInfo), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false, Arrays.asList(mRdsInfo),
+ null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], false, Arrays.asList(mRdsInfo),
+ null);
+
+ // Adding mAmFmInfo should update clients [1], [2], and [3].
+ updateHalProgramInfo(false, Arrays.asList(mAmFmInfo), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], false, Arrays.asList(mAmFmInfo),
+ null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[2], false, Arrays.asList(mAmFmInfo),
+ null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[3], false, Arrays.asList(mAmFmInfo),
+ null);
+
+ // Modifying mAmFmInfo to mModifiedAmFmInfo should update only [3].
+ updateHalProgramInfo(false, Arrays.asList(mModifiedAmFmInfo), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[3], false,
+ Arrays.asList(mModifiedAmFmInfo), null);
+
+ // Adding mDabEnsembleInfo should not update any client.
+ updateHalProgramInfo(false, Arrays.asList(mDabEnsembleInfo), null);
+ verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[1], times(2)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[2], times(1)).onProgramListUpdated(any());
+ verify(mAidlTunerCallbackMocks[3], times(2)).onProgramListUpdated(any());
+ }
+
+ @Test
+ public void testClientClosing() throws RemoteException {
+ // Open 2 clients that use different filters that are both sensitive to mAmFmIdentifier.
+ openAidlClients(2);
+ ProgramList.Filter idFilter = new ProgramList.Filter(new HashSet<Integer>(),
+ new HashSet<ProgramSelector.Identifier>(Arrays.asList(mAmFmIdentifier)), true,
+ false);
+ ProgramList.Filter typeFilter = new ProgramList.Filter(
+ new HashSet<Integer>(Arrays.asList(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)),
+ new HashSet<ProgramSelector.Identifier>(), true, false);
+
+ // Start updates on the clients, and verify the HAL filter is updated after each one.
+ mTunerSessions[0].startProgramListUpdates(idFilter);
+ ProgramFilter halFilter = Convert.programFilterToHal(idFilter);
+ verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+ mTunerSessions[1].startProgramListUpdates(typeFilter);
+ halFilter.identifiers.clear();
+ verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+ // Update the HAL with mAmFmInfo, and verify both clients are updated.
+ updateHalProgramInfo(true, Arrays.asList(mAmFmInfo), null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], true, Arrays.asList(mAmFmInfo),
+ null);
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true, Arrays.asList(mAmFmInfo),
+ null);
+
+ // Stop updates on the first client and verify the HAL filter is updated.
+ mTunerSessions[0].stopProgramListUpdates();
+ verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(Convert.programFilterToHal(
+ typeFilter));
+
+ // Update the HAL with mModifiedAmFmInfo, and verify only the remaining client is updated.
+ updateHalProgramInfo(true, Arrays.asList(mModifiedAmFmInfo), null);
+ verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
+ verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true,
+ Arrays.asList(mModifiedAmFmInfo), null);
+
+ // Close the other client without explicitly stopping updates, and verify HAL updates are
+ // stopped as well.
+ mTunerSessions[1].close();
+ verify(mHalTunerSessionMock).stopProgramListUpdates();
+ }
+
+ private void openAidlClients(int numClients) throws RemoteException {
+ mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients];
+ mTunerSessions = new TunerSession[numClients];
+ for (int i = 0; i < numClients; i++) {
+ mAidlTunerCallbackMocks[i] = mock(android.hardware.radio.ITunerCallback.class);
+ mTunerSessions[i] = mRadioModule.openSession(mAidlTunerCallbackMocks[i]);
+ }
+ }
+
+ private void updateHalProgramInfo(boolean purge, List<RadioManager.ProgramInfo> modified,
+ List<ProgramSelector.Identifier> removed) throws RemoteException {
+ ProgramListChunk programListChunk = new ProgramListChunk();
+ programListChunk.purge = purge;
+ programListChunk.complete = true;
+ if (modified != null) {
+ for (RadioManager.ProgramInfo mod : modified) {
+ programListChunk.modified.add(TestUtils.programInfoToHal(mod));
+ }
+ }
+ if (removed != null) {
+ for (ProgramSelector.Identifier id : removed) {
+ programListChunk.removed.add(Convert.programIdentifierToHal(id));
+ }
+ }
+ mHalTunerCallback.onProgramListUpdated(programListChunk);
+ }
+
+ private void verifyAidlClientReceivedChunk(android.hardware.radio.ITunerCallback clientMock,
+ boolean purge, List<RadioManager.ProgramInfo> modified,
+ List<ProgramSelector.Identifier> removed) throws RemoteException {
+ HashSet<RadioManager.ProgramInfo> modifiedSet = new HashSet<>();
+ if (modified != null) {
+ modifiedSet.addAll(modified);
+ }
+ HashSet<ProgramSelector.Identifier> removedSet = new HashSet<>();
+ if (removed != null) {
+ removedSet.addAll(removed);
+ }
+ ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet,
+ removedSet);
+ verify(clientMock).onProgramListUpdated(argThat(new ChunkMatcher(expectedChunk)));
+ }
+
+ // TODO(b/130750904): Remove this class and replace "argThat(new ChunkMatcher(chunk))" with
+ // "eq(chunk)".
+ //
+ // Ideally, this class wouldn't exist, but currently RadioManager.ProgramInfo#hashCode() can
+ // return different values for objects that satisfy ProgramInfo#equals(). As a short term
+ // workaround, this class performs the O(N^2) comparison between the Chunks' mModified sets.
+ //
+ // To test if ProgramInfo#hashCode() has been fixed, remove commenting from
+ // testProgramInfoHashCode() below.
+ private class ChunkMatcher implements ArgumentMatcher<ProgramList.Chunk> {
+ private final ProgramList.Chunk mExpected;
+
+ ChunkMatcher(ProgramList.Chunk expected) {
+ mExpected = expected;
+ }
+
+ @Override
+ public boolean matches(ProgramList.Chunk actual) {
+ if ((mExpected.isPurge() != actual.isPurge())
+ || (mExpected.isComplete() != actual.isComplete())
+ || (!mExpected.getRemoved().equals(actual.getRemoved()))) {
+ return false;
+ }
+ Set<RadioManager.ProgramInfo> expectedModified = mExpected.getModified();
+ Set<RadioManager.ProgramInfo> actualModified = new HashSet<>(actual.getModified());
+ if (expectedModified.size() != actualModified.size()) {
+ return false;
+ }
+ for (RadioManager.ProgramInfo expectedInfo : expectedModified) {
+ boolean found = false;
+ for (RadioManager.ProgramInfo actualInfo : actualModified) {
+ if (expectedInfo.equals(actualInfo)) {
+ found = true;
+ actualModified.remove(actualInfo);
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ // @Test
+ // public void testProgramInfoHashCode() {
+ // RadioManager.ProgramInfo info1 = TestUtils.makeProgramInfo(
+ // ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
+ // RadioManager.ProgramInfo info2 = TestUtils.makeProgramInfo(
+ // ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
+ // assertEquals(info1, info2);
+ // assertEquals(info1.hashCode(), info2.hashCode());
+ // }
+}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java
new file mode 100644
index 000000000000..4944803eaafe
--- /dev/null
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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.broadcastradio.hal2;
+
+import android.hardware.broadcastradio.V2_0.ProgramInfo;
+import android.hardware.radio.ProgramSelector;
+import android.hardware.radio.RadioManager;
+import android.hardware.radio.RadioMetadata;
+
+import java.util.HashMap;
+
+final class TestUtils {
+ static RadioManager.ProgramInfo makeProgramInfo(int programType,
+ ProgramSelector.Identifier identifier, int signalQuality) {
+ // Note: If you set new fields, check if programInfoToHal() needs to be updated as well.
+ return new RadioManager.ProgramInfo(new ProgramSelector(programType, identifier, null,
+ null), null, null, null, 0, signalQuality, new RadioMetadata.Builder().build(),
+ new HashMap<String, String>());
+ }
+
+ static ProgramInfo programInfoToHal(RadioManager.ProgramInfo info) {
+ // Note that because Convert does not by design provide functions for all conversions, this
+ // function only copies fields that are set by makeProgramInfo().
+ ProgramInfo hwInfo = new ProgramInfo();
+ hwInfo.selector = Convert.programSelectorToHal(info.getSelector());
+ hwInfo.signalQuality = info.getSignalStrength();
+ return hwInfo;
+ }
+}
diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index cadf37e0c53c..9d09830c585b 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -17,8 +17,11 @@
package android.view;
import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.TOOL_TYPE_FINGER;
+import static junit.framework.Assert.assertTrue;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -77,4 +80,62 @@ public class MotionEventTest {
0, 0, 0, 0, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, displayId, 0);
assertNull(motionEvent);
}
+
+ @Test
+ public void testCalculatesCursorPositionForTouchscreenEvents() {
+ final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+ ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
+ event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+
+ assertTrue(Float.isNaN(event.getXCursorPosition()));
+ assertTrue(Float.isNaN(event.getYCursorPosition()));
+ }
+
+ @Test
+ public void testCalculatesCursorPositionForSimpleMouseEvents() {
+ final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+ ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
+ event.setSource(InputDevice.SOURCE_MOUSE);
+
+ assertEquals(30, event.getXCursorPosition(), 0.1);
+ assertEquals(50, event.getYCursorPosition(), 0.1);
+ }
+
+ @Test
+ public void testCalculatesCursorPositionForSimpleMouseEventsWithOffset() {
+ final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+ ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
+ event.offsetLocation(10 /* deltaX */, 20 /* deltaY */);
+ event.setSource(InputDevice.SOURCE_MOUSE);
+
+ assertEquals(40, event.getXCursorPosition(), 0.1);
+ assertEquals(70, event.getYCursorPosition(), 0.1);
+ }
+
+
+ @Test
+ public void testCalculatesCursorPositionForMultiTouchMouseEvents() {
+ final int pointerCount = 2;
+ final PointerProperties[] properties = new PointerProperties[pointerCount];
+ final PointerCoords[] coords = new PointerCoords[pointerCount];
+
+ for (int i = 0; i < pointerCount; ++i) {
+ properties[i] = new PointerProperties();
+ properties[i].id = i;
+ properties[i].toolType = MotionEvent.TOOL_TYPE_FINGER;
+
+ coords[i] = new PointerCoords();
+ coords[i].x = 20 + i * 20;
+ coords[i].y = 60 - i * 20;
+ }
+
+ final MotionEvent event = MotionEvent.obtain(0 /* downTime */,
+ 0 /* eventTime */, ACTION_POINTER_DOWN, pointerCount, properties, coords,
+ 0 /* metaState */, 0 /* buttonState */, 1 /* xPrecision */, 1 /* yPrecision */,
+ 0 /* deviceId */, 0 /* edgeFlags */, InputDevice.SOURCE_MOUSE,
+ 0 /* flags */);
+
+ assertEquals(30, event.getXCursorPosition(), 0.1);
+ assertEquals(50, event.getYCursorPosition(), 0.1);
+ }
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index adaae5cdba8d..682416c58c72 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -132,6 +132,8 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
public void sendGesture(int sequence, ParceledListSlice gestureSteps) {}
+ public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {}
+
public boolean isFingerprintGestureDetectionAvailable() {
return false;
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
index 008085e38dbf..dc9208de7198 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -68,12 +68,7 @@ public class KernelWakelockReaderTest extends TestCase {
private WakeLockInfo createWakeLockInfo(String name, int activeCount, long totalTime) {
WakeLockInfo info = new WakeLockInfo();
info.name = name;
- info.pid = 1;
info.activeCount = activeCount;
- info.isActive = true;
- info.activeSince = 0;
- info.lastChange = 0;
- info.maxTime = 0;
info.totalTime = totalTime;
return info;
}
@@ -89,7 +84,7 @@ public class KernelWakelockReaderTest extends TestCase {
byte[] buffer, WakeLockInfo[] wlStats) {
mReader.updateVersion(staleStats);
mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
- mReader.getNativeWakelockStats(wlStats, staleStats);
+ mReader.updateWakelockStats(wlStats, staleStats);
return mReader.removeOldStats(staleStats);
}
@@ -101,7 +96,7 @@ public class KernelWakelockReaderTest extends TestCase {
mReader = new KernelWakelockReader();
}
-// ------------------------- Kernel Wakelock Stats Test ------------------------
+// ------------------------- Legacy Wakelock Stats Test ------------------------
@SmallTest
public void testParseEmptyFile() throws Exception {
KernelWakelockStats staleStats = mReader.parseProcWakelocks(new byte[0], 0, true,
@@ -196,10 +191,10 @@ public class KernelWakelockReaderTest extends TestCase {
assertFalse(staleStats.containsKey("Fakelock"));
}
-// -------------------- Native (SystemSuspend) Wakelock Stats Test -------------------
+// -------------------- SystemSuspend Wakelock Stats Test -------------------
@SmallTest
public void testEmptyWakeLockInfoList() {
- KernelWakelockStats staleStats = mReader.getNativeWakelockStats(new WakeLockInfo[0],
+ KernelWakelockStats staleStats = mReader.updateWakelockStats(new WakeLockInfo[0],
new KernelWakelockStats());
assertTrue(staleStats.isEmpty());
@@ -208,9 +203,9 @@ public class KernelWakelockReaderTest extends TestCase {
@SmallTest
public void testOneWakeLockInfo() {
WakeLockInfo[] wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock", 20, 10000);
+ wlStats[0] = createWakeLockInfo("WakeLock", 20, 1000); // Milliseconds
- KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
+ KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
new KernelWakelockStats());
assertEquals(1, staleStats.size());
@@ -219,16 +214,16 @@ public class KernelWakelockReaderTest extends TestCase {
KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
assertEquals(20, entry.mCount);
- assertEquals(10000, entry.mTotalTime);
+ assertEquals(1000 * 1000, entry.mTotalTime); // Microseconds
}
@SmallTest
public void testTwoWakeLockInfos() {
WakeLockInfo[] wlStats = new WakeLockInfo[2];
- wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
- wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000);
+ wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds
+ wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds
- KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
+ KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
new KernelWakelockStats());
assertEquals(2, staleStats.size());
@@ -238,17 +233,17 @@ public class KernelWakelockReaderTest extends TestCase {
KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
assertEquals(10, entry1.mCount);
- assertEquals(1000, entry1.mTotalTime);
+ assertEquals(1000 * 1000, entry1.mTotalTime); // Microseconds
KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
assertEquals(20, entry2.mCount);
- assertEquals(2000, entry2.mTotalTime);
+ assertEquals(2000 * 1000, entry2.mTotalTime); // Microseconds
}
@SmallTest
public void testWakeLockInfosBecomeStale() {
WakeLockInfo[] wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
+ wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds
KernelWakelockStats staleStats = new KernelWakelockStats();
@@ -259,9 +254,9 @@ public class KernelWakelockReaderTest extends TestCase {
assertTrue(staleStats.containsKey("WakeLock1"));
KernelWakelockStats.Entry entry = staleStats.get("WakeLock1");
assertEquals(10, entry.mCount);
- assertEquals(1000, entry.mTotalTime);
+ assertEquals(1000 * 1000, entry.mTotalTime); // Microseconds
- wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000);
+ wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds
readKernelWakelockStats(staleStats, new byte[0], wlStats);
@@ -271,7 +266,7 @@ public class KernelWakelockReaderTest extends TestCase {
assertTrue(staleStats.containsKey("WakeLock2"));
entry = staleStats.get("WakeLock2");
assertEquals(20, entry.mCount);
- assertEquals(2000, entry.mTotalTime);
+ assertEquals(2000 * 1000, entry.mTotalTime); // Micro seconds
}
// -------------------- Aggregate Wakelock Stats Tests --------------------
@@ -313,7 +308,7 @@ public class KernelWakelockReaderTest extends TestCase {
byte[] buffer = new byte[0];
WakeLockInfo[] wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock", 10, 1000);
+ wlStats[0] = createWakeLockInfo("WakeLock", 10, 1000); // Milliseconds
readKernelWakelockStats(staleStats, buffer, wlStats);
@@ -323,7 +318,7 @@ public class KernelWakelockReaderTest extends TestCase {
KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
assertEquals(10, entry.mCount);
- assertEquals(1000, entry.mTotalTime);
+ assertEquals(1000 * 1000, entry.mTotalTime); // Microseconds
}
@SmallTest
@@ -334,7 +329,7 @@ public class KernelWakelockReaderTest extends TestCase {
.addLine("WakeLock1", 34, 123) // Milliseconds
.getBytes();
WakeLockInfo[] wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock2", 10, 1000);
+ wlStats[0] = createWakeLockInfo("WakeLock2", 10, 1000); // Milliseconds
readKernelWakelockStats(staleStats, buffer, wlStats);
@@ -348,7 +343,7 @@ public class KernelWakelockReaderTest extends TestCase {
assertTrue(staleStats.containsKey("WakeLock2"));
KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
assertEquals(10, entry2.mCount);
- assertEquals(1000, entry2.mTotalTime);
+ assertEquals(1000 * 1000, entry2.mTotalTime); // Microseconds
}
@SmallTest
@@ -360,8 +355,8 @@ public class KernelWakelockReaderTest extends TestCase {
.addLine("WakeLock2", 46, 345) // Milliseconds
.getBytes();
WakeLockInfo[] wlStats = new WakeLockInfo[2];
- wlStats[0] = createWakeLockInfo("WakeLock3", 10, 1000);
- wlStats[1] = createWakeLockInfo("WakeLock4", 20, 2000);
+ wlStats[0] = createWakeLockInfo("WakeLock3", 10, 1000); // Milliseconds
+ wlStats[1] = createWakeLockInfo("WakeLock4", 20, 2000); // Milliseconds
readKernelWakelockStats(staleStats, buffer, wlStats);
@@ -382,18 +377,18 @@ public class KernelWakelockReaderTest extends TestCase {
KernelWakelockStats.Entry entry3 = staleStats.get("WakeLock3");
assertEquals(10, entry3.mCount);
- assertEquals(1000, entry3.mTotalTime);
+ assertEquals(1000 * 1000, entry3.mTotalTime); // Microseconds
KernelWakelockStats.Entry entry4 = staleStats.get("WakeLock4");
assertEquals(20, entry4.mCount);
- assertEquals(2000, entry4.mTotalTime);
+ assertEquals(2000 * 1000, entry4.mTotalTime); // Microseconds
buffer = new ProcFileBuilder()
.addLine("WakeLock1", 45, 789) // Milliseconds
.addLine("WakeLock1", 56, 123) // Milliseconds
.getBytes();
wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock4", 40, 4000);
+ wlStats[0] = createWakeLockInfo("WakeLock4", 40, 4000); // Milliseconds
readKernelWakelockStats(staleStats, buffer, wlStats);
@@ -411,6 +406,6 @@ public class KernelWakelockReaderTest extends TestCase {
entry2 = staleStats.get("WakeLock4");
assertEquals(40, entry2.mCount);
- assertEquals(4000, entry4.mTotalTime);
+ assertEquals(4000 * 1000, entry4.mTotalTime); // Microseconds
}
}
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index f01b1bfa780d..54ac0bd9ff75 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -454,7 +454,7 @@ void SkiaCanvas::drawPaint(const SkPaint& paint) {
// Canvas draw operations: Geometry
// ----------------------------------------------------------------------------
-void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
+void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint,
SkCanvas::PointMode mode) {
if (CC_UNLIKELY(count < 2 || paint.nothingToDraw())) return;
// convert the floats into SkPoints
@@ -464,109 +464,142 @@ void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint
pts[i].set(points[0], points[1]);
points += 2;
}
- mCanvas->drawPoints(mode, count, pts.get(), *filterPaint(paint));
+
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawPoints(mode, count, pts.get(), p);
+ });
}
-void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
- mCanvas->drawPoint(x, y, *filterPaint(paint));
+void SkiaCanvas::drawPoint(float x, float y, const Paint& paint) {
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawPoint(x, y, p);
+ });
}
-void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
- this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kPoints_PointMode);
+void SkiaCanvas::drawPoints(const float* points, int count, const Paint& paint) {
+ this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
}
void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
- const SkPaint& paint) {
- mCanvas->drawLine(startX, startY, stopX, stopY, *filterPaint(paint));
+ const Paint& paint) {
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawLine(startX, startY, stopX, stopY, p);
+ });
}
-void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
+void SkiaCanvas::drawLines(const float* points, int count, const Paint& paint) {
if (CC_UNLIKELY(count < 4 || paint.nothingToDraw())) return;
- this->drawPoints(points, count, *filterPaint(paint), SkCanvas::kLines_PointMode);
+ this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
}
-void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
+void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- mCanvas->drawRect({left, top, right, bottom}, *filterPaint(paint));
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawRect({left, top, right, bottom}, p);
+ });
}
-void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
+void SkiaCanvas::drawRegion(const SkRegion& region, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- mCanvas->drawRegion(region, *filterPaint(paint));
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawRegion(region, p);
+ });
}
void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
- const SkPaint& paint) {
+ const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
- mCanvas->drawRoundRect(rect, rx, ry, *filterPaint(paint));
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawRoundRect(rect, rx, ry, p);
+ });
}
void SkiaCanvas::drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
- const SkPaint& paint) {
- mCanvas->drawDRRect(outer, inner, *filterPaint(paint));
+ const Paint& paint) {
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawDRRect(outer, inner, p);
+ });
}
-void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
+void SkiaCanvas::drawCircle(float x, float y, float radius, const Paint& paint) {
if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
- mCanvas->drawCircle(x, y, radius, *filterPaint(paint));
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawCircle(x, y, radius, p);
+ });
}
-void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
+void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
- mCanvas->drawOval(oval, *filterPaint(paint));
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawOval(oval, p);
+ });
}
void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
- float sweepAngle, bool useCenter, const SkPaint& paint) {
+ float sweepAngle, bool useCenter, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
- if (fabs(sweepAngle) >= 360.0f) {
- mCanvas->drawOval(arc, *filterPaint(paint));
- } else {
- mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, *filterPaint(paint));
- }
+ apply_looper(&paint, [&](const SkPaint& p) {
+ if (fabs(sweepAngle) >= 360.0f) {
+ mCanvas->drawOval(arc, p);
+ } else {
+ mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, p);
+ }
+ });
}
-void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
+void SkiaCanvas::drawPath(const SkPath& path, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) {
return;
}
- mCanvas->drawPath(path, *filterPaint(paint));
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawPath(path, p);
+ });
}
-void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
- mCanvas->drawVertices(vertices, mode, *filterPaint(paint));
+void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const Paint& paint) {
+ apply_looper(&paint, [&](const SkPaint& p) {
+ mCanvas->drawVertices(vertices, mode, p);
+ });
}
// ----------------------------------------------------------------------------
// Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
- mCanvas->drawImage(bitmap.makeImage(), left, top, filterPaint(paint));
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
+ auto image = bitmap.makeImage();
+ apply_looper(paint, [&](const SkPaint& p) {
+ mCanvas->drawImage(image, left, top, &p);
+ });
}
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) {
+ auto image = bitmap.makeImage();
SkAutoCanvasRestore acr(mCanvas, true);
mCanvas->concat(matrix);
- mCanvas->drawImage(bitmap.makeImage(), 0, 0, filterPaint(paint));
+ apply_looper(paint, [&](const SkPaint& p) {
+ mCanvas->drawImage(image, 0, 0, &p);
+ });
}
void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
float srcBottom, float dstLeft, float dstTop, float dstRight,
- float dstBottom, const SkPaint* paint) {
+ float dstBottom, const Paint* paint) {
+ auto image = bitmap.makeImage();
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- mCanvas->drawImageRect(bitmap.makeImage(), srcRect, dstRect, filterPaint(paint),
- SkCanvas::kFast_SrcRectConstraint);
+ apply_looper(paint, [&](const SkPaint& p) {
+ mCanvas->drawImageRect(image, srcRect, dstRect, &p, SkCanvas::kFast_SrcRectConstraint);
+ });
}
void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) {
+ const float* vertices, const int* colors, const Paint* paint) {
const int ptCount = (meshWidth + 1) * (meshHeight + 1);
const int indexCount = meshWidth * meshHeight * 6;
uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
@@ -640,20 +673,20 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
#endif
// cons-up a shader for the bitmap
- PaintCoW paintCoW(paint);
- SkPaint& tmpPaint = paintCoW.writeable();
-
- sk_sp<SkImage> image = bitmap.makeImage();
- sk_sp<SkShader> shader = image->makeShader();
- tmpPaint.setShader(std::move(shader));
-
- mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate,
- *filterPaint(std::move(paintCoW)));
+ Paint pnt;
+ if (paint) {
+ pnt = *paint;
+ }
+ pnt.setShader(bitmap.makeImage()->makeShader());
+ auto v = builder.detach();
+ apply_looper(&pnt, [&](const SkPaint& p) {
+ mCanvas->drawVertices(v, SkBlendMode::kModulate, p);
+ });
}
void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) {
+ const Paint* paint) {
SkCanvas::Lattice lattice;
NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
@@ -674,8 +707,10 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-
- mCanvas->drawImageLattice(bitmap.makeImage().get(), lattice, dst, filterPaint(paint));
+ auto image = bitmap.makeImage();
+ apply_looper(paint, [&](const SkPaint& p) {
+ mCanvas->drawImageLattice(image.get(), lattice, dst, &p);
+ });
}
double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) {
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 799a89158298..ec83a1961eff 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -22,8 +22,10 @@
#include "RenderNode.h"
#include "VectorDrawable.h"
#include "hwui/Canvas.h"
+#include "hwui/Paint.h"
#include <SkCanvas.h>
+#include "src/core/SkArenaAlloc.h"
#include <cassert>
#include <optional>
@@ -99,39 +101,39 @@ public:
virtual void drawColor(int color, SkBlendMode mode) override;
virtual void drawPaint(const SkPaint& paint) override;
- virtual void drawPoint(float x, float y, const SkPaint& paint) override;
- virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
+ virtual void drawPoint(float x, float y, const Paint& paint) override;
+ virtual void drawPoints(const float* points, int count, const Paint& paint) override;
virtual void drawLine(float startX, float startY, float stopX, float stopY,
- const SkPaint& paint) override;
- virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
+ const Paint& paint) override;
+ virtual void drawLines(const float* points, int count, const Paint& paint) override;
virtual void drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) override;
- virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override;
+ const Paint& paint) override;
+ virtual void drawRegion(const SkRegion& region, const Paint& paint) override;
virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
- const SkPaint& paint) override;
+ const Paint& paint) override;
virtual void drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
- const SkPaint& paint) override;
+ const Paint& paint) override;
- virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
+ virtual void drawCircle(float x, float y, float radius, const Paint& paint) override;
virtual void drawOval(float left, float top, float right, float bottom,
- const SkPaint& paint) override;
+ const Paint& paint) override;
virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
- float sweepAngle, bool useCenter, const SkPaint& paint) override;
- virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
- virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) override;
+ float sweepAngle, bool useCenter, const Paint& paint) override;
+ virtual void drawPath(const SkPath& path, const Paint& paint) override;
+ virtual void drawVertices(const SkVertices*, SkBlendMode, const Paint& paint) override;
- virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) override;
virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
float srcBottom, float dstLeft, float dstTop, float dstRight,
- float dstBottom, const SkPaint* paint) override;
+ float dstBottom, const Paint* paint) override;
virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors,
- const SkPaint* paint) override;
+ const Paint* paint) override;
virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) override;
+ const Paint* paint) override;
virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) override;
virtual bool drawTextAbsolutePos() const override { return true; }
@@ -208,6 +210,35 @@ protected:
*/
PaintCoW&& filterPaint(PaintCoW&& paint) const;
+ template <typename Proc> void apply_looper(const Paint* paint, Proc proc) {
+ SkPaint skp;
+ SkDrawLooper* looper = nullptr;
+ if (paint) {
+ skp = *filterPaint(paint);
+ looper = paint->getLooper();
+ }
+ if (looper) {
+ SkSTArenaAlloc<256> alloc;
+ SkDrawLooper::Context* ctx = looper->makeContext(&alloc);
+ if (ctx) {
+ SkDrawLooper::Context::Info info;
+ for (;;) {
+ SkPaint p = skp;
+ if (!ctx->next(&info, &p)) {
+ break;
+ }
+ mCanvas->save();
+ mCanvas->translate(info.fTranslate.fX, info.fTranslate.fY);
+ proc(p);
+ mCanvas->restore();
+ }
+ }
+ } else {
+ proc(skp);
+ }
+ }
+
+
private:
struct SaveRec {
int saveCount;
@@ -222,7 +253,7 @@ private:
void recordClip(const T&, SkClipOp);
void applyPersistentClips(size_t clipStartIndex);
- void drawPoints(const float* points, int count, const SkPaint& paint, SkCanvas::PointMode mode);
+ void drawPoints(const float* points, int count, const Paint& paint, SkCanvas::PointMode mode);
class Clip;
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 89ad1b99c6b6..f91d178f01f3 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -17,6 +17,7 @@
#include "VectorDrawable.h"
#include <utils/Log.h>
+#include "hwui/Paint.h"
#include "PathParser.h"
#include "SkColorFilter.h"
#include "SkImageInfo.h"
@@ -458,8 +459,12 @@ void Tree::drawStaging(Canvas* outCanvas) {
mStagingCache.dirty = false;
}
- SkPaint paint;
- getPaintFor(&paint, mStagingProperties);
+ SkPaint skp;
+ getPaintFor(&skp, mStagingProperties);
+ Paint paint;
+ paint.setFilterQuality(skp.getFilterQuality());
+ paint.setColorFilter(skp.refColorFilter());
+ paint.setAlpha(skp.getAlpha());
outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0, mStagingCache.bitmap->width(),
mStagingCache.bitmap->height(), mStagingProperties.getBounds().left(),
mStagingProperties.getBounds().top(),
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index a48c86028262..b98ffca84dfc 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -34,7 +34,7 @@ Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::Rende
}
static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness,
- const SkPaint& paint, Canvas* canvas) {
+ const Paint& paint, Canvas* canvas) {
const SkScalar strokeWidth = fmax(thickness, 1.0f);
const SkScalar bottom = top + strokeWidth;
canvas->drawRect(left, top, right, bottom, paint);
@@ -182,7 +182,7 @@ void Canvas::drawText(const uint16_t* text, int textSize, int start, int count,
void Canvas::drawDoubleRoundRectXY(float outerLeft, float outerTop, float outerRight,
float outerBottom, float outerRx, float outerRy, float innerLeft,
float innerTop, float innerRight, float innerBottom, float innerRx,
- float innerRy, const SkPaint& paint) {
+ float innerRy, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect outer = SkRect::MakeLTRB(outerLeft, outerTop, outerRight, outerBottom);
SkRect inner = SkRect::MakeLTRB(innerLeft, innerTop, innerRight, innerBottom);
@@ -198,7 +198,7 @@ void Canvas::drawDoubleRoundRectXY(float outerLeft, float outerTop, float outerR
void Canvas::drawDoubleRoundRectRadii(float outerLeft, float outerTop, float outerRight,
float outerBottom, const float* outerRadii, float innerLeft,
float innerTop, float innerRight, float innerBottom,
- const float* innerRadii, const SkPaint& paint) {
+ const float* innerRadii, const Paint& paint) {
static_assert(sizeof(SkVector) == sizeof(float) * 2);
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect outer = SkRect::MakeLTRB(outerLeft, outerTop, outerRight, outerBottom);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index ee4fa1d689ef..b90a4a3d68e6 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -217,37 +217,37 @@ public:
virtual void drawPaint(const SkPaint& paint) = 0;
// Geometry
- virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
- virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) = 0;
+ virtual void drawPoint(float x, float y, const Paint& paint) = 0;
+ virtual void drawPoints(const float* points, int floatCount, const Paint& paint) = 0;
virtual void drawLine(float startX, float startY, float stopX, float stopY,
- const SkPaint& paint) = 0;
- virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) = 0;
+ const Paint& paint) = 0;
+ virtual void drawLines(const float* points, int floatCount, const Paint& paint) = 0;
virtual void drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) = 0;
- virtual void drawRegion(const SkRegion& region, const SkPaint& paint) = 0;
+ const Paint& paint) = 0;
+ virtual void drawRegion(const SkRegion& region, const Paint& paint) = 0;
virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
- const SkPaint& paint) = 0;
+ const Paint& paint) = 0;
virtual void drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
- const SkPaint& paint) = 0;
- virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
+ const Paint& paint) = 0;
+ virtual void drawCircle(float x, float y, float radius, const Paint& paint) = 0;
virtual void drawOval(float left, float top, float right, float bottom,
- const SkPaint& paint) = 0;
+ const Paint& paint) = 0;
virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
- float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
- virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
- virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) = 0;
+ float sweepAngle, bool useCenter, const Paint& paint) = 0;
+ virtual void drawPath(const SkPath& path, const Paint& paint) = 0;
+ virtual void drawVertices(const SkVertices*, SkBlendMode, const Paint& paint) = 0;
// Bitmap-based
- virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) = 0;
- virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) = 0;
+ virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) = 0;
+ virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) = 0;
virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
float srcBottom, float dstLeft, float dstTop, float dstRight,
- float dstBottom, const SkPaint* paint) = 0;
+ float dstBottom, const Paint* paint) = 0;
virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) = 0;
+ const float* vertices, const int* colors, const Paint* paint) = 0;
virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) = 0;
+ const Paint* paint) = 0;
virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) = 0;
virtual void drawPicture(const SkPicture& picture) = 0;
@@ -281,12 +281,12 @@ public:
void drawDoubleRoundRectXY(float outerLeft, float outerTop, float outerRight,
float outerBottom, float outerRx, float outerRy, float innerLeft,
float innerTop, float innerRight, float innerBottom, float innerRx,
- float innerRy, const SkPaint& paint);
+ float innerRy, const Paint& paint);
void drawDoubleRoundRectRadii(float outerLeft, float outerTop, float outerRight,
float outerBottom, const float* outerRadii, float innerLeft,
float innerTop, float innerRight, float innerBottom,
- const float* innerRadii, const SkPaint& paint);
+ const float* innerRadii, const Paint& paint);
static int GetApiLevel() { return sApiLevel; }
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 9b2fa9df1e8f..281ecd27d780 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -21,6 +21,7 @@
#include <cutils/compiler.h>
+#include <SkDrawLooper.h>
#include <SkFont.h>
#include <SkPaint.h>
#include <string>
@@ -58,12 +59,17 @@ public:
SkFont& getSkFont() { return mFont; }
const SkFont& getSkFont() const { return mFont; }
+ SkDrawLooper* getLooper() const { return mLooper.get(); }
+ void setLooper(sk_sp<SkDrawLooper> looper) { mLooper = std::move(looper); }
+
// These shadow the methods on SkPaint, but we need to so we can keep related
// attributes in-sync.
void reset();
void setAntiAlias(bool);
+ bool nothingToDraw() const { return !mLooper && SkPaint::nothingToDraw(); }
+
// End method shadowing
void setLetterSpacing(float letterSpacing) { mLetterSpacing = letterSpacing; }
@@ -146,6 +152,7 @@ public:
private:
SkFont mFont;
+ sk_sp<SkDrawLooper> mLooper;
float mLetterSpacing = 0;
float mWordSpacing = 0;
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index 2f2d575bca29..fa2674fc2f5e 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -34,6 +34,7 @@ Paint::Paint()
Paint::Paint(const Paint& paint)
: SkPaint(paint)
, mFont(paint.mFont)
+ , mLooper(paint.mLooper)
, mLetterSpacing(paint.mLetterSpacing)
, mWordSpacing(paint.mWordSpacing)
, mFontFeatureSettings(paint.mFontFeatureSettings)
@@ -52,6 +53,7 @@ Paint::~Paint() {}
Paint& Paint::operator=(const Paint& other) {
SkPaint::operator=(other);
mFont = other.mFont;
+ mLooper = other.mLooper;
mLetterSpacing = other.mLetterSpacing;
mWordSpacing = other.mWordSpacing;
mFontFeatureSettings = other.mFontFeatureSettings;
@@ -69,6 +71,7 @@ Paint& Paint::operator=(const Paint& other) {
bool operator==(const Paint& a, const Paint& b) {
return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) &&
a.mFont == b.mFont &&
+ a.mLooper == b.mLooper &&
a.mLetterSpacing == b.mLetterSpacing && a.mWordSpacing == b.mWordSpacing &&
a.mFontFeatureSettings == b.mFontFeatureSettings &&
a.mMinikinLocaleListId == b.mMinikinLocaleListId &&
@@ -83,6 +86,7 @@ void Paint::reset() {
mFont = SkFont();
mFont.setEdging(SkFont::Edging::kAlias);
+ mLooper.reset();
mStrikeThru = false;
mUnderline = false;
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 96b17e1d7975..b0173846e582 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -33,6 +33,10 @@ void LayerDrawable::onDraw(SkCanvas* canvas) {
}
}
+static inline SkScalar isIntegerAligned(SkScalar x) {
+ return fabsf(roundf(x) - x) <= NON_ZERO_EPSILON;
+}
+
// Disable filtering when there is no scaling in screen coordinates and the corners have the same
// fraction (for translate) or zero fraction (for any other rect-to-rect transform).
static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, const SkRect& dstRect) {
@@ -62,10 +66,10 @@ static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, cons
if (requiresIntegerTranslate) {
// Device rect and source rect should be integer aligned to ensure there's no difference
// in how nearest-neighbor sampling is resolved.
- return !(MathUtils::isZero(SkScalarFraction(srcRect.x())) &&
- MathUtils::isZero(SkScalarFraction(srcRect.y())) &&
- MathUtils::isZero(SkScalarFraction(dstDevRect.x())) &&
- MathUtils::isZero(SkScalarFraction(dstDevRect.y())));
+ return !(isIntegerAligned(srcRect.x()) &&
+ isIntegerAligned(srcRect.y()) &&
+ isIntegerAligned(dstDevRect.x()) &&
+ isIntegerAligned(dstDevRect.y()));
} else {
// As long as src and device rects are translated by the same fractional amount,
// filtering won't be needed
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 38ef131bedef..0db5133037b0 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -15,7 +15,7 @@
*/
#include "SkiaRecordingCanvas.h"
-
+#include "hwui/Paint.h"
#include <SkImagePriv.h>
#include "CanvasTransform.h"
#ifdef __ANDROID__ // Layoutlib does not support Layers
@@ -197,9 +197,37 @@ SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint) {
return filterPaint(std::move(paint));
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
+static SkDrawLooper* get_looper(const Paint* paint) {
+ return paint ? paint->getLooper() : nullptr;
+}
+
+template <typename Proc>
+void applyLooper(SkDrawLooper* looper, const SkPaint& paint, Proc proc) {
+ if (looper) {
+ SkSTArenaAlloc<256> alloc;
+ SkDrawLooper::Context* ctx = looper->makeContext(&alloc);
+ if (ctx) {
+ SkDrawLooper::Context::Info info;
+ for (;;) {
+ SkPaint p = paint;
+ if (!ctx->next(&info, &p)) {
+ break;
+ }
+ proc(info.fTranslate.fX, info.fTranslate.fY, p);
+ }
+ }
+ } else {
+ proc(0, 0, paint);
+ }
+}
+
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
sk_sp<SkImage> image = bitmap.makeImage();
- mRecorder.drawImage(image, left, top, filterBitmap(paint), bitmap.palette());
+
+ applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+ mRecorder.drawImage(image, left + x, top + y, &p, bitmap.palette());
+ });
+
// if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
// it is not safe to store a raw SkImage pointer, because the image object will be destroyed
// when this function ends.
@@ -208,12 +236,16 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, cons
}
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) {
SkAutoCanvasRestore acr(&mRecorder, true);
concat(matrix);
sk_sp<SkImage> image = bitmap.makeImage();
- mRecorder.drawImage(image, 0, 0, filterBitmap(paint), bitmap.palette());
+
+ applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+ mRecorder.drawImage(image, x, y, &p, bitmap.palette());
+ });
+
if (!bitmap.isImmutable() && image.get() && !image->unique()) {
mDisplayList->mMutableImages.push_back(image.get());
}
@@ -221,13 +253,17 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
float srcBottom, float dstLeft, float dstTop, float dstRight,
- float dstBottom, const SkPaint* paint) {
+ float dstBottom, const Paint* paint) {
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
sk_sp<SkImage> image = bitmap.makeImage();
- mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint),
- SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
+
+ applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+ mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), &p,
+ SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
+ });
+
if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
!dstRect.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
@@ -236,7 +272,7 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop
void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) {
+ const Paint* paint) {
SkCanvas::Lattice lattice;
NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
@@ -264,8 +300,11 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch
filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality);
}
sk_sp<SkImage> image = bitmap.makeImage();
- mRecorder.drawImageLattice(image, lattice, dst, filterBitmap(std::move(filteredPaint)),
- bitmap.palette());
+
+ applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
+ mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), &p, bitmap.palette());
+ });
+
if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index c42cea33211e..bd5274c94e75 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -45,14 +45,14 @@ public:
virtual uirenderer::DisplayList* finishRecording() override;
- virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) override;
virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
float srcBottom, float dstLeft, float dstTop, float dstRight,
- float dstBottom, const SkPaint* paint) override;
+ float dstBottom, const Paint* paint) override;
virtual void drawNinePatch(Bitmap& hwuiBitmap, const android::Res_png_9patch& chunk,
float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) override;
+ const Paint* paint) override;
virtual double drawAnimatedImage(AnimatedImageDrawable* animatedImage) override;
virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index d97c5ed4c7f5..d19351bf1db9 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -450,20 +450,38 @@ void CanvasContext::draw() {
waitOnFences();
bool requireSwap = false;
+ int error = OK;
bool didSwap =
mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
mIsDirty = false;
if (requireSwap) {
- if (!didSwap) { // some error happened
+ bool didDraw = true;
+ // Handle any swapchain errors
+ error = mNativeSurface->getAndClearError();
+ if (error == TIMED_OUT) {
+ // Try again
+ mRenderThread.postFrameCallback(this);
+ // But since this frame didn't happen, we need to mark full damage in the swap
+ // history
+ didDraw = false;
+
+ } else if (error != OK || !didSwap) {
+ // Unknown error, abandon the surface
setSurface(nullptr);
+ didDraw = false;
}
+
SwapHistory& swap = mSwapHistory.next();
- swap.damage = windowDirty;
+ if (didDraw) {
+ swap.damage = windowDirty;
+ } else {
+ swap.damage = SkRect::MakeWH(INT_MAX, INT_MAX);
+ }
swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC);
swap.vsyncTime = mRenderThread.timeLord().latestVsync();
- if (mNativeSurface.get()) {
+ if (didDraw) {
int durationUs;
nsecs_t dequeueStart = mNativeSurface->getLastDequeueStartTime();
if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) {
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
index ad1fc4921781..a44b80457218 100644
--- a/libs/hwui/renderthread/ReliableSurface.cpp
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -87,21 +87,21 @@ void ReliableSurface::perform(int operation, va_list args) {
}
int ReliableSurface::reserveNext() {
+ if constexpr (DISABLE_BUFFER_PREFETCH) {
+ return OK;
+ }
{
std::lock_guard _lock{mMutex};
if (mReservedBuffer) {
ALOGW("reserveNext called but there was already a buffer reserved?");
return OK;
}
- if (mInErrorState) {
+ if (mBufferQueueState != OK) {
return UNKNOWN_ERROR;
}
if (mHasDequeuedBuffer) {
return OK;
}
- if constexpr (DISABLE_BUFFER_PREFETCH) {
- return OK;
- }
}
// TODO: Update this to better handle when requested dimensions have changed
@@ -165,10 +165,11 @@ int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) {
}
}
+
int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
if (result != OK) {
ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
- *buffer = acquireFallbackBuffer();
+ *buffer = acquireFallbackBuffer(result);
*fenceFd = -1;
return *buffer ? OK : INVALID_OPERATION;
} else {
@@ -201,9 +202,9 @@ bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer)
return windowBuffer == scratchBuffer;
}
-ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() {
+ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer(int error) {
std::lock_guard _lock{mMutex};
- mInErrorState = true;
+ mBufferQueueState = error;
if (mScratchBuffer) {
return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index 0bfc72ef61cb..41fc35eca9f7 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -43,6 +43,12 @@ public:
uint64_t getNextFrameNumber() const { return mSurface->getNextFrameNumber(); }
+ int getAndClearError() {
+ int ret = mBufferQueueState;
+ mBufferQueueState = OK;
+ return ret;
+ }
+
private:
const sp<Surface> mSurface;
@@ -55,10 +61,10 @@ private:
ANativeWindowBuffer* mReservedBuffer = nullptr;
base::unique_fd mReservedFenceFd;
bool mHasDequeuedBuffer = false;
- bool mInErrorState = false;
+ int mBufferQueueState = OK;
bool isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const;
- ANativeWindowBuffer* acquireFallbackBuffer();
+ ANativeWindowBuffer* acquireFallbackBuffer(int error);
void clearReservedBuffer();
void perform(int operation, va_list args);
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 400196b203b9..c4067af388e3 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -15,6 +15,7 @@
*/
#include <SkImagePriv.h>
+#include "hwui/Paint.h"
#include "TestSceneBase.h"
#include "tests/common/BitmapAllocationTestUtils.h"
#include "utils/Color.h"
@@ -43,7 +44,7 @@ public:
skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
});
- SkPaint paint;
+ Paint paint;
sk_sp<SkImage> image = hwuiBitmap->makeImage();
sk_sp<SkShader> repeatShader =
image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat);
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 659926bae06f..3d0a2b2474bf 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -65,7 +65,7 @@ public:
sk_sp<SkShader> compositeShader(
SkShaders::Blend(SkBlendMode::kDstATop, hardwareShader, gradientShader));
- SkPaint paint;
+ Paint paint;
paint.setShader(std::move(compositeShader));
canvas.drawRoundRect(0, 0, 400, 200, 10.0f, 10.0f, paint);
}
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index c6b60aaec9c5..a9449b62a1f8 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -49,7 +49,7 @@ class ListOfFadedTextAnimation : public TestListViewSceneBase {
SkMatrix matrix;
matrix.setScale(1, length);
matrix.postRotate(-90);
- SkPaint fadingPaint;
+ Paint fadingPaint;
fadingPaint.setShader(s->makeWithLocalMatrix(matrix));
fadingPaint.setBlendMode(SkBlendMode::kDstOut);
canvas.drawRect(0, 0, length, itemHeight, fadingPaint);
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index fb7e34dfa513..d031923a112b 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -79,7 +79,7 @@ class ListViewAnimation : public TestListViewSceneBase {
static sk_sp<Bitmap> filledBox(createBoxBitmap(true));
static sk_sp<Bitmap> strokedBox(createBoxBitmap(false));
// TODO: switch to using round rect clipping, once merging correctly handles that
- SkPaint roundRectPaint;
+ Paint roundRectPaint;
roundRectPaint.setAntiAlias(true);
roundRectPaint.setColor(Color::White);
canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint);
diff --git a/libs/hwui/tests/common/scenes/OvalAnimation.cpp b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
index 4ff868b9d068..402c1ece2146 100644
--- a/libs/hwui/tests/common/scenes/OvalAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
@@ -28,7 +28,7 @@ public:
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
- SkPaint paint;
+ Paint paint;
paint.setAntiAlias(true);
paint.setColor(Color::Black);
canvas.drawOval(0, 0, 200, 200, paint);
diff --git a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
index 6a3b6a57b28a..d5ecfaff4f0c 100644
--- a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
@@ -41,7 +41,7 @@ public:
}
}
- SkPaint paint;
+ Paint paint;
paint.setColor(0xff00ffff);
canvas.drawRegion(region, paint);
});
diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
index 02dd42ff2ae8..97bfba34c790 100644
--- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
@@ -45,7 +45,7 @@ public:
canvas.save(SaveFlags::MatrixClip);
canvas.translate(0, 400);
canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::Flags(0)); // unclipped
- SkPaint paint;
+ Paint paint;
paint.setAntiAlias(true);
paint.setColor(Color::Green_700);
canvas.drawCircle(200, 200, 200, paint);
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index d189a9379c33..70a1557dcf6a 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -30,14 +30,14 @@ public:
void createContent(int width, int height, Canvas& canvas) override {
card = TestUtils::createNode(
0, 0, width, height, [width](RenderProperties& props, Canvas& canvas) {
- std::function<void(Canvas&, float, const SkPaint&)> ops[] = {
- [](Canvas& canvas, float size, const SkPaint& paint) {
+ std::function<void(Canvas&, float, const Paint&)> ops[] = {
+ [](Canvas& canvas, float size, const Paint& paint) {
canvas.drawArc(0, 0, size, size, 50, 189, true, paint);
},
- [](Canvas& canvas, float size, const SkPaint& paint) {
+ [](Canvas& canvas, float size, const Paint& paint) {
canvas.drawOval(0, 0, size, size, paint);
},
- [](Canvas& canvas, float size, const SkPaint& paint) {
+ [](Canvas& canvas, float size, const Paint& paint) {
SkPath diamondPath;
diamondPath.moveTo(size / 2, 0);
diamondPath.lineTo(size, size / 2);
@@ -46,18 +46,18 @@ public:
diamondPath.close();
canvas.drawPath(diamondPath, paint);
},
- [](Canvas& canvas, float size, const SkPaint& paint) {
+ [](Canvas& canvas, float size, const Paint& paint) {
float data[] = {0, 0, size, size, 0, size, size, 0};
canvas.drawLines(data, sizeof(data) / sizeof(float), paint);
},
- [](Canvas& canvas, float size, const SkPaint& paint) {
+ [](Canvas& canvas, float size, const Paint& paint) {
float data[] = {0, 0, size, size, 0, size, size, 0};
canvas.drawPoints(data, sizeof(data) / sizeof(float), paint);
},
- [](Canvas& canvas, float size, const SkPaint& paint) {
+ [](Canvas& canvas, float size, const Paint& paint) {
canvas.drawRect(0, 0, size, size, paint);
},
- [](Canvas& canvas, float size, const SkPaint& paint) {
+ [](Canvas& canvas, float size, const Paint& paint) {
float rad = size / 4;
canvas.drawRoundRect(0, 0, size, size, rad, rad, paint);
}};
@@ -66,7 +66,7 @@ public:
// each combination of strokeWidth + style gets a column
int outerCount = canvas.save(SaveFlags::MatrixClip);
- SkPaint paint;
+ Paint paint;
paint.setAntiAlias(true);
SkPaint::Style styles[] = {SkPaint::kStroke_Style, SkPaint::kFill_Style,
SkPaint::kStrokeAndFill_Style};
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index e60bd5fae198..a0bc5aa245d5 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -52,7 +52,7 @@ private:
return TestUtils::createNode(
x, y, x + width, y + height,
[width, height](RenderProperties& props, Canvas& canvas) {
- SkPaint paint;
+ Paint paint;
// Simple scale/translate case where R, G, and B are all treated equivalently
SkColorMatrix cm;
cm.setScale(1.1f, 1.1f, 1.1f, 0.5f);
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
index 8bd804e75674..57a260c8d234 100644
--- a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -51,7 +51,7 @@ private:
[width, height](RenderProperties& props, Canvas& canvas) {
float pos[] = {0, 1};
SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
- SkPaint paint;
+ Paint paint;
// overdraw several times to emphasize shader cost
for (int i = 0; i < 10; i++) {
// use i%2 start position to pick 2 color combo with black in it
diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h
index 6f76a502ae3e..24d35857c60d 100644
--- a/libs/hwui/tests/common/scenes/TestSceneBase.h
+++ b/libs/hwui/tests/common/scenes/TestSceneBase.h
@@ -17,6 +17,7 @@
#pragma once
#include "hwui/Canvas.h"
+#include "hwui/Paint.h"
#include "RenderNode.h"
#include "tests/common/TestContext.h"
#include "tests/common/TestScene.h"
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index 76f02888f994..bac887053d2f 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -217,7 +217,7 @@ private:
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
image->stagingProperties().getWidth(), image->stagingProperties().getHeight(),
image.get()));
- SkPaint paint;
+ Paint paint;
sk_sp<SkColorFilter> filter(
SkColorFilters::Blend((curFrame % 150) << 24, SkBlendMode::kSrcATop));
paint.setColorFilter(filter);
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 70423a70157b..4ce6c32470ea 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -18,6 +18,7 @@
#include "DisplayList.h"
#include "hwui/Canvas.h"
+#include "hwui/Paint.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "tests/common/TestUtils.h"
@@ -93,7 +94,7 @@ void BM_DisplayListCanvas_record_simpleBitmapView(benchmark::State& benchState)
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
delete canvas->finishRecording();
- SkPaint rectPaint;
+ Paint rectPaint;
sk_sp<Bitmap> iconBitmap(TestUtils::createBitmap(80, 80));
while (benchState.KeepRunning()) {
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index e70378bd15a5..3632be06c45f 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -24,6 +24,7 @@
#include "DamageAccumulator.h"
#include "FatalTestCanvas.h"
#include "IContextFactory.h"
+#include "hwui/Paint.h"
#include "RecordingCanvas.h"
#include "SkiaCanvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
@@ -59,7 +60,7 @@ TEST(RenderNodeDrawable, create) {
namespace {
static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
- SkPaint paint;
+ Paint paint;
// order put in blue channel, transparent so overlapped content doesn't get rejected
paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
canvas->drawRect(0, 0, 100, 100, paint);
@@ -211,7 +212,7 @@ TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore) {
ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
- SkPaint paint;
+ Paint paint;
paint.setAntiAlias(true);
paint.setColor(SK_ColorGREEN);
recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
@@ -291,7 +292,7 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
properties.setTranslationX(SCROLL_X);
properties.setTranslationY(SCROLL_Y);
- SkPaint paint;
+ Paint paint;
paint.setColor(SK_ColorWHITE);
canvas.drawRect(0, 0, 100, 100, paint);
},
@@ -302,7 +303,7 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
properties.setProjectBackwards(true);
properties.setClipToBounds(false);
- SkPaint paint;
+ Paint paint;
paint.setColor(SK_ColorDKGRAY);
canvas.drawRect(-10, -10, 60, 60, paint);
},
@@ -310,7 +311,7 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
auto child = TestUtils::createSkiaNode(
0, 50, 100, 100,
[&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
+ Paint paint;
paint.setColor(SK_ColorBLUE);
canvas.drawRect(0, 0, 100, 50, paint);
canvas.drawRenderNode(projectingRipple.get());
@@ -375,14 +376,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) {
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
properties.setProjectBackwards(true);
properties.setClipToBounds(false);
- SkPaint paint;
+ Paint paint;
canvas.drawRect(0, 0, 100, 100, paint);
},
"P");
auto child = TestUtils::createSkiaNode(
0, 0, 100, 100,
[&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
+ Paint paint;
canvas.drawRect(0, 0, 100, 100, paint);
canvas.drawRenderNode(projectingRipple.get());
},
@@ -483,7 +484,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
properties.setTranslationX(SCROLL_X);
properties.setTranslationY(SCROLL_Y);
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
},
"B"); // B
auto projectingRipple = TestUtils::createSkiaNode(
@@ -491,14 +492,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
properties.setProjectBackwards(true);
properties.setClipToBounds(false);
- canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
+ canvas.drawOval(100, 100, 300, 300, Paint()); // drawn mostly out of layer bounds
},
"R"); // R
auto child = TestUtils::createSkiaNode(
100, 100, 300, 300,
[&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
canvas.drawRenderNode(projectingRipple.get());
- canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
+ canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, Paint());
},
"C"); // C
auto parent = TestUtils::createSkiaNode(
@@ -578,7 +579,7 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
properties.setProjectionReceiver(true);
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
},
"B"); // B
auto projectingRipple = TestUtils::createSkiaNode(
@@ -591,7 +592,7 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
properties.setTranslationY(SCROLL_Y);
properties.setProjectBackwards(true);
properties.setClipToBounds(false);
- canvas.drawOval(0, 0, 200, 200, SkPaint());
+ canvas.drawOval(0, 0, 200, 200, Paint());
},
"R"); // R
auto child = TestUtils::createSkiaNode(
@@ -946,7 +947,7 @@ RENDERTHREAD_TEST(RenderNodeDrawable, simple) {
[](RenderProperties& props, SkiaRecordingCanvas& canvas) {
sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
- SkPaint());
+ Paint());
canvas.drawBitmap(*bitmap, 10, 10, nullptr);
});
@@ -1022,7 +1023,7 @@ TEST(RenderNodeDrawable, renderNode) {
auto child = TestUtils::createSkiaNode(
10, 10, 110, 110, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
+ Paint paint;
paint.setColor(SK_ColorWHITE);
canvas.drawRect(0, 0, 100, 100, paint);
});
@@ -1030,7 +1031,7 @@ TEST(RenderNodeDrawable, renderNode) {
auto parent = TestUtils::createSkiaNode(
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[&child](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
+ Paint paint;
paint.setColor(SK_ColorDKGRAY);
canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
@@ -1065,7 +1066,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
auto layerNode = TestUtils::createSkiaNode(
0, 0, LAYER_WIDTH, LAYER_HEIGHT,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- canvas.drawPaint(SkPaint());
+ canvas.drawPaint(Paint());
});
layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 2ed1b25efc71..fcc64fdd0be6 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -16,6 +16,7 @@
#include "tests/common/TestUtils.h"
+#include <hwui/Paint.h>
#include <SkBlurDrawLooper.h>
#include <SkCanvasStateUtils.h>
#include <SkPicture.h>
@@ -32,7 +33,7 @@ TEST(SkiaCanvas, drawShadowLayer) {
// clear to white
canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrc);
- SkPaint paint;
+ Paint paint;
// it is transparent to ensure that we still draw the rect since it has a looper
paint.setColor(SK_ColorTRANSPARENT);
// this is how view's shadow layers are implemented
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 7b76bd80de4d..958baa78deab 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -23,6 +23,7 @@
#include "AnimationContext.h"
#include "DamageAccumulator.h"
#include "IContextFactory.h"
+#include "hwui/Paint.h"
#include "SkiaCanvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
@@ -96,7 +97,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) {
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
auto halfGreenNode = TestUtils::createSkiaNode(
0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
- SkPaint greenPaint;
+ Paint greenPaint;
greenPaint.setColor(SK_ColorGREEN);
greenPaint.setStyle(SkPaint::kFill_Style);
bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
@@ -294,7 +295,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, deferRenderNodeScene) {
};
std::vector<sp<RenderNode>> nodes;
- SkPaint transparentPaint;
+ Paint transparentPaint;
transparentPaint.setAlpha(128);
// backdrop
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 635429dea359..eec25c6bd40d 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -24,6 +24,7 @@
#include "DamageAccumulator.h"
#include "FatalTestCanvas.h"
#include "IContextFactory.h"
+#include "hwui/Paint.h"
#include "SkiaCanvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaPipeline.h"
@@ -60,7 +61,7 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[propSetupCallback](RenderProperties& props, SkiaRecordingCanvas& canvas) {
propSetupCallback(props);
- SkPaint paint;
+ Paint paint;
paint.setColor(SK_ColorWHITE);
canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
});
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index ebf2343c5518..e2fdf2fcb5a5 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -67,29 +67,6 @@ public:
return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
}
- struct TextShadow {
- SkScalar radius;
- float dx;
- float dy;
- SkColor color;
- };
-
- static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) {
- SkDrawLooper::BlurShadowRec blur;
- if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) {
- if (textShadow) {
- textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma);
- textShadow->dx = blur.fOffset.fX;
- textShadow->dy = blur.fOffset.fY;
- textShadow->color = blur.fColor;
- }
- return true;
- }
- return false;
- }
-
- static inline bool hasTextShadow(const SkPaint* paint) { return getTextShadow(paint, nullptr); }
-
static inline SkBlendMode getBlendModeDirect(const SkPaint* paint) {
return paint ? paint->getBlendMode() : SkBlendMode::kSrcOver;
}
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index 03eb0d9aad5a..0ef4654d72e7 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -65,6 +65,9 @@ LOCAL_FULL_MANIFEST_FILE := $(gen)
LOCAL_MULTILIB := both
LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
+# Explicitly uncompress native libs rather than letting the build system doing it and destroy the
+# v2/v3 signature.
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := true
LOCAL_USE_AAPT2 := true
diff --git a/packages/DynamicSystemInstallationService/Android.bp b/packages/DynamicSystemInstallationService/Android.bp
new file mode 100644
index 000000000000..f1a18ae2a53f
--- /dev/null
+++ b/packages/DynamicSystemInstallationService/Android.bp
@@ -0,0 +1,14 @@
+android_app {
+ name: "DynamicSystemInstallationService",
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ certificate: "platform",
+ privileged: true,
+ platform_apis: true,
+
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/packages/DynamicSystemInstallationService/Android.mk b/packages/DynamicSystemInstallationService/Android.mk
deleted file mode 100644
index 16aca1bd07c5..000000000000
--- a/packages/DynamicSystemInstallationService/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, res)
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_PACKAGE_NAME := DynamicSystemInstallationService
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-
-include $(BUILD_PACKAGE)
diff --git a/packages/InputDevices/Android.bp b/packages/InputDevices/Android.bp
new file mode 100644
index 000000000000..7532aea23615
--- /dev/null
+++ b/packages/InputDevices/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2012 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.
+
+android_app {
+ name: "InputDevices",
+
+ srcs: [
+ "**/*.java",
+ ":validate_input_devices_keymaps",
+ ],
+
+ resource_dirs: ["res"],
+
+ sdk_version: "current",
+ certificate: "platform",
+ privileged: true,
+}
+
+// Validate all key maps.
+// Produces an empty srcjar that is used as an input to InputDevices to make sure
+// the check runs for platform builds.
+genrule {
+ name: "validate_input_devices_keymaps",
+ tools: [
+ "validatekeymaps",
+ "soong_zip",
+ ],
+ srcs: ["res/raw/*.kcm"],
+ out: ["validate_input_devices_keymaps.srcjar"],
+ cmd: "$(location validatekeymaps) -q $(in) && $(location soong_zip) -o $(out)",
+}
diff --git a/packages/InputDevices/Android.mk b/packages/InputDevices/Android.mk
deleted file mode 100644
index 80803fd94ff1..000000000000
--- a/packages/InputDevices/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2012 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES :=
-
-LOCAL_PACKAGE_NAME := InputDevices
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-include $(BUILD_PACKAGE)
-
-# Validate all key maps.
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := validate_input_devices_keymaps
-intermediates := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE),,COMMON)
-LOCAL_BUILT_MODULE := $(intermediates)/stamp
-
-validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX)
-input_devices_keymaps := $(wildcard $(LOCAL_PATH)/res/raw/*.kcm)
-$(LOCAL_BUILT_MODULE): PRIVATE_VALIDATEKEYMAPS := $(validatekeymaps)
-$(LOCAL_BUILT_MODULE) : $(input_devices_keymaps) | $(validatekeymaps)
- $(hide) $(PRIVATE_VALIDATEKEYMAPS) -q $^
- $(hide) mkdir -p $(dir $@) && touch $@
-
-# Run validatekeymaps unconditionally for platform build.
-droidcore : $(LOCAL_BUILT_MODULE)
-
-# Reset temp vars.
-validatekeymaps :=
-input_devices_keymaps :=
diff --git a/packages/MtpDocumentsProvider/Android.bp b/packages/MtpDocumentsProvider/Android.bp
new file mode 100644
index 000000000000..3dafa2649af6
--- /dev/null
+++ b/packages/MtpDocumentsProvider/Android.bp
@@ -0,0 +1,11 @@
+android_app {
+ name: "MtpDocumentsProvider",
+
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "media",
+ privileged: true,
+ optimize: {
+ proguard_flags_files: ["proguard.flags"],
+ },
+}
diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk
deleted file mode 100644
index 2d62a07566bf..000000000000
--- a/packages/MtpDocumentsProvider/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PACKAGE_NAME := MtpDocumentsProvider
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := media
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-# Only enable asserts on userdebug/eng builds
-ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
-LOCAL_JACK_FLAGS += -D jack.assert.policy=always
-endif
-
-include $(BUILD_PACKAGE)
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index beb1ac546949..2734f4e28632 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -141,7 +141,7 @@
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicaciones eliminadas"</string>
<string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicaciones y usuarios eliminados"</string>
<string name="data_usage_ota" msgid="5377889154805560860">"Actualizaciones del sistema"</string>
- <string name="tether_settings_title_usb" msgid="6688416425801386511">"Conexión USB"</string>
+ <string name="tether_settings_title_usb" msgid="6688416425801386511">"Conexión a red por USB"</string>
<string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portátil"</string>
<string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Conexión Bluetooth"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Compartir conexión"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 238eba58e0a5..3a20d04d7ab2 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -46,7 +46,7 @@
<string name="wifi_limited_connection" msgid="7717855024753201527">"सीमित कनेक्शन"</string>
<string name="wifi_status_no_internet" msgid="5784710974669608361">"इंटरनेट कनेक्शन नहीं है"</string>
<string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन करना ज़रूरी है"</string>
- <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"एक्सेस पॉइंट फ़िलहाल भरा हुआ है"</string>
+ <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ऐक्सेस पॉइंट फ़िलहाल भरा हुआ है"</string>
<string name="connected_via_carrier" msgid="7583780074526041912">"%1$s के ज़रिए कनेक्ट"</string>
<string name="available_via_carrier" msgid="1469036129740799053">"%1$s के ज़रिए उपलब्ध"</string>
<string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> खोला जा रहा है"</string>
@@ -68,7 +68,7 @@
<string name="bluetooth_pairing" msgid="1426882272690346242">"युग्‍मित कर रहा है…"</string>
<string name="bluetooth_connected_no_headset" msgid="616068069034994802">"जुड़ गया (फ़ोन के ऑडियो को छोड़कर)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"जुड़ गया (मीडिया ऑडियो को छोड़कर)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"जुड़ गया (मैसेज का एक्सेस नहीं)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"जुड़ गया (मैसेज का ऐक्सेस नहीं)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"जुड़ गया (फ़ोन या मीडिया ऑडियो को छोड़कर)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_battery_level" msgid="5162924691231307748">"जुड़ गया, बैटरी का लेवल <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"जुड़ गया (फ़ोन के ऑडियो को छोड़कर), बैटरी का लेवल <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
@@ -88,7 +88,7 @@
<string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"संपर्क साझाकरण के लिए उपयोग करें"</string>
<string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"इंटरनेट कनेक्शन साझाकरण"</string>
<string name="bluetooth_profile_map" msgid="1019763341565580450">"लेख संदेश"</string>
- <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम एक्सेस"</string>
+ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम ऐक्सेस"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ऑडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ऑडियो"</string>
<string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"सुनने में मदद करने वाले डिवाइस"</string>
@@ -200,7 +200,7 @@
<string name="development_settings_not_available" msgid="4308569041701535607">"यह उपयोगकर्ता, डेवलपर के लिए सेटिंग और टूल का इस्तेमाल नहीं कर सकता"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"VPN सेटिंग इस उपयोगकर्ता के लिए उपलब्ध नहीं हैं"</string>
<string name="tethering_settings_not_available" msgid="6765770438438291012">"टेदरिंग सेटिंग इस उपयोगकर्ता के लिए उपलब्ध नहीं हैं"</string>
- <string name="apn_settings_not_available" msgid="7873729032165324000">"एक्सेस पॉइंट के नाम की सेटिंग इस उपयोगकर्ता के लिए मौजूद नहीं हैं"</string>
+ <string name="apn_settings_not_available" msgid="7873729032165324000">"ऐक्सेस पॉइंट के नाम की सेटिंग इस उपयोगकर्ता के लिए मौजूद नहीं हैं"</string>
<string name="enable_adb" msgid="7982306934419797485">"USB डीबग करना"</string>
<string name="enable_adb_summary" msgid="4881186971746056635">"डीबग मोड जब USB कनेक्‍ट किया गया हो"</string>
<string name="clear_adb_keys" msgid="4038889221503122743">"USB डीबग करने की मंज़ूरी रद्द करें"</string>
@@ -414,7 +414,7 @@
<string name="disabled" msgid="9206776641295849915">"बंद किया गया"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"अनुमति है"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"अनुमति नहीं है"</string>
- <string name="install_other_apps" msgid="6986686991775883017">"अनजान ऐप्लिकेशन इंस्टॉल करने का एक्सेस"</string>
+ <string name="install_other_apps" msgid="6986686991775883017">"अनजान ऐप्लिकेशन इंस्टॉल करने का ऐक्सेस"</string>
<string name="home" msgid="3256884684164448244">"सेटिंग का होम पेज"</string>
<string-array name="battery_labels">
<item msgid="8494684293649631252">"0%"</item>
diff --git a/packages/SettingsLib/tests/Android.mk b/packages/SettingsLib/tests/Android.mk
deleted file mode 100644
index 333c41d33f40..000000000000
--- a/packages/SettingsLib/tests/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# Include all makefiles in subdirectories
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index b11df4890e98..7d56868d0ce8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -56,6 +56,7 @@ import java.time.DateTimeException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import java.util.zip.CRC32;
/**
@@ -241,6 +242,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
HashSet<String> movedToGlobal = new HashSet<String>();
Settings.System.getMovedToGlobalSettings(movedToGlobal);
Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
+ Set<String> movedToSecure = getMovedToSecureSettings();
+
byte[] restoredWifiSupplicantData = null;
byte[] restoredWifiIpConfigData = null;
@@ -259,16 +262,17 @@ public class SettingsBackupAgent extends BackupAgentHelper {
switch (key) {
case KEY_SYSTEM :
- restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
+ restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal,
+ movedToSecure);
mSettingsHelper.applyAudioSettings();
break;
case KEY_SECURE :
- restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
+ restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal, null);
break;
case KEY_GLOBAL :
- restoreSettings(data, Settings.Global.CONTENT_URI, null);
+ restoreSettings(data, Settings.Global.CONTENT_URI, null, movedToSecure);
break;
case KEY_WIFI_SUPPLICANT :
@@ -347,20 +351,22 @@ public class SettingsBackupAgent extends BackupAgentHelper {
HashSet<String> movedToGlobal = new HashSet<String>();
Settings.System.getMovedToGlobalSettings(movedToGlobal);
Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
+ Set<String> movedToSecure = getMovedToSecureSettings();
// system settings data first
int nBytes = in.readInt();
if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
byte[] buffer = new byte[nBytes];
in.readFully(buffer, 0, nBytes);
- restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal);
+ restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal,
+ movedToSecure);
// secure settings
nBytes = in.readInt();
if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
if (nBytes > buffer.length) buffer = new byte[nBytes];
in.readFully(buffer, 0, nBytes);
- restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal);
+ restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal, null);
// Global only if sufficiently new
if (version >= FULL_BACKUP_ADDED_GLOBAL) {
@@ -369,7 +375,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
if (nBytes > buffer.length) buffer = new byte[nBytes];
in.readFully(buffer, 0, nBytes);
movedToGlobal.clear(); // no redirection; this *is* the global namespace
- restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal);
+ restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal,
+ movedToSecure);
}
// locale
@@ -440,6 +447,13 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
}
+ private Set<String> getMovedToSecureSettings() {
+ Set<String> movedToSecureSettings = new HashSet<>();
+ Settings.Global.getMovedToSecureSettings(movedToSecureSettings);
+ Settings.System.getMovedToSecureSettings(movedToSecureSettings);
+ return movedToSecureSettings;
+ }
+
private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
long[] stateChecksums = new long[STATE_SIZE];
@@ -564,7 +578,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
private void restoreSettings(BackupDataInput data, Uri contentUri,
- HashSet<String> movedToGlobal) {
+ HashSet<String> movedToGlobal, Set<String> movedToSecure) {
byte[] settings = new byte[data.getDataSize()];
try {
data.readEntityData(settings, 0, settings.length);
@@ -572,11 +586,11 @@ public class SettingsBackupAgent extends BackupAgentHelper {
Log.e(TAG, "Couldn't read entity data");
return;
}
- restoreSettings(settings, settings.length, contentUri, movedToGlobal);
+ restoreSettings(settings, settings.length, contentUri, movedToGlobal, movedToSecure);
}
private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
- HashSet<String> movedToGlobal) {
+ HashSet<String> movedToGlobal, Set<String> movedToSecure) {
if (DEBUG) {
Log.i(TAG, "restoreSettings: " + contentUri);
}
@@ -651,9 +665,14 @@ public class SettingsBackupAgent extends BackupAgentHelper {
continue;
}
- final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
- ? Settings.Global.CONTENT_URI
- : contentUri;
+ final Uri destination;
+ if (movedToGlobal != null && movedToGlobal.contains(key)) {
+ destination = Settings.Global.CONTENT_URI;
+ } else if (movedToSecure != null && movedToSecure.contains(key)) {
+ destination = Settings.Secure.CONTENT_URI;
+ } else {
+ destination = contentUri;
+ }
settingsHelper.restoreValue(this, cr, contentValues, destination, key, value,
mRestoredFromSdkInt);
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index c9bb83c0b986..a7b44443fc9c 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -350,18 +350,19 @@ public class BugreportProgressService extends Service {
private final class BugreportCallbackImpl extends BugreportCallback {
- private final int mId;
private final BugreportInfo mInfo;
- BugreportCallbackImpl(String name, int id) {
- mId = id;
+ BugreportCallbackImpl(String name) {
// pid not used in this workflow, so setting default = 0
- mInfo = new BugreportInfo(mContext, mId, 0 /* pid */, name,
+ mInfo = new BugreportInfo(mContext, 0 /* pid */, name,
100 /* max progress*/);
}
@Override
public void onProgress(float progress) {
+ if (progress == 0) {
+ trackInfoWithId();
+ }
checkProgressUpdated(mInfo, (int) progress);
}
@@ -369,17 +370,34 @@ public class BugreportProgressService extends Service {
// Logging errors and removing progress notification for now.
@Override
public void onError(@BugreportErrorCode int errorCode) {
- stopProgress(mId);
+ trackInfoWithId();
+ stopProgress(mInfo.id);
Log.e(TAG, "Bugreport API callback onError() errorCode = " + errorCode);
return;
}
@Override
public void onFinished() {
+ trackInfoWithId();
// Stop running on foreground, otherwise share notification cannot be dismissed.
- onBugreportFinished(mId);
+ onBugreportFinished(mInfo.id);
stopSelfWhenDone();
}
+
+ /**
+ * Reads bugreport id and links it to the bugreport info to track the bugreport's
+ * progress/completion/error. id is incremented in dumpstate code. This function is called
+ * when dumpstate calls one of the callback functions (onProgress, onFinished, onError)
+ * after the id has been incremented.
+ */
+ private void trackInfoWithId() {
+ final int id = SystemProperties.getInt(PROPERTY_LAST_ID, 1);
+ if (mBugreportInfos.get(id) == null) {
+ mInfo.id = id;
+ mBugreportInfos.put(mInfo.id, mInfo);
+ }
+ return;
+ }
}
/**
@@ -539,12 +557,17 @@ public class BugreportProgressService extends Service {
}
}
+ private String getBugreportName() {
+ String buildId = SystemProperties.get("ro.build.id", "UNKNOWN_BUILD");
+ String deviceName = SystemProperties.get("ro.product.name", "UNKNOWN_DEVICE");
+ String currentTimestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
+ return String.format("bugreport-%s-%s-%s", deviceName, buildId, currentTimestamp);
+ }
+
private void startBugreportAPI(Intent intent) {
mUsingBugreportApi = true;
- String bugreportName = "bugreport-" + new SimpleDateFormat("yyyy-MM-dd-HH-mm").format(
- new Date());
+ String bugreportName = getBugreportName();
- // TODO(b/126862297): Make file naming same as dumpstate triggered bugreports
ParcelFileDescriptor bugreportFd = createReadWriteFile(BUGREPORT_DIR,
bugreportName + ".zip");
if (bugreportFd == null) {
@@ -565,19 +588,15 @@ public class BugreportProgressService extends Service {
mBugreportManager = (BugreportManager) mContext.getSystemService(
Context.BUGREPORT_SERVICE);
final Executor executor = ActivityThread.currentActivityThread().getExecutor();
- // TODO(b/123617758): This id should come from dumpstate.
- // Dumpstate increments PROPERTY_LAST_ID, may be racy if multiple calls
- // to dumpstate are made simultaneously.
- final int id = SystemProperties.getInt(PROPERTY_LAST_ID, 0) + 1;
+
Log.i(TAG, "bugreport type = " + bugreportType
+ " bugreport file fd: " + bugreportFd
+ " screenshot file fd: " + screenshotFd);
- BugreportCallbackImpl bugreportCallback = new BugreportCallbackImpl(bugreportName, id);
+ BugreportCallbackImpl bugreportCallback = new BugreportCallbackImpl(bugreportName);
try {
mBugreportManager.startBugreport(bugreportFd, screenshotFd,
new BugreportParams(bugreportType), executor, bugreportCallback);
- mBugreportInfos.put(bugreportCallback.mInfo.id, bugreportCallback.mInfo);
} catch (RuntimeException e) {
Log.i(TAG, "error in generating bugreports: ", e);
// The binder call didn't go through successfully, so need to close the fds.
@@ -1811,7 +1830,7 @@ public class BugreportProgressService extends Service {
/**
* Sequential, user-friendly id used to identify the bugreport.
*/
- final int id;
+ int id;
/**
* {@code pid} of the {@code dumpstate} process generating the bugreport.
@@ -1903,8 +1922,15 @@ public class BugreportProgressService extends Service {
* Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
*/
BugreportInfo(Context context, int id, int pid, String name, int max) {
- this.context = context;
+ this(context, pid, name, max);
this.id = id;
+ }
+
+ /**
+ * Constructor for tracked bugreports - typically called upon receiving BUGREPORT_REQUESTED.
+ */
+ BugreportInfo(Context context, int pid, String name, int max) {
+ this.context = context;
this.pid = pid;
this.name = name;
this.max = this.realMax = max;
diff --git a/packages/SimAppDialog/Android.bp b/packages/SimAppDialog/Android.bp
new file mode 100644
index 000000000000..ff26710fa2e1
--- /dev/null
+++ b/packages/SimAppDialog/Android.bp
@@ -0,0 +1,15 @@
+android_app {
+ name: "SimAppDialog",
+
+ srcs: ["src/**/*.java"],
+
+ platform_apis: true,
+ certificate: "platform",
+
+ static_libs: [
+ "androidx.legacy_legacy-support-v4",
+ "setup-wizard-lib",
+ ],
+
+ resource_dirs: ["res"],
+}
diff --git a/packages/SimAppDialog/Android.mk b/packages/SimAppDialog/Android.mk
deleted file mode 100644
index 991e3330e00a..000000000000
--- a/packages/SimAppDialog/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := SimAppDialog
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- androidx.legacy_legacy-support-v4
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-include frameworks/opt/setupwizard/library/common-platform-deprecated.mk
-
-include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/plugin/ExamplePlugin/Android.bp b/packages/SystemUI/plugin/ExamplePlugin/Android.bp
index a0eaf14f4a06..c6c80f3780a3 100644
--- a/packages/SystemUI/plugin/ExamplePlugin/Android.bp
+++ b/packages/SystemUI/plugin/ExamplePlugin/Android.bp
@@ -11,4 +11,5 @@ android_app {
srcs: ["src/**/*.java"],
+ platform_apis: true,
}
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index f124d89070bf..6becd21984b9 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -75,14 +75,15 @@
<attr name="horizontalSpacing" format="dimension" />
</declare-styleable>
- <!-- Theme for icons in the status bar (light/dark). background/fillColor is used for dual tone
- icons like wifi and signal, and singleToneColor is used for icons with only one tone.
+ <!-- Theme for icons in the status/nav bar (light/dark). background/fillColor is used for dual
+ tone icons like wifi and signal, and singleToneColor is used for icons with only one tone.
Contract: Pixel with fillColor blended over backgroundColor blended over translucent should
equal to singleToneColor blended over translucent. -->
<declare-styleable name="TonedIcon">
<attr name="backgroundColor" format="integer" />
<attr name="fillColor" format="integer" />
<attr name="singleToneColor" format="integer" />
+ <attr name="homeHandleColor" format="integer" />
</declare-styleable>
<declare-styleable name="StatusBarWindowView_Layout">
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e7a1a660abc2..61816f60d0ba 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -116,6 +116,9 @@
<!-- The color of the navigation bar icons. Need to be in sync with ic_sysbar_* -->
<color name="navigation_bar_icon_color">#E5FFFFFF</color>
+ <color name="navigation_bar_home_handle_light_color">#EBffffff</color>
+ <color name="navigation_bar_home_handle_dark_color">#99000000</color>
+
<!-- The shadow color for light navigation bar icons. -->
<color name="nav_key_button_shadow_color">#30000000</color>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2f1770a39f02..6374191c4d7b 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -366,11 +366,13 @@
<item name="backgroundColor">@color/light_mode_icon_color_dual_tone_background</item>
<item name="fillColor">@color/light_mode_icon_color_dual_tone_fill</item>
<item name="singleToneColor">@color/light_mode_icon_color_single_tone</item>
+ <item name="homeHandleColor">@color/navigation_bar_home_handle_light_color</item>
</style>
<style name="DualToneDarkTheme">
<item name="backgroundColor">@color/dark_mode_icon_color_dual_tone_background</item>
<item name="fillColor">@color/dark_mode_icon_color_dual_tone_fill</item>
<item name="singleToneColor">@color/dark_mode_icon_color_single_tone</item>
+ <item name="homeHandleColor">@color/navigation_bar_home_handle_dark_color</item>
</style>
<style name="QSHeaderDarkTheme">
<item name="backgroundColor">@color/dark_mode_qs_icon_color_dual_tone_background</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
index b2c79a4c0a32..e106c657109d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
@@ -52,7 +52,11 @@ public class TaskKeyLruCache<V> extends TaskKeyCache<V> {
if (mEvictionCallback != null) {
mEvictionCallback.onEntryEvicted(mKeys.get(taskId));
}
- mKeys.remove(taskId);
+
+ // Only remove from mKeys on cache remove, not a cache update.
+ if (newV == null) {
+ mKeys.remove(taskId);
+ }
}
};
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index cc7863c0113b..c732584eddfc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -80,18 +80,25 @@ public class QuickStepContract {
public static final int SYSUI_STATE_HOME_DISABLED = 1 << 8;
// The keyguard is showing, but occluded
public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED = 1 << 9;
+ // The search feature is disabled (either by SUW/SysUI/device policy)
+ public static final int SYSUI_STATE_SEARCH_DISABLED = 1 << 10;
+ // The notification panel is expanded and interactive (either locked or unlocked), and the
+ // quick settings is not expanded
+ public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11;
@Retention(RetentionPolicy.SOURCE)
@IntDef({SYSUI_STATE_SCREEN_PINNING,
SYSUI_STATE_NAV_BAR_HIDDEN,
SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
SYSUI_STATE_BOUNCER_SHOWING,
SYSUI_STATE_A11Y_BUTTON_CLICKABLE,
SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE,
SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
SYSUI_STATE_OVERVIEW_DISABLED,
- SYSUI_STATE_HOME_DISABLED
+ SYSUI_STATE_HOME_DISABLED,
+ SYSUI_STATE_SEARCH_DISABLED
})
public @interface SystemUiStateFlags {}
@@ -100,8 +107,10 @@ public class QuickStepContract {
str.add((flags & SYSUI_STATE_SCREEN_PINNING) != 0 ? "screen_pinned" : "");
str.add((flags & SYSUI_STATE_OVERVIEW_DISABLED) != 0 ? "overview_disabled" : "");
str.add((flags & SYSUI_STATE_HOME_DISABLED) != 0 ? "home_disabled" : "");
+ str.add((flags & SYSUI_STATE_SEARCH_DISABLED) != 0 ? "search_disabled" : "");
str.add((flags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0 ? "navbar_hidden" : "");
str.add((flags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0 ? "notif_visible" : "");
+ str.add((flags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) != 0 ? "qs_visible" : "");
str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) != 0 ? "keygrd_visible" : "");
str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0
? "keygrd_occluded" : "");
@@ -150,10 +159,13 @@ public class QuickStepContract {
* disabled.
*/
public static boolean isAssistantGestureDisabled(int sysuiStateFlags) {
- // Disable when in screen pinning, immersive, the bouncer is showing
+ // Disable when in quick settings, screen pinning, immersive, the bouncer is showing,
+ // or search is disabled
int disableFlags = SYSUI_STATE_SCREEN_PINNING
| SYSUI_STATE_NAV_BAR_HIDDEN
- | SYSUI_STATE_BOUNCER_SHOWING;
+ | SYSUI_STATE_BOUNCER_SHOWING
+ | SYSUI_STATE_SEARCH_DISABLED
+ | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
if ((sysuiStateFlags & disableFlags) != 0) {
return true;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index d2fe5cd9ef64..2ef042210e67 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -91,6 +91,7 @@ public class RecentsAnimationControllerCompat {
}
}
+ @Deprecated
public void setCancelWithDeferredScreenshot(boolean screenshot) {
try {
mAnimationController.setCancelWithDeferredScreenshot(screenshot);
@@ -99,6 +100,14 @@ public class RecentsAnimationControllerCompat {
}
}
+ public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+ try {
+ mAnimationController.setDeferCancelUntilNextTransition(defer, screenshot);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set deferred cancel with screenshot", e);
+ }
+ }
+
public void cleanupScreenshot() {
try {
mAnimationController.cleanupScreenshot();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
index a5299038d3a9..326c2aa37175 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
@@ -17,29 +17,32 @@
package com.android.systemui.shared.system;
import android.app.ActivityManager;
+import android.app.TaskInfo;
import android.content.ComponentName;
-public class RecentTaskInfoCompat {
+public class TaskInfoCompat {
- private ActivityManager.RecentTaskInfo mInfo;
+ public static int getUserId(TaskInfo info) {
+ return info.userId;
+ }
- public RecentTaskInfoCompat(ActivityManager.RecentTaskInfo info) {
- mInfo = info;
+ public static int getActivityType(TaskInfo info) {
+ return info.configuration.windowConfiguration.getActivityType();
}
- public int getUserId() {
- return mInfo.userId;
+ public static int getWindowingMode(TaskInfo info) {
+ return info.configuration.windowConfiguration.getWindowingMode();
}
- public boolean supportsSplitScreenMultiWindow() {
- return mInfo.supportsSplitScreenMultiWindow;
+ public static boolean supportsSplitScreenMultiWindow(TaskInfo info) {
+ return info.supportsSplitScreenMultiWindow;
}
- public ComponentName getTopActivity() {
- return mInfo.topActivity;
+ public static ComponentName getTopActivity(TaskInfo info) {
+ return info.topActivity;
}
- public ActivityManager.TaskDescription getTaskDescription() {
- return mInfo.taskDescription;
+ public static ActivityManager.TaskDescription getTaskDescription(TaskInfo info) {
+ return info.taskDescription;
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 4ad262fee520..8059dcf33df7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -269,7 +269,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
*/
private void updateBiometricRetry() {
SecurityMode securityMode = getSecurityMode();
- mSwipeUpToRetry = mUnlockMethodCache.isUnlockingWithFacePossible()
+ mSwipeUpToRetry = mUnlockMethodCache.isFaceAuthEnabled()
&& securityMode != SecurityMode.SimPin
&& securityMode != SecurityMode.SimPuk
&& securityMode != SecurityMode.None;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fd618b05f348..4e7b15715243 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1783,13 +1783,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
&& mFpm.getEnrolledFingerprints(userId).size() > 0;
}
+ private boolean isUnlockWithFacePossible(int userId) {
+ return isFaceAuthEnabledForUser(userId) && !isFaceDisabled(userId);
+ }
+
/**
* If face hardware is available, user has enrolled and enabled auth via setting.
- * Not considering encryption or lock down state.
*/
- public boolean isUnlockWithFacePossible(int userId) {
+ public boolean isFaceAuthEnabledForUser(int userId) {
return mFaceManager != null && mFaceManager.isHardwareDetected()
- && !isFaceDisabled(userId)
&& mFaceManager.hasEnrolledTemplates(userId)
&& mFaceSettingEnabledForUser.get(userId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
index 54a36355decb..a94952c5bc19 100644
--- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
@@ -107,7 +107,9 @@ public class CornerHandleView extends View {
mPaint.setColor((int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
mLightColor,
mDarkColor));
- invalidate();
+ if (getVisibility() == VISIBLE) {
+ invalidate();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/DumpController.kt b/packages/SystemUI/src/com/android/systemui/DumpController.kt
index 646abb5c2c5a..65f1abd863c7 100644
--- a/packages/SystemUI/src/com/android/systemui/DumpController.kt
+++ b/packages/SystemUI/src/com/android/systemui/DumpController.kt
@@ -16,6 +16,7 @@
package com.android.systemui
+import android.util.ArraySet
import android.util.Log
import androidx.annotation.GuardedBy
import com.android.internal.util.Preconditions
@@ -39,38 +40,39 @@ class DumpController @Inject constructor() : Dumpable {
}
@GuardedBy("listeners")
- private val listeners = mutableListOf<WeakReference<Dumpable>>()
+ private val listeners = mutableListOf<RegisteredDumpable>()
val numListeners: Int
get() = listeners.size
/**
- * Adds a [Dumpable] listener to be dumped. It will only be added if it is not already tracked.
+ * Adds a [Dumpable] dumpable to be dumped.
*
- * @param listener the [Dumpable] to be added
+ * @param tag a string tag to associate with this dumpable. Tags must be globally unique; this
+ * method will throw if the same tag has already been registered. Tags can be used to
+ * filter output when debugging.
+ * @param dumpable the [Dumpable] to be added
*/
- fun addListener(listener: Dumpable) {
- Preconditions.checkNotNull(listener, "The listener to be added cannot be null")
- if (DEBUG) Log.v(TAG, "*** register callback for $listener")
+ fun registerDumpable(tag: String, dumpable: Dumpable) {
+ Preconditions.checkNotNull(dumpable, "The dumpable to be added cannot be null")
+ if (DEBUG) Log.v(TAG, "*** register callback for $dumpable")
synchronized<Unit>(listeners) {
- if (listeners.any { it.get() == listener }) {
- if (DEBUG) {
- Log.e(TAG, "Object tried to add another callback")
- }
+ if (listeners.any { it.tag == tag }) {
+ throw IllegalArgumentException("Duplicate dumpable tag registered: $tag")
} else {
- listeners.add(WeakReference(listener))
+ listeners.add(RegisteredDumpable(tag, WeakReference(dumpable)))
}
}
}
/**
- * Removes a listener from the list of elements to be dumped.
+ * Removes a dumpable from the list of elements to be dumped.
*
- * @param listener the [Dumpable] to be removed.
+ * @param dumpable the [Dumpable] to be removed.
*/
- fun removeListener(listener: Dumpable) {
- if (DEBUG) Log.v(TAG, "*** unregister callback for $listener")
+ fun unregisterDumpable(dumpable: Dumpable) {
+ if (DEBUG) Log.v(TAG, "*** unregister callback for $dumpable")
synchronized(listeners) {
- listeners.removeAll { it.get() == listener || it.get() == null }
+ listeners.removeAll { it.dumpable.get() == dumpable || it.dumpable.get() == null }
}
}
@@ -79,8 +81,22 @@ class DumpController @Inject constructor() : Dumpable {
*/
override fun dump(fd: FileDescriptor?, pw: PrintWriter, args: Array<String>?) {
pw.println("DumpController state:")
+
+ val filter = if (args != null && args.size >= 3 &&
+ args[0] == "dependency" && args[1] == "DumpController") {
+ ArraySet(args[2].split(',').map { it.toLowerCase() })
+ } else {
+ null
+ }
+
synchronized(listeners) {
- listeners.forEach { it.get()?.dump(fd, pw, args) }
+ listeners.forEach {
+ if (filter == null || filter.contains(it.tag.toLowerCase())) {
+ it.dumpable.get()?.dump(fd, pw, args)
+ }
+ }
}
}
+
+ data class RegisteredDumpable(val tag: String, val dumpable: WeakReference<Dumpable>)
}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index c9d4957494e4..bd91333100bd 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -47,7 +47,7 @@ public class ImageWallpaper extends WallpaperService {
// This is to avoid destroying then recreating render context in a very short time.
private static final int DELAY_FINISH_RENDERING = 1000;
private static final int INTERVAL_WAIT_FOR_RENDERING = 100;
- private static final int PATIENCE_WAIT_FOR_RENDERING = 5;
+ private static final int PATIENCE_WAIT_FOR_RENDERING = 10;
private HandlerThread mWorker;
@Override
@@ -124,10 +124,10 @@ public class ImageWallpaper extends WallpaperService {
@Override
public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) {
- long duration = mNeedTransition || animationDuration != 0 ? animationDuration : 0;
+ if (!mNeedTransition) return;
mWorker.getThreadHandler().post(
- () -> mRenderer.updateAmbientMode(inAmbientMode, duration));
- if (inAmbientMode && duration == 0) {
+ () -> mRenderer.updateAmbientMode(inAmbientMode, animationDuration));
+ if (inAmbientMode && animationDuration == 0) {
// This means that we are transiting from home to aod, to avoid
// race condition between window visibility and transition,
// we don't return until the transition is finished. See b/136643341.
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
index 002d4f34be11..75956545432e 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
@@ -127,7 +127,7 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac
SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE, null));
}
});
- Dependency.get(DumpController.class).addListener(this);
+ Dependency.get(DumpController.class).registerDumpable(TAG, this);
}
@Override // AssistHandleCallbacks
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index a5857df8ba5a..ce67577ea483 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -111,6 +111,9 @@ public abstract class BiometricDialogView extends LinearLayout {
protected boolean mRequireConfirmation;
private int mUserId; // used to determine if we should show work background
+ private boolean mCompletedAnimatingIn;
+ private boolean mPendingDismissDialog;
+
protected abstract int getHintStringResourceId();
protected abstract int getAuthenticatedAccessibilityResourceId();
protected abstract int getIconDescriptionResourceId();
@@ -332,6 +335,7 @@ public abstract class BiometricDialogView extends LinearLayout {
mDialog.setAlpha(1.0f);
mDialog.setTranslationY(0);
mLayout.setAlpha(1.0f);
+ mCompletedAnimatingIn = true;
} else {
// Dim the background and slide the dialog up
mDialog.setTranslationY(mAnimationTranslationOffset);
@@ -352,6 +356,12 @@ public abstract class BiometricDialogView extends LinearLayout {
}
public void startDismiss() {
+ if (!mCompletedAnimatingIn) {
+ Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn");
+ mPendingDismissDialog = true;
+ return;
+ }
+
mAnimatingAway = true;
// This is where final cleanup should occur.
@@ -499,6 +509,13 @@ public abstract class BiometricDialogView extends LinearLayout {
}
public void onDialogAnimatedIn() {
+ mCompletedAnimatingIn = true;
+
+ if (mPendingDismissDialog) {
+ Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now");
+ startDismiss();
+ mPendingDismissDialog = false;
+ }
}
public void restoreState(Bundle bundle) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index 729242e3144f..ae6cb5ce23d3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -460,6 +460,7 @@ public class FaceDialogView extends BiometricDialogView {
@Override
public void onDialogAnimatedIn() {
+ super.onDialogAnimatedIn();
mDialogAnimatedIn = true;
mIconController.startPulsing();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index cee01a4d3048..ce82bbfb1512 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -50,6 +50,8 @@ public class BrightLineFalsingManager implements FalsingManager {
private boolean mSessionStarted;
private MetricsLogger mMetricsLogger;
private int mIsFalseTouchCalls;
+ private boolean mShowingAod;
+ private boolean mScreenOn;
private final ExecutorService mBackgroundExecutor = Executors.newSingleThreadExecutor();
@@ -105,10 +107,12 @@ public class BrightLineFalsingManager implements FalsingManager {
}
private void sessionStart() {
- logDebug("Starting Session");
- mSessionStarted = true;
- registerSensors();
- mClassifiers.forEach(FalsingClassifier::onSessionStarted);
+ if (!mSessionStarted && !mShowingAod && mScreenOn) {
+ logDebug("Starting Session");
+ mSessionStarted = true;
+ registerSensors();
+ mClassifiers.forEach(FalsingClassifier::onSessionStarted);
+ }
}
private void sessionEnd() {
@@ -172,6 +176,7 @@ public class BrightLineFalsingManager implements FalsingManager {
mMetricsLogger.histogram(FALSING_SUCCESS, mIsFalseTouchCalls);
mIsFalseTouchCalls = 0;
}
+ sessionEnd();
}
@Override
@@ -180,6 +185,7 @@ public class BrightLineFalsingManager implements FalsingManager {
@Override
public void setShowingAod(boolean showingAod) {
+ mShowingAod = showingAod;
if (showingAod) {
sessionEnd();
} else {
@@ -264,7 +270,7 @@ public class BrightLineFalsingManager implements FalsingManager {
@Override
public void onScreenOnFromTouch() {
- sessionStart();
+ onScreenTurningOn();
}
@Override
@@ -286,11 +292,13 @@ public class BrightLineFalsingManager implements FalsingManager {
@Override
public void onScreenTurningOn() {
+ mScreenOn = true;
sessionStart();
}
@Override
public void onScreenOff() {
+ mScreenOn = false;
sessionEnd();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index ae6dac59b2f5..07dd2cd77043 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -77,8 +77,10 @@ public interface DozeHost {
interface Callback {
/**
* Called when a high priority notification is added.
+ * @param onPulseSuppressedListener A listener that is invoked if the pulse is being
+ * supressed.
*/
- default void onNotificationAlerted() {}
+ default void onNotificationAlerted(Runnable onPulseSuppressedListener) {}
/**
* Called when battery state or power save mode changes.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 8ef01e8d608e..2ca85c074a89 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -106,22 +106,31 @@ public class DozeTriggers implements DozeMachine.Part {
mDockManager = dockManager;
}
- private void onNotification() {
+ private void onNotification(Runnable onPulseSuppressedListener) {
if (DozeMachine.DEBUG) {
Log.d(TAG, "requestNotificationPulse");
}
if (!sWakeDisplaySensorState) {
Log.d(TAG, "Wake display false. Pulse denied.");
+ runIfNotNull(onPulseSuppressedListener);
return;
}
mNotificationPulseTime = SystemClock.elapsedRealtime();
if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
+ runIfNotNull(onPulseSuppressedListener);
return;
}
- requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */);
+ requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */,
+ onPulseSuppressedListener);
DozeLog.traceNotificationPulse(mContext);
}
+ private static void runIfNotNull(Runnable runnable) {
+ if (runnable != null) {
+ runnable.run();
+ }
+ }
+
private void proximityCheckThenCall(IntConsumer callback,
boolean alreadyPerformedProxCheck,
int reason) {
@@ -158,10 +167,11 @@ public class DozeTriggers implements DozeMachine.Part {
if (isWakeDisplay) {
onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
} else if (isLongPress) {
- requestPulse(pulseReason, sensorPerformedProxCheck);
+ requestPulse(pulseReason, sensorPerformedProxCheck, null /* onPulseSupressedListener */);
} else if (isWakeLockScreen) {
if (wakeEvent) {
- requestPulse(pulseReason, sensorPerformedProxCheck);
+ requestPulse(pulseReason, sensorPerformedProxCheck,
+ null /* onPulseSupressedListener */);
}
} else {
proximityCheckThenCall((result) -> {
@@ -340,7 +350,8 @@ public class DozeTriggers implements DozeMachine.Part {
}
}
- private void requestPulse(final int reason, boolean performedProxCheck) {
+ private void requestPulse(final int reason, boolean performedProxCheck,
+ Runnable onPulseSuppressedListener) {
Assert.isMainThread();
mDozeHost.extendPulse(reason);
@@ -357,6 +368,7 @@ public class DozeTriggers implements DozeMachine.Part {
DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
mDozeHost.isPulsingBlocked());
}
+ runIfNotNull(onPulseSuppressedListener);
return;
}
@@ -365,6 +377,7 @@ public class DozeTriggers implements DozeMachine.Part {
if (result == ProximityCheck.RESULT_NEAR) {
// in pocket, abort pulse
mPulsePending = false;
+ runIfNotNull(onPulseSuppressedListener);
} else {
// not in pocket, continue pulsing
continuePulseRequest(reason);
@@ -482,7 +495,8 @@ public class DozeTriggers implements DozeMachine.Part {
public void onReceive(Context context, Intent intent) {
if (PULSE_ACTION.equals(intent.getAction())) {
if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent");
- requestPulse(DozeLog.PULSE_REASON_INTENT, false /* performedProxCheck */);
+ requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */
+ null /* onPulseSupressedListener */);
}
if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
mMachine.requestState(DozeMachine.State.FINISH);
@@ -532,8 +546,8 @@ public class DozeTriggers implements DozeMachine.Part {
private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
@Override
- public void onNotificationAlerted() {
- onNotification();
+ public void onNotificationAlerted(Runnable onPulseSuppressedListener) {
+ onNotification(onPulseSuppressedListener);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
index 45e97b38d87e..b154e66a846e 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
@@ -65,7 +65,7 @@ class ImageRevealHelper {
@Override
public void onAnimationStart(Animator animation) {
if (mRevealListener != null) {
- mRevealListener.onRevealStart();
+ mRevealListener.onRevealStart(true /* animate */);
}
}
});
@@ -73,7 +73,7 @@ class ImageRevealHelper {
private void animate() {
mAnimator.cancel();
- mAnimator.setFloatValues(mReveal, !mAwake ? MIN_REVEAL : MAX_REVEAL);
+ mAnimator.setFloatValues(mReveal, mAwake ? MAX_REVEAL : MIN_REVEAL);
mAnimator.start();
}
@@ -84,12 +84,11 @@ class ImageRevealHelper {
void updateAwake(boolean awake, long duration) {
mAwake = awake;
mAnimator.setDuration(duration);
- if (!mAwake && duration == 0) {
- // We are transiting from home to aod,
- // since main thread is waiting for rendering finished, we only need draw
- // the last state directly, which is a black screen.
- mReveal = MIN_REVEAL;
- mRevealListener.onRevealStart();
+ if (duration == 0) {
+ // We are transiting from home to aod or aod to home directly,
+ // we don't need to do transition in these cases.
+ mReveal = mAwake ? MAX_REVEAL : MIN_REVEAL;
+ mRevealListener.onRevealStart(false /* animate */);
mRevealListener.onRevealStateChanged();
mRevealListener.onRevealEnd();
} else {
@@ -110,7 +109,7 @@ class ImageRevealHelper {
/**
* Called back while reveal starts.
*/
- void onRevealStart();
+ void onRevealStart(boolean animate);
/**
* Called back while reveal ends.
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
index 93d8dd6146a6..7b22a49fc88a 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
@@ -24,6 +24,7 @@ import static android.opengl.GLES20.glViewport;
import android.app.WallpaperManager;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.Log;
@@ -70,7 +71,14 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer,
DisplayInfo displayInfo = new DisplayInfo();
WindowManager wm = context.getSystemService(WindowManager.class);
wm.getDefaultDisplay().getDisplayInfo(displayInfo);
- mScissor = new Rect(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+
+ // We only do transition in portrait currently, b/137962047.
+ int orientation = context.getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ mScissor = new Rect(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ } else {
+ mScissor = new Rect(0, 0, displayInfo.logicalHeight, displayInfo.logicalWidth);
+ }
mProxy = proxy;
mProgram = new ImageGLProgram(context);
@@ -179,20 +187,24 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer,
}
@Override
- public void onRevealStart() {
- mScissorMode = true;
- // Use current display area of texture.
- mWallpaper.adjustTextureCoordinates(mSurfaceSize, mScissor, mXOffset, mYOffset);
+ public void onRevealStart(boolean animate) {
+ if (animate) {
+ mScissorMode = true;
+ // Use current display area of texture.
+ mWallpaper.adjustTextureCoordinates(mSurfaceSize, mScissor, mXOffset, mYOffset);
+ }
mProxy.preRender();
}
@Override
public void onRevealEnd() {
- mScissorMode = false;
- // reset texture coordinates to use full texture.
- mWallpaper.adjustTextureCoordinates(null, null, 0, 0);
- // We need draw full texture back before finishing render.
- mProxy.requestRender();
+ if (mScissorMode) {
+ mScissorMode = false;
+ // reset texture coordinates to use full texture.
+ mWallpaper.adjustTextureCoordinates(null, null, 0, 0);
+ // We need draw full texture back before finishing render.
+ mProxy.requestRender();
+ }
mProxy.postRender();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 89aa96db7a92..ae83567ed159 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -187,7 +187,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.addCallback(this);
}
- if (mDumpController != null) mDumpController.addListener(this);
+ if (mDumpController != null) mDumpController.registerDumpable(getDumpableTag(), this);
}
@Override
@@ -202,10 +202,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.removeCallback(this);
}
- if (mDumpController != null) mDumpController.removeListener(this);
+ if (mDumpController != null) mDumpController.unregisterDumpable(this);
super.onDetachedFromWindow();
}
+ protected String getDumpableTag() {
+ return TAG;
+ }
+
@Override
public void onTilesChanged() {
setTiles(mHost.getTiles());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index fed59a526bab..b27bf32b9382 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -109,7 +109,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
defaultFactory.setHost(this);
mQsFactories.add(defaultFactory);
pluginManager.addPluginListener(this, QSFactory.class, true);
- mDumpController.addListener(this);
+ mDumpController.registerDumpable(TAG, this);
mainHandler.post(() -> {
// This is technically a hack to avoid circular dependency of
@@ -131,7 +131,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
mTunerService.removeTunable(this);
mServices.destroy();
mPluginManager.removePluginListener(this);
- mDumpController.removeListener(this);
+ mDumpController.unregisterDumpable(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 73f6fc5ea2f4..f1e9c8714776 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -96,6 +96,11 @@ public class QuickQSPanel extends QSPanel {
Dependency.get(TunerService.class).removeTunable(mNumTiles);
}
+ @Override
+ protected String getDumpableTag() {
+ return TAG;
+ }
+
public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
mFullPanel = fullPanel;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index a9896f51369c..822a6669bd5c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -22,6 +22,8 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
+import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -48,6 +50,7 @@ import com.android.systemui.R;
import java.io.File;
import java.io.IOException;
+import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
@@ -158,19 +161,34 @@ public class RecordingService extends Service {
case ACTION_STOP:
stopRecording();
- // Move temp file to user directory
- File recordDir = new File(
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),
- RECORD_DIR);
- recordDir.mkdirs();
-
String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
.format(new Date());
- Path path = new File(recordDir, fileName).toPath();
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
+ values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
+ values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis());
+ values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
+
+ ContentResolver resolver = getContentResolver();
+ Uri collectionUri = MediaStore.Video.Media.getContentUri(
+ MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ Uri itemUri = resolver.insert(collectionUri, values);
+
+ File recordDir = new File(getExternalFilesDir(Environment.DIRECTORY_MOVIES),
+ RECORD_DIR);
+ recordDir.mkdirs();
+ Path path = new File(recordDir, fileName).toPath();
try {
+ // Move file out of temp directory
Files.move(mTempFile.toPath(), path);
- Notification notification = createSaveNotification(path);
+
+ // Add to the mediastore
+ OutputStream os = resolver.openOutputStream(itemUri, "w");
+ Files.copy(path, os);
+ os.close();
+
+ Notification notification = createSaveNotification(itemUri, path);
notificationManager.notify(NOTIFICATION_ID, notification);
} catch (IOException e) {
e.printStackTrace();
@@ -352,13 +370,12 @@ public class RecordingService extends Service {
notificationManager.notify(NOTIFICATION_ID, mRecordingNotificationBuilder.build());
}
- private Notification createSaveNotification(Path path) {
- Uri saveUri = FileProvider.getUriForFile(this, FILE_PROVIDER, path.toFile());
- Log.d(TAG, "Screen recording saved to " + path.toString());
+ private Notification createSaveNotification(Uri uri, Path path) {
+ Log.d(TAG, "Screen recording saved to " + uri.toString() + ", " + path.toString());
Intent viewIntent = new Intent(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION)
- .setDataAndType(saveUri, "video/mp4");
+ .setDataAndType(uri, "video/mp4");
Notification.Action shareAction = new Notification.Action.Builder(
Icon.createWithResource(this, R.drawable.ic_android),
@@ -366,7 +383,7 @@ public class RecordingService extends Service {
PendingIntent.getService(
this,
REQUEST_CODE,
- getShareIntent(this, path.toString()),
+ getShareIntent(this, uri.toString()),
PendingIntent.FLAG_UPDATE_CURRENT))
.build();
@@ -376,7 +393,7 @@ public class RecordingService extends Service {
PendingIntent.getService(
this,
REQUEST_CODE,
- getDeleteIntent(this, path.toString()),
+ getDeleteIntent(this, uri.toString()),
PendingIntent.FLAG_UPDATE_CURRENT))
.build();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 0fe5f8a6af5a..4cc5b2144adc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -15,7 +15,6 @@
package com.android.systemui.statusbar;
import android.content.pm.UserInfo;
-import android.service.notification.StatusBarNotification;
import android.util.SparseArray;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -58,7 +57,7 @@ public interface NotificationLockscreenUserManager {
boolean shouldHideNotifications(int userId);
boolean shouldHideNotifications(String key);
- boolean shouldShowOnKeyguard(StatusBarNotification sbn);
+ boolean shouldShowOnKeyguard(NotificationEntry entry);
boolean isAnyProfilePublicMode();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 4ea1ed5b9451..e08a5ae07bd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -33,7 +33,6 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -302,7 +301,7 @@ public class NotificationLockscreenUserManagerImpl implements
Notification.VISIBILITY_SECRET;
}
- public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
+ public boolean shouldShowOnKeyguard(NotificationEntry entry) {
if (getEntryManager() == null) {
Log.wtf(TAG, "mEntryManager was null!", new Throwable());
return false;
@@ -310,10 +309,10 @@ public class NotificationLockscreenUserManagerImpl implements
boolean exceedsPriorityThreshold;
if (NotificationUtils.useNewInterruptionModel(mContext)
&& hideSilentNotificationsOnLockscreen()) {
- exceedsPriorityThreshold = getEntryManager().getNotificationData().isHighPriority(sbn);
+ exceedsPriorityThreshold = entry.isTopBucket();
} else {
exceedsPriorityThreshold =
- !getEntryManager().getNotificationData().isAmbient(sbn.getKey());
+ !getEntryManager().getNotificationData().isAmbient(entry.key);
}
return mShowLockscreenNotifications && exceedsPriorityThreshold;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index f001561754aa..00a12a9e4409 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -17,6 +17,10 @@ package com.android.systemui.statusbar;
import static com.android.systemui.Dependency.MAIN_HANDLER;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController
+ .MODE_WAKE_AND_UNLOCK_PULSING;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_MEDIA_FAKE_ARTWORK;
import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_WALLPAPER;
import static com.android.systemui.statusbar.phone.StatusBar.SHOW_LOCKSCREEN_MEDIA_ARTWORK;
@@ -595,9 +599,11 @@ public class NotificationMediaManager implements Dumpable {
boolean cannotAnimateDoze = shadeController != null
&& shadeController.isDozing()
&& !ScrimState.AOD.getAnimateChange();
- if (mBiometricUnlockController != null && mBiometricUnlockController.getMode()
+ boolean needsBypassFading = mKeyguardMonitor.isBypassFadingAnimation();
+ if (((mBiometricUnlockController != null && mBiometricUnlockController.getMode()
== BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
- || hideBecauseOccluded || cannotAnimateDoze) {
+ || cannotAnimateDoze) && !needsBypassFading)
+ || hideBecauseOccluded) {
// We are unlocking directly - no animation!
mBackdrop.setVisibility(View.GONE);
@@ -622,9 +628,7 @@ public class NotificationMediaManager implements Dumpable {
});
if (mKeyguardMonitor.isKeyguardFadingAway()) {
mBackdrop.animate()
- // Make it disappear faster, as the focus should be on the activity
- // behind.
- .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+ .setDuration(mKeyguardMonitor.getShortenedFadingAwayDuration())
.setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
.setInterpolator(Interpolators.LINEAR)
.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 4ccd0cd3353b..99682fcfccbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -374,6 +374,10 @@ public class NotificationShelf extends ActivatableNotificationView implements
clipTransientViews();
setClipTopAmount(clipTopAmount);
+ boolean isHidden = getViewState().hidden || clipTopAmount >= getIntrinsicHeight();
+ if (mShowNotificationShelf) {
+ setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE);
+ }
setBackgroundTop(backgroundTop);
setFirstElementRoundness(firstElementRoundness);
mShelfIcons.setSpeedBumpIndex(mAmbientState.getSpeedBumpIndex());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 22c91647d7f7..6e75c0375afc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -397,15 +397,13 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
int userId = entry.notification.getUserId();
boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
entry.notification) && !entry.isRowRemoved();
- boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry
- .notification);
+ boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry);
if (!showOnKeyguard) {
// min priority notifications should show if their summary is showing
if (mGroupManager.isChildInGroupWithSummary(entry.notification)) {
NotificationEntry summary = mGroupManager.getLogicalGroupSummary(
entry.notification);
- if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(
- summary.notification)) {
+ if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(summary)) {
showOnKeyguard = true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 0d9f4e7b909d..91d47077fc31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -153,6 +153,7 @@ public class ActivityLaunchAnimator {
if (primary == null) {
setAnimationPending(false);
invokeCallback(iRemoteAnimationFinishedCallback);
+ mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
index ea474ced7632..314dc04e574f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -21,6 +21,7 @@ import android.media.MediaMetadata
import android.provider.Settings
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -40,6 +41,7 @@ class BypassHeadsUpNotifier @Inject constructor(
private val bypassController: KeyguardBypassController,
private val statusBarStateController: StatusBarStateController,
private val headsUpManager: HeadsUpManagerPhone,
+ private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
private val mediaManager: NotificationMediaManager,
tunerService: TunerService) : StatusBarStateController.StateListener,
NotificationMediaManager.MediaListener {
@@ -63,7 +65,7 @@ class BypassHeadsUpNotifier @Inject constructor(
enabled = Settings.Secure.getIntForUser(
context.contentResolver,
Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING,
- 1 /* default */,
+ 0 /* default */,
KeyguardUpdateMonitor.getCurrentUser()) != 0
}, Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING)
}
@@ -79,9 +81,6 @@ class BypassHeadsUpNotifier @Inject constructor(
if (!NotificationMediaManager.isPlayingState(state)) {
newEntry = null
}
- if (newEntry?.isSensitive == true) {
- newEntry = null
- }
currentMediaEntry = newEntry
updateAutoHeadsUp(previous)
updateAutoHeadsUp(currentMediaEntry)
@@ -89,7 +88,7 @@ class BypassHeadsUpNotifier @Inject constructor(
private fun updateAutoHeadsUp(entry: NotificationEntry?) {
entry?.let {
- val autoHeadsUp = it == currentMediaEntry && canAutoHeadsUp()
+ val autoHeadsUp = it == currentMediaEntry && canAutoHeadsUp(it)
it.isAutoHeadsUp = autoHeadsUp
if (autoHeadsUp) {
headsUpManager.showNotification(it)
@@ -97,11 +96,36 @@ class BypassHeadsUpNotifier @Inject constructor(
}
}
+ /**
+ * @return {@code true} if this entry be autoHeadsUpped right now.
+ */
+ private fun canAutoHeadsUp(entry: NotificationEntry): Boolean {
+ if (!isAutoHeadsUpAllowed()) {
+ return false;
+ }
+ if (entry.isSensitive) {
+ // filter sensitive notifications
+ return false
+ }
+ if (!notificationLockscreenUserManager.shouldShowOnKeyguard(entry)) {
+ // filter notifications invisible on Keyguard
+ return false
+ }
+ if (!entryManager.notificationData.activeNotifications.contains(entry)) {
+ // filter notifications not the active list currently
+ return false
+ }
+ return true
+ }
+
override fun onStatePostChange() {
updateAutoHeadsUp(currentMediaEntry)
}
- private fun canAutoHeadsUp() : Boolean {
+ /**
+ * @return {@code true} if autoHeadsUp is possible right now.
+ */
+ private fun isAutoHeadsUpAllowed() : Boolean {
if (!enabled) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index f7e5bcf4769c..2f67f90a115e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -29,6 +29,7 @@ import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.statusbar.phone.PanelExpansionListener
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import javax.inject.Inject
@@ -40,7 +41,8 @@ class NotificationWakeUpCoordinator @Inject constructor(
private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
private val statusBarStateController: StatusBarStateController,
private val bypassController: KeyguardBypassController)
- : OnHeadsUpChangedListener, StatusBarStateController.StateListener {
+ : OnHeadsUpChangedListener, StatusBarStateController.StateListener,
+ PanelExpansionListener {
private val mNotificationVisibility
= object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
@@ -98,7 +100,9 @@ class NotificationWakeUpCoordinator @Inject constructor(
}
}
+ private var collapsedEnoughToHide: Boolean = false
lateinit var iconAreaController : NotificationIconAreaController
+
var pulsing: Boolean = false
set(value) {
field = value
@@ -120,7 +124,6 @@ class NotificationWakeUpCoordinator @Inject constructor(
}
}
}
-
/**
* True if we can show pulsing heads up notifications
*/
@@ -132,6 +135,10 @@ class NotificationWakeUpCoordinator @Inject constructor(
// We also allow pulsing on the lock screen!
canShow = canShow || (wakingUp || willWakeUp || fullyAwake)
&& statusBarStateController.state == StatusBarState.KEYGUARD
+ // We want to hide the notifications when collapsed too much
+ if (collapsedEnoughToHide) {
+ canShow = false
+ }
}
return canShow
}
@@ -140,6 +147,17 @@ class NotificationWakeUpCoordinator @Inject constructor(
mHeadsUpManagerPhone.addListener(this)
statusBarStateController.addCallback(this)
mDozeParameters = DozeParameters.getInstance(mContext)
+ addListener(object : WakeUpListener {
+ override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
+ if (isFullyHidden && mNotificationsVisibleForExpansion) {
+ // When the notification becomes fully invisible, let's make sure our expansion
+ // flag also changes. This can happen if the bouncer shows when dragging down
+ // and then the screen turning off, where we don't reset this state.
+ setNotificationsVisibleForExpansion(visible = false, animate = false,
+ increaseSpeed = false)
+ }
+ }
+ });
}
fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
@@ -247,6 +265,18 @@ class NotificationWakeUpCoordinator @Inject constructor(
this.state = newState
}
+ override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
+ val collapsedEnough = expansion <= 0.9f
+ if (collapsedEnough != this.collapsedEnoughToHide) {
+ val couldShowPulsingHuns = canShowPulsingHuns;
+ this.collapsedEnoughToHide = collapsedEnough
+ if (couldShowPulsingHuns && !canShowPulsingHuns) {
+ updateNotificationVisibility(animate = true, increaseSpeed = true)
+ mHeadsUpManagerPhone.releaseAllImmediately()
+ }
+ }
+ }
+
private fun updateDozeAmountIfBypass(): Boolean {
if (bypassController.bypassEnabled) {
var amount = 1.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index fca520fe0521..1ce493444e25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -25,7 +25,6 @@ import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
-import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
@@ -108,10 +107,19 @@ public class NotificationData {
boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH
&& isSystemNotification(nb);
- boolean isHeadsUp = a.getRow().isHeadsUp();
- if (isHeadsUp != b.getRow().isHeadsUp()) {
- return isHeadsUp ? -1 : 1;
- } else if (isHeadsUp) {
+
+ boolean aHeadsUp = a.getRow().isHeadsUp();
+ boolean bHeadsUp = b.getRow().isHeadsUp();
+
+ // HACK: This should really go elsewhere, but it's currently not straightforward to
+ // extract the comparison code and we're guaranteed to touch every element, so this is
+ // the best place to set the buckets for the moment.
+ a.setIsTopBucket(aHeadsUp || aMedia || aSystemMax || a.isHighPriority());
+ b.setIsTopBucket(bHeadsUp || bMedia || bSystemMax || b.isHighPriority());
+
+ if (aHeadsUp != bHeadsUp) {
+ return aHeadsUp ? -1 : 1;
+ } else if (aHeadsUp) {
// Provide consistent ranking with headsUpManager
return mHeadsUpManager.compare(a, b);
} else if (aMedia != bMedia) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index b19d2ca29c96..fe8854168288 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -173,9 +173,13 @@ public final class NotificationEntry {
* the lock screen/status bar and in the top section in the shade.
*/
private boolean mHighPriority;
+
+ private boolean mIsTopBucket;
+
private boolean mSensitive = true;
private Runnable mOnSensitiveChangedListener;
private boolean mAutoHeadsUp;
+ private boolean mPulseSupressed;
public NotificationEntry(StatusBarNotification n) {
this(n, null);
@@ -224,6 +228,18 @@ public final class NotificationEntry {
this.mHighPriority = highPriority;
}
+ /**
+ * @return True if the notif should appear in the "top" or "important" section of notifications
+ * (as opposed to the "bottom" or "silent" section). This is usually the same as
+ * {@link #isHighPriority()}, but there are certain exceptions, such as media notifs.
+ */
+ public boolean isTopBucket() {
+ return mIsTopBucket;
+ }
+ public void setIsTopBucket(boolean isTopBucket) {
+ mIsTopBucket = isTopBucket;
+ }
+
public boolean isBubble() {
return (notification.getNotification().flags & FLAG_BUBBLE) != 0;
}
@@ -900,6 +916,14 @@ public final class NotificationEntry {
mOnSensitiveChangedListener = listener;
}
+ public boolean isPulseSuppressed() {
+ return mPulseSupressed;
+ }
+
+ public void setPulseSuppressed(boolean suppressed) {
+ mPulseSupressed = suppressed;
+ }
+
/** Information about a suggestion that is being edited. */
public static class EditedSuggestionInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 8e6822770694..782aad17345e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -23,6 +23,7 @@ import android.app.NotificationChannel.DEFAULT_CHANNEL_ID
import android.app.NotificationChannelGroup
import android.app.NotificationManager.IMPORTANCE_NONE
import android.content.Context
+import android.content.DialogInterface
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
@@ -171,7 +172,6 @@ class ChannelEditorDialogController @Inject constructor(
private fun done() {
resetState()
dialog.dismiss()
- onFinishListener?.onChannelEditorDialogFinished()
}
private fun resetState() {
@@ -261,6 +261,11 @@ class ChannelEditorDialogController @Inject constructor(
dialog.apply {
setContentView(R.layout.notif_half_shelf)
setCanceledOnTouchOutside(true)
+ setOnDismissListener(object : DialogInterface.OnDismissListener {
+ override fun onDismiss(dialog: DialogInterface?) {
+ onFinishListener?.onChannelEditorDialogFinished()
+ }
+ })
findViewById<ChannelEditorListView>(R.id.half_shelf_container).apply {
controller = this@ChannelEditorDialogController
appIcon = this@ChannelEditorDialogController.appIcon
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index d057a1d2f20b..48a82957bf1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -349,7 +349,7 @@ public class NotificationContentInflater {
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
- result.newPublicView = builder.makePublicContentView();
+ result.newPublicView = builder.makePublicContentView(isLowPriority);
}
result.packageContext = packageContext;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 20e8b733ce6a..38f9bff2a63f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -39,6 +39,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.widget.MediaNotificationView;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.TransformableView;
@@ -67,6 +68,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
private View mSeekBarView;
private Context mContext;
private MetricsLogger mMetricsLogger;
+ private boolean mIsViewVisible;
@VisibleForTesting
protected SeekBar.OnSeekBarChangeListener mSeekListener =
@@ -88,11 +90,33 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
}
};
+ MediaNotificationView.VisibilityChangeListener mVisibilityListener =
+ new MediaNotificationView.VisibilityChangeListener() {
+ @Override
+ public void onAggregatedVisibilityChanged(boolean isVisible) {
+ mIsViewVisible = isVisible;
+ if (isVisible) {
+ // Restart timer if we're currently playing and didn't already have one going
+ PlaybackState state = mMediaController.getPlaybackState();
+ if (state != null && state.getState() == PlaybackState.STATE_PLAYING
+ && mSeekBarTimer == null && mSeekBarView != null
+ && mSeekBarView.getVisibility() != View.GONE) {
+ startTimer();
+ }
+ } else {
+ clearTimer();
+ }
+ }
+ };
+
private MediaController.Callback mMediaCallback = new MediaController.Callback() {
@Override
public void onSessionDestroyed() {
clearTimer();
mMediaController.unregisterCallback(this);
+ if (mView instanceof MediaNotificationView) {
+ ((MediaNotificationView) mView).removeVisibilityListener(mVisibilityListener);
+ }
}
@Override
@@ -126,10 +150,16 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
mContext = ctx;
mMediaManager = Dependency.get(NotificationMediaManager.class);
mMetricsLogger = Dependency.get(MetricsLogger.class);
+
+ if (mView instanceof MediaNotificationView) {
+ MediaNotificationView mediaView = (MediaNotificationView) mView;
+ mediaView.addVisibilityListener(mVisibilityListener);
+ }
}
private void resolveViews() {
mActions = mView.findViewById(com.android.internal.R.id.media_actions);
+ mIsViewVisible = mView.isShown();
final MediaSession.Token token = mRow.getEntry().notification.getNotification().extras
.getParcelable(Notification.EXTRA_MEDIA_SESSION);
@@ -208,18 +238,19 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
private void startTimer() {
clearTimer();
- mSeekBarTimer = new Timer(true /* isDaemon */);
- mSeekBarTimer.schedule(new TimerTask() {
- @Override
- public void run() {
- mHandler.post(mOnUpdateTimerTick);
- }
- }, 0, PROGRESS_UPDATE_INTERVAL);
+ if (mIsViewVisible) {
+ mSeekBarTimer = new Timer(true /* isDaemon */);
+ mSeekBarTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ mHandler.post(mOnUpdateTimerTick);
+ }
+ }, 0, PROGRESS_UPDATE_INTERVAL);
+ }
}
private void clearTimer() {
if (mSeekBarTimer != null) {
- // TODO: also trigger this when the notification panel is collapsed
mSeekBarTimer.cancel();
mSeekBarTimer.purge();
mSeekBarTimer = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 212808dae8e3..15cc72c2d7a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -184,4 +184,6 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange
default boolean containsView(View v) {
return true;
}
+
+ default void setWillExpand(boolean willExpand) {};
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 170a4d570688..d119fb79e4c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -133,7 +133,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide
if (child instanceof ExpandableNotificationRow
&& child.getVisibility() != View.GONE) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- if (!row.getEntry().isHighPriority()) {
+ if (!row.getEntry().isTopBucket()) {
firstGentleNotifIndex = i;
mFirstGentleNotif = row;
break;
@@ -248,7 +248,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide
View child = mParent.getChildAt(i);
if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- if (!row.getEntry().isHighPriority()) {
+ if (!row.getEntry().isTopBucket()) {
break;
} else {
lastChildBeforeGap = row;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 04cbb130c243..1a418665dd2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -411,6 +411,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
outline.setRoundRect(mBackgroundAnimationRect,
MathUtils.lerp(mCornerRadius / 2.0f, mCornerRadius,
xProgress));
+ outline.setAlpha(1.0f - mAmbientState.getHideAmount());
} else {
ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
}
@@ -499,6 +500,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private boolean mAnimateBottomOnLayout;
private float mLastSentAppear;
private float mLastSentExpandedHeight;
+ private boolean mWillExpand;
@Inject
public NotificationStackScrollLayout(
@@ -1043,6 +1045,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
requestChildrenUpdate();
updateFirstAndLastBackgroundViews();
updateAlgorithmLayoutMinHeight();
+ updateOwnTranslationZ();
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4406,6 +4409,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mStateAnimator.setShadeExpanded(isExpanded);
mSwipeHelper.setIsExpanded(isExpanded);
if (changed) {
+ mWillExpand = false;
if (!mIsExpanded) {
mGroupManager.collapseAllGroups();
mExpandHelper.cancelImmediately();
@@ -4774,6 +4778,20 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
updateAlgorithmHeightAndPadding();
updateBackgroundDimming();
requestChildrenUpdate();
+ updateOwnTranslationZ();
+ }
+
+ private void updateOwnTranslationZ() {
+ // Since we are clipping to the outline we need to make sure that the shadows aren't
+ // clipped when pulsing
+ float ownTranslationZ = 0;
+ if (mKeyguardBypassController.getBypassEnabled() && mAmbientState.isHiddenAtAll()) {
+ ExpandableView firstChildNotGone = getFirstChildNotGone();
+ if (firstChildNotGone != null && firstChildNotGone.showingPulsing()) {
+ ownTranslationZ = firstChildNotGone.getTranslationZ();
+ }
+ }
+ setTranslationZ(ownTranslationZ);
}
private void updateVisibility() {
@@ -5054,7 +5072,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) {
mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
mNeedsAnimation = true;
- if (!mIsExpanded && !isHeadsUp) {
+ if (!mIsExpanded && !mWillExpand && !isHeadsUp) {
row.setHeadsUpAnimatingAway(true);
}
requestChildrenUpdate();
@@ -5075,6 +5093,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
requestChildrenUpdate();
}
+ @Override
+ public void setWillExpand(boolean willExpand) {
+ mWillExpand = willExpand;
+ }
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setTrackingHeadsUp(ExpandableNotificationRow row) {
mTrackingHeadsUp = row != null;
@@ -5675,6 +5698,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
// The bottom might change because we're using the final actual height of the view
mAnimateBottomOnLayout = true;
}
+ // Let's update the footer once the notifications have been updated (in the next frame)
+ post(this::updateFooter);
}
public void setOnPulseHeightChangedListener(Runnable listener) {
@@ -5745,7 +5770,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
currentIndex++;
boolean beforeSpeedBump;
if (mHighPriorityBeforeSpeedBump) {
- beforeSpeedBump = row.getEntry().isHighPriority();
+ beforeSpeedBump = row.getEntry().isTopBucket();
} else {
beforeSpeedBump = !row.getEntry().ambient;
}
@@ -5803,9 +5828,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
case ROWS_ALL:
return true;
case ROWS_HIGH_PRIORITY:
- return row.getEntry().isHighPriority();
+ return row.getEntry().isTopBucket();
case ROWS_GENTLE:
- return !row.getEntry().isHighPriority();
+ return !row.getEntry().isTopBucket();
default:
throw new IllegalArgumentException("Unknown selection: " + selection);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 7655056ea60b..ef8048487022 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -161,6 +161,7 @@ public class StackScrollAlgorithm {
: 0;
float clipStart = 0;
int childCount = algorithmState.visibleChildren.size();
+ boolean firstHeadsUp = true;
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
ExpandableViewState state = child.getViewState();
@@ -173,7 +174,7 @@ public class StackScrollAlgorithm {
boolean isHeadsUp = (child instanceof ExpandableNotificationRow)
&& ((ExpandableNotificationRow) child).isPinned();
if (mClipNotificationScrollToTop
- && (!state.inShelf || isHeadsUp)
+ && (!state.inShelf || (isHeadsUp && !firstHeadsUp))
&& newYTranslation < clipStart) {
// The previous view is overlapping on top, clip!
float overlapAmount = clipStart - newYTranslation;
@@ -181,7 +182,9 @@ public class StackScrollAlgorithm {
} else {
state.clipTopAmount = 0;
}
-
+ if (isHeadsUp) {
+ firstHeadsUp = false;
+ }
if (!child.isTransparent()) {
// Only update the previous values if we are not transparent,
// otherwise we would clip to a transparent view.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 94cd2cdaa9d3..41c6a7ba7848 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -445,14 +445,13 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
if (!mUpdateMonitor.isDeviceInteractive()) {
if (!mStatusBarKeyguardViewManager.isShowing()) {
return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE;
- } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
+ } else if (!unlockingAllowed) {
+ return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
+ } else if (mDozeScrimController.isPulsing()) {
// Let's not wake-up to lock screen when not bypassing, otherwise the notification
// would move as the user tried to tap it.
return bypass ? MODE_WAKE_AND_UNLOCK_PULSING : MODE_NONE;
} else {
- if (!(mDozeScrimController.isPulsing() && !unlockingAllowed)) {
- Log.wtf(TAG, "Face somehow arrived when the device was not interactive");
- }
if (bypass) {
// Wake-up fading out nicely
return MODE_WAKE_AND_UNLOCK_PULSING;
@@ -530,7 +529,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
mStatusBar.notifyBiometricAuthModeChanged();
}
- private final WakefulnessLifecycle.Observer mWakefulnessObserver =
+ @VisibleForTesting
+ final WakefulnessLifecycle.Observer mWakefulnessObserver =
new WakefulnessLifecycle.Observer() {
@Override
public void onFinishedWakingUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 539bc7bcb3f6..d22ad71594b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.Interpolators.ALPHA_IN;
import static com.android.systemui.Interpolators.ALPHA_OUT;
+import static com.android.systemui.Interpolators.LINEAR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -33,7 +34,7 @@ import java.util.ArrayList;
*/
public class ButtonDispatcher {
private final static int FADE_DURATION_IN = 150;
- private final static int FADE_DURATION_OUT = 100;
+ private final static int FADE_DURATION_OUT = 1000;
private final ArrayList<View> mViews = new ArrayList<>();
@@ -178,7 +179,7 @@ public class ButtonDispatcher {
setVisibility(View.VISIBLE);
mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), alpha);
mFadeAnimator.setDuration(duration);
- mFadeAnimator.setInterpolator(getAlpha() < alpha ? ALPHA_IN : ALPHA_OUT);
+ mFadeAnimator.setInterpolator(LINEAR);
mFadeAnimator.addListener(mFadeListener);
mFadeAnimator.addUpdateListener(mAlphaListener);
mFadeAnimator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index d6f8a606af55..c4d346ccaefb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -170,7 +170,7 @@ public class KeyguardBouncer {
// Split up the work over multiple frames.
DejankUtils.removeCallbacks(mResetRunnable);
- if (mUnlockMethodCache.isUnlockingWithFacePossible() && !needsFullscreenBouncer()
+ if (mUnlockMethodCache.isFaceAuthEnabled() && !needsFullscreenBouncer()
&& !mKeyguardUpdateMonitor.userNeedsStrongAuth()) {
mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
} else {
@@ -207,14 +207,12 @@ public class KeyguardBouncer {
* @see #onFullyShown()
*/
private void onFullyHidden() {
- if (!mShowingSoon) {
- cancelShowRunnable();
- if (mRoot != null) {
- mRoot.setVisibility(View.INVISIBLE);
- }
- mFalsingManager.onBouncerHidden();
- DejankUtils.postAfterTraversal(mResetRunnable);
+ cancelShowRunnable();
+ if (mRoot != null) {
+ mRoot.setVisibility(View.INVISIBLE);
}
+ mFalsingManager.onBouncerHidden();
+ DejankUtils.postAfterTraversal(mResetRunnable);
}
private final Runnable mShowRunnable = new Runnable() {
@@ -349,7 +347,7 @@ public class KeyguardBouncer {
* {@link #show(boolean)} was called but we're not showing yet, or being dragged.
*/
public boolean inTransit() {
- return mShowingSoon || mExpansion != EXPANSION_HIDDEN;
+ return mShowingSoon || mExpansion != EXPANSION_HIDDEN && mExpansion != EXPANSION_VISIBLE;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 0aec2b12fa92..70d3bff9b822 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -47,7 +47,7 @@ class KeyguardBypassController {
* If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
*/
var bypassEnabled: Boolean = false
- get() = field && unlockMethodCache.isUnlockingWithFacePossible
+ get() = field && unlockMethodCache.isFaceAuthEnabled
private set
var bouncerShowing: Boolean = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index b13af8bea784..06a2225ed0bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -323,14 +323,24 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
}
updateDarkTint();
+ updateIconVisibility();
+ updateClickability();
+
+ return true;
+ }
+
+ /**
+ * Update the icon visibility
+ * @return true if the visibility changed
+ */
+ private boolean updateIconVisibility() {
boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
|| mShowingLaunchAffordance;
if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
- if (mHeadsUpManager.isHeadsUpGoingAway()
- || mHeadsUpManager.hasPinnedHeadsUp()
- || (mStatusBarStateController.getState() == StatusBarState.KEYGUARD
- && !mWakeUpCoordinator.getNotificationsFullyHidden())) {
+ if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp()
+ || mStatusBarStateController.getState() == StatusBarState.KEYGUARD)
+ && !mWakeUpCoordinator.getNotificationsFullyHidden()) {
invisible = true;
}
}
@@ -349,10 +359,9 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
.setDuration(233)
.start();
}
+ return true;
}
- updateClickability();
-
- return true;
+ return false;
}
private boolean canBlockUpdates() {
@@ -440,7 +449,10 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
if (mBypassController.getBypassEnabled()) {
- update();
+ boolean changed = updateIconVisibility();
+ if (changed) {
+ update();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 22e3edb2bbd8..081e29381a65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -21,7 +21,9 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SEARCH_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -706,7 +708,7 @@ public class NavigationBarView extends FrameLayout implements
}
}
- public void onPanelExpandedChange() {
+ public void onStatusBarPanelStateChanged() {
updateSlippery();
updateSystemUiStateFlags();
}
@@ -719,9 +721,13 @@ public class NavigationBarView extends FrameLayout implements
(mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0, displayId);
mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_HOME_DISABLED,
(mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0, displayId);
+ mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SEARCH_DISABLED,
+ (mDisabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0, displayId);
if (mPanelView != null) {
mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
mPanelView.isFullyExpanded() && !mPanelView.isInSettings(), displayId);
+ mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
+ mPanelView.isInSettings(), displayId);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
index 0fe12943614c..4f7af58094ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
@@ -53,8 +53,8 @@ public class NavigationHandle extends View implements ButtonInterface {
final int dualToneLightTheme = Utils.getThemeAttr(context, R.attr.lightIconTheme);
Context lightContext = new ContextThemeWrapper(context, dualToneLightTheme);
Context darkContext = new ContextThemeWrapper(context, dualToneDarkTheme);
- mLightColor = Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor);
- mDarkColor = Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor);
+ mLightColor = Utils.getColorAttrDefaultColor(lightContext, R.attr.homeHandleColor);
+ mDarkColor = Utils.getColorAttrDefaultColor(darkContext, R.attr.homeHandleColor);
mPaint.setAntiAlias(true);
setFocusable(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 21de8a59836e..ba3406999388 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -78,6 +78,7 @@ public class NotificationIconAreaController implements DarkReceiver,
private int mAodIconTint;
private boolean mFullyHidden;
private boolean mAodIconsVisible;
+ private boolean mIsPulsing;
public NotificationIconAreaController(Context context, StatusBar statusBar,
StatusBarStateController statusBarStateController,
@@ -265,7 +266,9 @@ public class NotificationIconAreaController implements DarkReceiver,
if (!showAmbient && entry.shouldSuppressStatusBar()) {
return false;
}
- if (hidePulsing && entry.showingPulsing()) {
+ if (hidePulsing && entry.showingPulsing()
+ && (!mWakeUpCoordinator.getNotificationsFullyHidden()
+ || !entry.isPulseSuppressed())) {
return false;
}
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 901afab4a6f7..d0626ed780e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -40,6 +40,7 @@ import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
@@ -139,6 +140,12 @@ public class NotificationPanelView extends PanelView implements
private static final int CAP_HEIGHT = 1456;
private static final int FONT_HEIGHT = 2163;
+ /**
+ * Maximum time before which we will expand the panel even for slow motions when getting a
+ * touch passed over from launcher.
+ */
+ private static final int MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER = 300;
+
static final String COUNTER_PANEL_OPEN = "panel_open";
static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
@@ -374,6 +381,8 @@ public class NotificationPanelView extends PanelView implements
private boolean mHeadsUpPinnedMode;
private float mKeyguardHeadsUpShowingAmount = 0.0f;
private boolean mShowingKeyguardHeadsUp;
+ private boolean mAllowExpandForSmallExpansion;
+ private Runnable mExpandAfterLayoutRunnable;
@Inject
public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -671,6 +680,10 @@ public class NotificationPanelView extends PanelView implements
}
updateMaxHeadsUpTranslation();
updateGestureExclusionRect();
+ if (mExpandAfterLayoutRunnable != null) {
+ mExpandAfterLayoutRunnable.run();
+ mExpandAfterLayoutRunnable = null;
+ }
}
private void updateGestureExclusionRect() {
@@ -808,8 +821,7 @@ public class NotificationPanelView extends PanelView implements
if (suppressedSummary) {
continue;
}
- if (!mLockscreenUserManager.shouldShowOnKeyguard(
- row.getStatusBarNotification())) {
+ if (!mLockscreenUserManager.shouldShowOnKeyguard(row.getEntry())) {
continue;
}
if (row.isRemoved()) {
@@ -1070,6 +1082,8 @@ public class NotificationPanelView extends PanelView implements
mDownY = event.getY();
mCollapsedOnDown = isFullyCollapsed();
mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
+ mAllowExpandForSmallExpansion = mExpectingSynthesizedDown;
+ mTouchSlopExceededBeforeDown = mExpectingSynthesizedDown;
if (mExpectingSynthesizedDown) {
mLastEventSynthesizedDown = true;
} else {
@@ -1128,6 +1142,20 @@ public class NotificationPanelView extends PanelView implements
}
@Override
+ protected boolean shouldExpandWhenNotFlinging() {
+ if (super.shouldExpandWhenNotFlinging()) {
+ return true;
+ }
+ if (mAllowExpandForSmallExpansion) {
+ // When we get a touch that came over from launcher, the velocity isn't always correct
+ // Let's err on expanding if the gesture has been reasonably slow
+ long timeSinceDown = SystemClock.uptimeMillis() - mDownTime;
+ return timeSinceDown <= MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER;
+ }
+ return false;
+ }
+
+ @Override
protected float getOpeningHeight() {
return mNotificationStackScroller.getOpeningHeight();
}
@@ -1283,6 +1311,7 @@ public class NotificationPanelView extends PanelView implements
}
mExpectingSynthesizedDown = true;
onTrackingStarted();
+ updatePanelExpanded();
}
/**
@@ -1299,10 +1328,19 @@ public class NotificationPanelView extends PanelView implements
*
* @param velocity unit is in px / millis
*/
- public void stopWaitingForOpenPanelGesture(float velocity) {
+ public void stopWaitingForOpenPanelGesture(final float velocity) {
if (mExpectingSynthesizedDown) {
mExpectingSynthesizedDown = false;
- fling(velocity > 1f ? 1000f * velocity : 0, true /* animate */);
+ maybeVibrateOnOpening();
+ Runnable runnable = () -> fling(velocity > 1f ? 1000f * velocity : 0,
+ true /* expand */);
+ if (mStatusBar.getStatusBarWindow().getHeight()
+ != mStatusBar.getStatusBarHeight()) {
+ // The panel is already expanded to its full size, let's expand directly
+ runnable.run();
+ } else {
+ mExpandAfterLayoutRunnable = runnable;
+ }
onTrackingStopped(false);
}
}
@@ -1565,9 +1603,15 @@ public class NotificationPanelView extends PanelView implements
anim.setStartDelay(mKeyguardMonitor.isKeyguardFadingAway()
? mKeyguardMonitor.getKeyguardFadingAwayDelay()
: 0);
- anim.setDuration(mKeyguardMonitor.isKeyguardFadingAway()
- ? mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2
- : StackStateAnimator.ANIMATION_DURATION_STANDARD);
+
+ long duration;
+ if (mKeyguardMonitor.isKeyguardFadingAway()) {
+ duration = mKeyguardMonitor.getShortenedFadingAwayDuration();
+ } else {
+ duration = StackStateAnimator.ANIMATION_DURATION_STANDARD;
+ }
+ anim.setDuration(duration);
+
anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
anim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -1610,7 +1654,7 @@ public class NotificationPanelView extends PanelView implements
mKeyguardBottomArea.animate()
.alpha(0f)
.setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
- .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+ .setDuration(mKeyguardMonitor.getShortenedFadingAwayDuration())
.setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable)
.start();
@@ -1639,7 +1683,7 @@ public class NotificationPanelView extends PanelView implements
if (keyguardFadingAway) {
mKeyguardStatusView.animate()
.setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
- .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+ .setDuration(mKeyguardMonitor.getShortenedFadingAwayDuration())
.start();
}
} else if (mBarState == StatusBarState.SHADE_LOCKED
@@ -1722,8 +1766,8 @@ public class NotificationPanelView extends PanelView implements
mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
}
- if (mExpansionListener != null) {
- mExpansionListener.onQsExpansionChanged(mQsMaxExpansionHeight != 0
+ for (int i = 0; i < mExpansionListeners.size(); i++) {
+ mExpansionListeners.get(i).onQsExpansionChanged(mQsMaxExpansionHeight != 0
? mQsExpansionHeight / mQsMaxExpansionHeight : 0);
}
if (DEBUG) {
@@ -1923,7 +1967,8 @@ public class NotificationPanelView extends PanelView implements
* @return Whether we should intercept a gesture to open Quick Settings.
*/
private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) {
- if (!mQsExpansionEnabled || mCollapsedOnDown) {
+ if (!mQsExpansionEnabled || mCollapsedOnDown
+ || (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled())) {
return false;
}
View header = mKeyguardShowing || mQs == null ? mKeyguardStatusBar : mQs.getHeader();
@@ -2034,7 +2079,7 @@ public class NotificationPanelView extends PanelView implements
}
private void updatePanelExpanded() {
- boolean isExpanded = !isFullyCollapsed();
+ boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown;
if (mPanelExpanded != isExpanded) {
mHeadsUpManager.setIsPanelExpanded(isExpanded);
mStatusBar.setPanelExpanded(isExpanded);
@@ -3379,24 +3424,4 @@ public class NotificationPanelView extends PanelView implements
mOnReinflationListener = onReinflationListener;
}
- /**
- * Panel and QS expansion callbacks.
- */
- public interface PanelExpansionListener {
- /**
- * Invoked whenever the notification panel expansion changes, at every animation frame.
- * This is the main expansion that happens when the user is swiping up to dismiss the
- * lock screen.
- *
- * @param expansion 0 when collapsed, 1 when expanded.
- * @param tracking {@code true} when the user is actively dragging the panel.
- */
- void onPanelExpansionChanged(float expansion, boolean tracking);
-
- /**
- * Invoked whenever the QS expansion changes, at every animation frame.
- * @param expansion 0 when collapsed, 1 when expanded.
- */
- void onQsExpansionChanged(float expansion);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java
new file mode 100644
index 000000000000..655a25d22337
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.systemui.statusbar.phone;
+
+/**
+ * Panel and QS expansion callbacks.
+ */
+public interface PanelExpansionListener {
+ /**
+ * Invoked whenever the notification panel expansion changes, at every animation frame.
+ * This is the main expansion that happens when the user is swiping up to dismiss the
+ * lock screen.
+ *
+ * @param expansion 0 when collapsed, 1 when expanded.
+ * @param tracking {@code true} when the user is actively dragging the panel.
+ */
+ void onPanelExpansionChanged(float expansion, boolean tracking);
+
+ /**
+ * Invoked whenever the QS expansion changes, at every animation frame.
+ * @param expansion 0 when collapsed, 1 when expanded.
+ */
+ default void onQsExpansionChanged(float expansion) {};
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 853faabbbc81..31600e391f34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -49,11 +49,11 @@ import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView.PanelExpansionListener;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
@@ -61,14 +61,15 @@ public abstract class PanelView extends FrameLayout {
private static final int INITIAL_OPENING_PEEK_DURATION = 200;
private static final int PEEK_ANIMATION_DURATION = 360;
private static final int NO_FIXED_DURATION = -1;
- private long mDownTime;
+ protected long mDownTime;
+ protected boolean mTouchSlopExceededBeforeDown;
private float mMinExpandHeight;
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mPanelUpdateWhenAnimatorEnds;
private boolean mVibrateOnOpening;
protected boolean mLaunchingNotification;
private int mFixedDuration = NO_FIXED_DURATION;
- protected PanelExpansionListener mExpansionListener;
+ protected ArrayList<PanelExpansionListener> mExpansionListeners = new ArrayList<>();
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -322,7 +323,7 @@ public abstract class PanelView extends FrameLayout {
if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning)
|| mPeekAnimator != null) {
mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)
- || mPeekAnimator != null;
+ || mPeekAnimator != null || mTouchSlopExceededBeforeDown;
cancelHeightAnimator();
cancelPeek();
onTrackingStarted();
@@ -408,9 +409,7 @@ public abstract class PanelView extends FrameLayout {
runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
false /* collapseWhenFinished */);
notifyBarPanelExpansionChanged();
- if (mVibrateOnOpening) {
- mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
- }
+ maybeVibrateOnOpening();
//TODO: keyguard opens QS a different way; log that too?
@@ -425,6 +424,12 @@ public abstract class PanelView extends FrameLayout {
rot);
}
+ protected void maybeVibrateOnOpening() {
+ if (mVibrateOnOpening) {
+ mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+ }
+ }
+
protected abstract float getOpeningHeight();
/**
@@ -576,7 +581,7 @@ public abstract class PanelView extends FrameLayout {
mInitialTouchY = y;
mInitialTouchX = x;
mTouchStartedInEmptyArea = !isInContentBounds(x, y);
- mTouchSlopExceeded = false;
+ mTouchSlopExceeded = mTouchSlopExceededBeforeDown;
mJustPeeked = false;
mMotionAborted = false;
mPanelClosedOnDown = isFullyCollapsed();
@@ -679,12 +684,16 @@ public abstract class PanelView extends FrameLayout {
return true;
}
if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
- return getExpandedFraction() > 0.5f;
+ return shouldExpandWhenNotFlinging();
} else {
return vel > 0;
}
}
+ protected boolean shouldExpandWhenNotFlinging() {
+ return getExpandedFraction() > 0.5f;
+ }
+
/**
* @param x the final x-coordinate when the finger was lifted
* @param y the final y-coordinate when the finger was lifted
@@ -1173,13 +1182,13 @@ public abstract class PanelView extends FrameLayout {
|| mPeekAnimator != null || mInstantExpanding
|| isPanelVisibleBecauseOfHeadsUp() || mTracking || mHeightAnimator != null);
}
- if (mExpansionListener != null) {
- mExpansionListener.onPanelExpansionChanged(mExpandedFraction, mTracking);
+ for (int i = 0; i < mExpansionListeners.size(); i++) {
+ mExpansionListeners.get(i).onPanelExpansionChanged(mExpandedFraction, mTracking);
}
}
- public void setExpansionListener(PanelExpansionListener panelExpansionListener) {
- mExpansionListener = panelExpansionListener;
+ public void addExpansionListener(PanelExpansionListener panelExpansionListener) {
+ mExpansionListeners.add(panelExpansionListener);
}
protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 660810fe7eb9..8efd952e67c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -46,7 +46,6 @@ import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.Objects;
@@ -279,7 +278,7 @@ public class PhoneStatusBarView extends PanelBar {
super.panelExpansionChanged(frac, expanded);
updateScrimFraction();
if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
- mBar.getNavigationBarView().onPanelExpandedChange();
+ mBar.getNavigationBarView().onStatusBarPanelStateChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 1aec5e4d0b1d..b12bf5c39970 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -491,8 +491,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
* away once the display turns on.
*/
public void prepareForGentleWakeUp() {
- if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()) {
+ if (mState == ScrimState.AOD) {
mCurrentInFrontAlpha = 1f;
+ mCurrentInFrontTint = Color.BLACK;
+ mCurrentBehindTint = Color.BLACK;
mAnimateChange = false;
updateScrims();
mAnimateChange = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 763e0d70469b..c706062d3bb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -129,7 +129,10 @@ public enum ScrimState {
public void prepare(ScrimState previousState) {
mCurrentInFrontAlpha = 0f;
mCurrentBehindTint = Color.BLACK;
+ mCurrentInFrontTint = Color.BLACK;
mBlankScreen = mDisplayRequiresBlanking;
+ mAnimationDuration = mWakeLockScreenSensorActive
+ ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 9f1ec4d6894a..f15b60123a80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -489,9 +489,12 @@ public class StatusBar extends SystemUI implements DemoMode,
WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
+ final boolean imageWallpaperInAmbient =
+ !DozeParameters.getInstance(mContext).getDisplayNeedsBlanking();
// If WallpaperInfo is null, it must be ImageWallpaper.
final boolean supportsAmbientMode = deviceSupportsAodWallpaper
- && (info == null || info.supportsAmbientMode());
+ && ((info == null && imageWallpaperInAmbient)
+ || (info != null && info.supportsAmbientMode()));
mStatusBarWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
@@ -813,6 +816,7 @@ public class StatusBar extends SystemUI implements DemoMode,
inflateShelf();
mNotificationIconAreaController.setupShelf(mNotificationShelf);
mNotificationPanel.setOnReinflationListener(mNotificationIconAreaController::initAodIcons);
+ mNotificationPanel.addExpansionListener(mWakeUpCoordinator);
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
// Allow plugins to reference DarkIconDispatcher and StatusBarStateController
@@ -1508,6 +1512,9 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanel.setStatusAccessibilityImportance(expanded
? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ if (getNavigationBarView() != null) {
+ getNavigationBarView().onStatusBarPanelStateChanged();
+ }
}
public boolean isWakeUpComingFromTouch() {
@@ -1578,7 +1585,8 @@ public class StatusBar extends SystemUI implements DemoMode,
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
mEntryManager.updateNotifications();
if (isDozing() && isHeadsUp) {
- mDozeServiceHost.fireNotificationPulse();
+ entry.setPulseSuppressed(false);
+ mDozeServiceHost.fireNotificationPulse(entry);
if (mPulsing) {
mDozeScrimController.cancelPendingPulseTimeout();
}
@@ -1802,6 +1810,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
}
mNotificationPanel.expand(true /* animate */);
+ ((NotificationListContainer) mStackScroller).setWillExpand(true);
+ mHeadsUpManager.unpinAll(true /* userUnpinned */);
mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
} else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
mNotificationPanel.flingSettings(0 /* velocity */,
@@ -1939,7 +1949,6 @@ public class StatusBar extends SystemUI implements DemoMode,
if (start) {
mNotificationPanel.startWaitingForOpenPanelGesture();
- setPanelExpanded(true);
} else {
mNotificationPanel.stopWaitingForOpenPanelGesture(velocity);
}
@@ -2388,6 +2397,10 @@ public class StatusBar extends SystemUI implements DemoMode,
mLightBarController.dump(fd, pw, args);
}
+ if (mUnlockMethodCache != null) {
+ mUnlockMethodCache.dump(pw);
+ }
+
if (mKeyguardBypassController != null) {
mKeyguardBypassController.dump(pw);
}
@@ -3200,12 +3213,13 @@ public class StatusBar extends SystemUI implements DemoMode,
/**
* Notifies the status bar the Keyguard is fading away with the specified timings.
- *
- * @param startTime the start time of the animations in uptime millis
+ * @param startTime the start time of the animations in uptime millis
* @param delay the precalculated animation delay in milliseconds
* @param fadeoutDuration the duration of the exit animation, in milliseconds
+ * @param isBypassFading is this a fading away animation while bypassing
*/
- public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
+ public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration,
+ boolean isBypassFading) {
mCommandQueue.appTransitionStarting(mDisplayId, startTime + fadeoutDuration
- LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
@@ -3213,7 +3227,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mCommandQueue.appTransitionStarting(mDisplayId,
startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
- mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
+ mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration, isBypassFading);
}
/**
@@ -3563,6 +3577,9 @@ public class StatusBar extends SystemUI implements DemoMode,
userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
|| !mLockscreenUserManager.shouldShowLockscreenNotifications()
|| mFalsingManager.shouldEnforceBouncer();
+ if (mKeyguardBypassController.getBypassEnabled()) {
+ fullShadeNeedsBouncer = false;
+ }
if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
showBouncerIfKeyguard();
@@ -3920,9 +3937,13 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- public void fireNotificationPulse() {
+ public void fireNotificationPulse(NotificationEntry entry) {
+ Runnable pulseSupressedListener = () -> {
+ entry.setPulseSuppressed(true);
+ mNotificationIconAreaController.updateAodNotificationIcons();
+ };
for (Callback callback : mCallbacks) {
- callback.onNotificationAlerted();
+ callback.onNotificationAlerted(pulseSupressedListener);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5ce1329d5a89..3508c90bc8a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -70,7 +70,7 @@ import java.util.ArrayList;
*/
public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
- NotificationPanelView.PanelExpansionListener, NavigationModeController.ModeChangedListener {
+ PanelExpansionListener, NavigationModeController.ModeChangedListener {
// When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -223,7 +223,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
mExpansionCallback, falsingManager);
mNotificationPanelView = notificationPanelView;
- notificationPanelView.setExpansionListener(this);
+ notificationPanelView.addExpansionListener(this);
mBypassController = bypassController;
mNotificationContainer = notificationContainer;
}
@@ -561,18 +561,22 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
executeAfterKeyguardGoneAction();
boolean wakeUnlockPulsing =
mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
- if (wakeUnlockPulsing) {
+ boolean needsFading = needsBypassFading();
+ if (needsFading) {
+ delay = 0;
+ fadeoutDuration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION;
+ } else if (wakeUnlockPulsing) {
delay = 0;
fadeoutDuration = 240;
}
- mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
+ mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration, needsFading);
mBiometricUnlockController.startKeyguardFadingAway();
hideBouncer(true /* destroyView */);
if (wakeUnlockPulsing) {
- if (needsBypassFading()) {
+ if (needsFading) {
ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
mNotificationContainer,
- KeyguardBypassController.BYPASS_PANEL_FADE_DURATION,
+ fadeoutDuration,
() -> {
mStatusBar.hideKeyguard();
onKeyguardFadedAway();
@@ -585,10 +589,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
if (!staying) {
mStatusBarWindowController.setKeyguardFadingAway(true);
- if (needsBypassFading()) {
+ if (needsFading) {
ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
mNotificationContainer,
- KeyguardBypassController.BYPASS_PANEL_FADE_DURATION,
+ fadeoutDuration,
() -> {
mStatusBar.hideKeyguard();
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 4ddd0e9962ad..d9a9f7cbc2a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -51,12 +51,13 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.google.android.collect.Lists;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
-
import java.util.ArrayList;
+
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -352,7 +353,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat
}
private void applyForceStatusBarVisibleFlag(State state) {
- if (state.forceStatusBarVisible) {
+ if (state.forceStatusBarVisible || state.forcePluginOpen) {
mLpChanged.privateFlags |= WindowManager
.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index a71fcdbd9914..b1d6ca6e5580 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -28,6 +28,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
@@ -51,7 +52,7 @@ public class UnlockMethodCache {
private boolean mTrustManaged;
private boolean mTrusted;
private boolean mDebugUnlocked = false;
- private boolean mIsUnlockingWithFacePossible;
+ private boolean mFaceAuthEnabled;
private UnlockMethodCache(Context ctx) {
mLockPatternUtils = new LockPatternUtils(ctx);
@@ -110,8 +111,8 @@ public class UnlockMethodCache {
/**
* If there are faces enrolled and user enabled face auth on keyguard.
*/
- public boolean isUnlockingWithFacePossible() {
- return mIsUnlockingWithFacePossible;
+ public boolean isFaceAuthEnabled() {
+ return mFaceAuthEnabled;
}
private void update(boolean updateAlways) {
@@ -122,16 +123,16 @@ public class UnlockMethodCache {
|| (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
- boolean isUnlockingWithFacePossible = mKeyguardUpdateMonitor.isUnlockWithFacePossible(user);
+ boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(user);
boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer
|| trustManaged != mTrustManaged
- || mIsUnlockingWithFacePossible != isUnlockingWithFacePossible;
+ || mFaceAuthEnabled != faceAuthEnabled;
if (changed || updateAlways) {
mSecure = secure;
mCanSkipBouncer = canSkipBouncer;
mTrusted = trusted;
mTrustManaged = trustManaged;
- mIsUnlockingWithFacePossible = isUnlockingWithFacePossible;
+ mFaceAuthEnabled = faceAuthEnabled;
notifyListeners();
}
Trace.endSection();
@@ -143,6 +144,16 @@ public class UnlockMethodCache {
}
}
+ public void dump(PrintWriter pw) {
+ pw.println("UnlockMethodCache");
+ pw.println(" mSecure: " + mSecure);
+ pw.println(" mCanSkipBouncer: " + mCanSkipBouncer);
+ pw.println(" mTrustManaged: " + mTrustManaged);
+ pw.println(" mTrusted: " + mTrusted);
+ pw.println(" mDebugUnlocked: " + mDebugUnlocked);
+ pw.println(" mFaceAuthEnabled: " + mFaceAuthEnabled);
+ }
+
private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onUserSwitchComplete(int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index f61b556e22ab..070136ec94c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -29,6 +29,19 @@ public interface KeyguardMonitor extends CallbackController<Callback> {
long getKeyguardFadingAwayDelay();
long calculateGoingToFullShadeDelay();
+ /**
+ * @return a shortened fading away duration similar to
+ * {{@link #getKeyguardFadingAwayDuration()}} which may only span half of the duration, unless
+ * we're bypassing
+ */
+ default long getShortenedFadingAwayDuration() {
+ if (isBypassFadingAnimation()) {
+ return getKeyguardFadingAwayDuration();
+ } else {
+ return getKeyguardFadingAwayDuration() / 2;
+ }
+ }
+
default boolean isDeviceInteractive() {
return false;
}
@@ -39,7 +52,21 @@ public interface KeyguardMonitor extends CallbackController<Callback> {
default void notifyKeyguardGoingAway(boolean b) {
}
- default void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
+ /**
+ * @return {@code true} if the current fading away animation is the fast bypass fading.
+ */
+ default boolean isBypassFadingAnimation() {
+ return false;
+ }
+
+ /**
+ * Notifies that the Keyguard is fading away with the specified timings.
+ * @param delay the precalculated animation delay in milliseconds
+ * @param fadeoutDuration the duration of the exit animation, in milliseconds
+ * @param isBypassFading is this a fading away animation while bypassing
+ */
+ default void notifyKeyguardFadingAway(long delay, long fadeoutDuration,
+ boolean isBypassFading) {
}
default void notifyKeyguardDoneFading() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index 68d00708b0d3..8829be4ee0f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -54,6 +54,7 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback
private long mKeyguardFadingAwayDuration;
private boolean mKeyguardGoingAway;
private boolean mLaunchTransitionFadingAway;
+ private boolean mBypassFadingAnimation;
/**
*/
@@ -140,10 +141,11 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback
new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
}
- public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
+ public void notifyKeyguardFadingAway(long delay, long fadeoutDuration, boolean isBypassFading) {
setKeyguardFadingAway(true);
mKeyguardFadingAwayDelay = delay;
mKeyguardFadingAwayDuration = fadeoutDuration;
+ mBypassFadingAnimation = isBypassFading;
}
private void setKeyguardFadingAway(boolean keyguardFadingAway) {
@@ -172,6 +174,11 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback
}
@Override
+ public boolean isBypassFadingAnimation() {
+ return mBypassFadingAnimation;
+ }
+
+ @Override
public long getKeyguardFadingAwayDelay() {
return mKeyguardFadingAwayDelay;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 3f3e1e32a951..a6b5b38fd728 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -43,6 +43,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
@@ -275,14 +276,14 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
}
public boolean areCaptionsEnabled() {
- int currentValue = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.ODI_CAPTIONS_ENABLED, 0);
+ int currentValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ODI_CAPTIONS_ENABLED, 0, UserHandle.USER_CURRENT);
return currentValue == 1;
}
public void setCaptionsEnabled(boolean isEnabled) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0);
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0, UserHandle.USER_CURRENT);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt
index cca35ca39606..d921d5832a01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/DumpControllerTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,6 +36,7 @@ class DumpControllerTest : SysuiTestCase() {
private lateinit var controller: DumpController
@Mock private lateinit var callback1: Dumpable
@Mock private lateinit var callback2: Dumpable
+ @Mock private lateinit var callback3: Dumpable
@Mock private lateinit var fd: FileDescriptor
@Mock private lateinit var pw: PrintWriter
private val args = emptyArray<String>()
@@ -46,40 +46,81 @@ class DumpControllerTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
controller = DumpController()
-// Debug.waitForDebugger()
}
- @Test
+ @Test(expected = IllegalArgumentException::class)
fun testListenerOnlyAddedOnce() {
+ controller.registerDumpable("cb1", callback1)
+ controller.registerDumpable("cb1", callback2)
+ }
+
+ @Test
+ fun testListenersCalledOnDump() {
controller.apply {
- addListener(callback1)
- addListener(callback1)
+ registerDumpable("cb1", callback1)
+ registerDumpable("cb2", callback2)
}
- assertEquals(1, controller.numListeners)
controller.dump(fd, pw, args)
+
verify(callback1 /* only once */).dump(fd, pw, args)
+ verify(callback2 /* only once */).dump(fd, pw, args)
}
@Test
- fun testListenersCalledOnDump() {
+ fun testListenersAreFiltered() {
+ controller.apply {
+ registerDumpable("cb1", callback1)
+ registerDumpable("cb2", callback2)
+ registerDumpable("cb3", callback3)
+ }
+
+ val args = arrayOf("dependency", "DumpController", "cb3,cb1")
+ controller.dump(fd, pw, args)
+
+ verify(callback1 /* only once */).dump(fd, pw, args)
+ verify(callback2, never()).dump(fd, pw, args)
+ verify(callback3 /* only once */).dump(fd, pw, args)
+ }
+
+ @Test
+ fun testFiltersAreNotCaseSensitive() {
+ controller.apply {
+ registerDumpable("cb1", callback1)
+ registerDumpable("cb2", callback2)
+ registerDumpable("cb3", callback3)
+ }
+
+ val args = arrayOf("dependency", "DumpController", "CB3")
+ controller.dump(fd, pw, args)
+
+ verify(callback1, never()).dump(fd, pw, args)
+ verify(callback2, never()).dump(fd, pw, args)
+ verify(callback3 /* only once */).dump(fd, pw, args)
+ }
+
+ @Test
+ fun testFiltersAreIgnoredIfPrecedingArgsDontMatch() {
controller.apply {
- addListener(callback1)
- addListener(callback2)
+ registerDumpable("cb1", callback1)
+ registerDumpable("cb2", callback2)
+ registerDumpable("cb3", callback3)
}
+ val args = arrayOf("", "", "cb2")
controller.dump(fd, pw, args)
verify(callback1 /* only once */).dump(fd, pw, args)
verify(callback2 /* only once */).dump(fd, pw, args)
+ verify(callback3 /* only once */).dump(fd, pw, args)
}
@Test
fun testRemoveListener() {
controller.apply {
- addListener(callback1)
- addListener(callback2)
- removeListener(callback1)
+ registerDumpable("cb1", callback1)
+ registerDumpable("cb2", callback2)
+ unregisterDumpable(callback1)
}
controller.dump(fd, pw, args)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index eb8ef09d0635..d4642238d8fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -95,13 +95,13 @@ public class DozeTriggersTest extends SysuiTestCase {
mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
clearInvocations(mMachine);
- mHost.callback.onNotificationAlerted();
+ mHost.callback.onNotificationAlerted(null /* pulseSuppressedListener */);
mSensors.getMockProximitySensor().sendProximityResult(false); /* Near */
verify(mMachine, never()).requestState(any());
verify(mMachine, never()).requestPulse(anyInt());
- mHost.callback.onNotificationAlerted();
+ mHost.callback.onNotificationAlerted(null /* pulseSuppressedListener */);
mSensors.getMockProximitySensor().sendProximityResult(true); /* Far */
verify(mMachine).requestPulse(anyInt());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
new file mode 100644
index 000000000000..eb71dd6ee677
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2019 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.systemui.shared.recents.model;
+
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNull;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class TaskKeyLruCacheTest extends SysuiTestCase {
+ private static int sCacheSize = 3;
+ private static int sIdTask1 = 1;
+ private static int sIdTask2 = 2;
+ private static int sIdTask3 = 3;
+ private static int sIdUser1 = 1;
+
+ TaskKeyCache<Integer> mCache = new TaskKeyLruCache<>(sCacheSize, null);
+ Task.TaskKey mKey1;
+ Task.TaskKey mKey2;
+ Task.TaskKey mKey3;
+
+ @Before
+ public void setup() {
+ mKey1 = new Task.TaskKey(sIdTask1, 0, null, null, sIdUser1, System.currentTimeMillis());
+ mKey2 = new Task.TaskKey(sIdTask2, 0, null, null, sIdUser1, System.currentTimeMillis());
+ mKey3 = new Task.TaskKey(sIdTask3, 0, null, null, sIdUser1, System.currentTimeMillis());
+ }
+
+ @Test
+ public void addSingleItem_get_success() {
+ mCache.put(mKey1, 1);
+
+ assertEquals(1, (int) mCache.get(mKey1));
+ }
+
+ @Test
+ public void addSingleItem_getUninsertedItem_returnsNull() {
+ mCache.put(mKey1, 1);
+
+ assertNull(mCache.get(mKey2));
+ }
+
+ @Test
+ public void emptyCache_get_returnsNull() {
+ assertNull(mCache.get(mKey1));
+ }
+
+ @Test
+ public void updateItem_get_returnsSecond() {
+ mCache.put(mKey1, 1);
+ mCache.put(mKey1, 2);
+
+ assertEquals(2, (int) mCache.get(mKey1));
+ assertEquals(1, mCache.mKeys.size());
+ }
+
+ @Test
+ public void fillCache_put_evictsOldest() {
+ mCache.put(mKey1, 1);
+ mCache.put(mKey2, 2);
+ mCache.put(mKey3, 3);
+ Task.TaskKey key4 = new Task.TaskKey(sIdTask3 + 1, 0,
+ null, null, sIdUser1, System.currentTimeMillis());
+ mCache.put(key4, 4);
+
+ assertNull(mCache.get(mKey1));
+ assertEquals(3, mCache.mKeys.size());
+ assertEquals(mKey2, mCache.mKeys.valueAt(0));
+ }
+
+ @Test
+ public void fillCache_remove_success() {
+ mCache.put(mKey1, 1);
+ mCache.put(mKey2, 2);
+ mCache.put(mKey3, 3);
+
+ mCache.remove(mKey2);
+
+ assertNull(mCache.get(mKey2));
+ assertEquals(2, mCache.mKeys.size());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 49a263a8d781..57dd8c94c790 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -38,7 +38,6 @@ import android.os.Handler;
import android.os.Looper;
import android.os.UserManager;
import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -48,6 +47,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -166,7 +166,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
when(mNotificationData.isHighPriority(any())).thenReturn(false);
- assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class)));
+ assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class)));
}
@Test
@@ -179,7 +179,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
when(mNotificationData.isHighPriority(any())).thenReturn(false);
- assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class)));
+ assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class)));
}
private class TestNotificationLockscreenUserManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 73abda9a5da7..59d0f912d38e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -263,6 +263,8 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
when(notifRow.getEntry().isHighPriority())
.thenReturn(children[i] == ChildType.HIPRI);
+ when(notifRow.getEntry().isTopBucket())
+ .thenReturn(children[i] == ChildType.HIPRI);
when(notifRow.getParent()).thenReturn(mNssl);
child = notifRow;
break;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 7d9920db36a4..fd676111b1da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -82,7 +82,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
- when(mUnlockMethodCache.isUnlockingWithFacePossible()).thenReturn(true);
+ when(mUnlockMethodCache.isFaceAuthEnabled()).thenReturn(true);
when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
mContext.addMockSystemService(PowerManager.class, mPowerManager);
@@ -161,6 +161,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
@Test
public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showBouncer() {
+ reset(mUpdateMonitor);
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -168,11 +169,18 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FACE);
+ // Wake up before showing the bouncer
+ verify(mStatusBarKeyguardViewManager, never()).showBouncer(eq(false));
+ mBiometricUnlockController.mWakefulnessObserver.onFinishedWakingUp();
+
verify(mStatusBarKeyguardViewManager).showBouncer(eq(false));
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
}
@Test
public void onBiometricAuthenticated_whenFace_noBypass_encrypted_doNothing() {
+ reset(mUpdateMonitor);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(false);
@@ -181,6 +189,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_NONE);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 4e0ef56ad830..907e695f2513 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -379,7 +379,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Test
public void testShow_delaysIfFaceAuthIsRunning() {
- when(mUnlockMethodCache.isUnlockingWithFacePossible()).thenReturn(true);
+ when(mUnlockMethodCache.isFaceAuthEnabled()).thenReturn(true);
mBouncer.show(true /* reset */);
ArgumentCaptor<Runnable> showRunnable = ArgumentCaptor.forClass(Runnable.class);
@@ -394,4 +394,15 @@ public class KeyguardBouncerTest extends SysuiTestCase {
public void testRegisterUpdateMonitorCallback() {
verify(mKeyguardUpdateMonitor).registerCallback(any());
}
+
+ @Test
+ public void testInTransit_whenTranslation() {
+ mBouncer.show(true);
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
+ assertThat(mBouncer.inTransit()).isFalse();
+ mBouncer.setExpansion(0.5f);
+ assertThat(mBouncer.inTransit()).isTrue();
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
+ assertThat(mBouncer.inTransit()).isFalse();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index d8e90a584058..0dbf30881ffe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -225,11 +225,12 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimController.transitionTo(ScrimState.PULSING);
mScrimController.finishAnimationsImmediately();
- // Front scrim should be transparent
+ // Front scrim should be transparent, but tinted
// Back scrim should be semi-transparent so the user can see the wallpaper
// Pulse callback should have been invoked
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
assertScrimTint(mScrimBehind, true /* tinted */);
+ assertScrimTint(mScrimInFront, true /* tinted */);
mScrimController.setWakeLockScreenSensorActive(true);
mScrimController.finishAnimationsImmediately();
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index f9a2ca269335..8ad24894a1b9 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -551,6 +551,30 @@ message WifiLog {
// Histogram of the EAP method type of all installed Passpoint profiles for R2
repeated PasspointProfileTypeCount installed_passpoint_profile_type_for_r2 = 148;
+
+ // Histogram of Tx link speed at 2G
+ repeated Int32Count tx_link_speed_count_2g = 149;
+
+ // Histogram of Tx link speed at 5G low band
+ repeated Int32Count tx_link_speed_count_5g_low = 150;
+
+ // Histogram of Tx link speed at 5G middle band
+ repeated Int32Count tx_link_speed_count_5g_mid = 151;
+
+ // Histogram of Tx link speed at 5G high band
+ repeated Int32Count tx_link_speed_count_5g_high = 152;
+
+ // Histogram of Rx link speed at 2G
+ repeated Int32Count rx_link_speed_count_2g = 153;
+
+ // Histogram of Rx link speed at 5G low band
+ repeated Int32Count rx_link_speed_count_5g_low = 154;
+
+ // Histogram of Rx link speed at 5G middle band
+ repeated Int32Count rx_link_speed_count_5g_mid = 155;
+
+ // Histogram of Rx link speed at 5G high band
+ repeated Int32Count rx_link_speed_count_5g_high = 156;
}
// Information that gets logged for every WiFi connection.
@@ -827,6 +851,7 @@ message LinkSpeedCount {
optional int64 rssi_sum_of_squares_dbm_sq = 4;
}
+
// Number of occurrences of Soft AP session durations
message SoftApDurationBucket {
// Bucket covers duration : [duration_sec, duration_sec + bucket_size_sec)
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 2db7f0e108b4..d923bedd15c1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -23,6 +23,7 @@ import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCE
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
+import android.accessibilityservice.AccessibilityGestureInfo;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.accessibilityservice.IAccessibilityServiceConnection;
@@ -89,7 +90,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
protected final Context mContext;
protected final SystemSupport mSystemSupport;
- private final WindowManagerInternal mWindowManagerService;
+ protected final WindowManagerInternal mWindowManagerService;
private final GlobalActionPerformer mGlobalActionPerformer;
private final AccessibilityWindowManager mA11yWindowManager;
private final DisplayManager mDisplayManager;
@@ -167,9 +168,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
@Nullable MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId);
/**
- * @return The current injector of motion events, if one exists
+ * @param displayId The display id.
+ * @return The current injector of motion events used on the display, if one exists.
*/
- @Nullable MotionEventInjector getMotionEventInjectorLocked();
+ @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId);
/**
* @return The current dispatcher for fingerprint gestures, if one exists
@@ -715,6 +717,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
@Override
+ public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
+ }
+
+ @Override
public boolean performAccessibilityAction(int accessibilityWindowId,
long accessibilityNodeId, int action, Bundle arguments, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
@@ -1159,9 +1165,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
- public void notifyGesture(int gestureId) {
+ public void notifyGesture(AccessibilityGestureInfo gestureInfo) {
mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
- gestureId, 0).sendToTarget();
+ gestureInfo).sendToTarget();
}
public void notifyClearAccessibilityNodeInfoCache() {
@@ -1250,13 +1256,13 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
- private void notifyGestureInternal(int gestureId) {
+ private void notifyGestureInternal(AccessibilityGestureInfo gestureInfo) {
final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
if (listener != null) {
try {
- listener.onGesture(gestureId);
+ listener.onGesture(gestureInfo);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
+ Slog.e(LOG_TAG, "Error during sending gesture " + gestureInfo
+ " to " + mService, re);
}
}
@@ -1451,8 +1457,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int type = message.what;
switch (type) {
case MSG_ON_GESTURE: {
- final int gestureId = message.arg1;
- notifyGestureInternal(gestureId);
+ notifyGestureInternal((AccessibilityGestureInfo) message.obj);
} break;
case MSG_CLEAR_ACCESSIBILITY_CACHE: {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index d7670112d55c..b4ac92f0cf55 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -16,21 +16,15 @@
package com.android.server.accessibility;
+import android.accessibilityservice.AccessibilityGestureInfo;
import android.accessibilityservice.AccessibilityService;
import android.content.Context;
-import android.gesture.Gesture;
import android.gesture.GesturePoint;
-import android.gesture.GestureStore;
-import android.gesture.GestureStroke;
-import android.gesture.Prediction;
import android.graphics.PointF;
import android.util.Slog;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-
-import com.android.internal.R;
import java.util.ArrayList;
@@ -125,11 +119,11 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
/**
* Called when an event stream is recognized as a gesture.
*
- * @param gestureId ID of the gesture that was recognized.
+ * @param gestureInfo Information about the gesture.
*
* @return true if the event is consumed, else false
*/
- boolean onGestureCompleted(int gestureId);
+ boolean onGestureCompleted(AccessibilityGestureInfo gestureInfo);
/**
* Called when the system has decided an event stream doesn't match any
@@ -562,6 +556,7 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
private boolean recognizeGesturePath(MotionEvent event, int policyFlags,
ArrayList<PointF> path) {
+ final int displayId = event.getDisplayId();
if (path.size() == 2) {
PointF start = path.get(0);
PointF end = path.get(1);
@@ -571,13 +566,21 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
int direction = toDirection(dX, dY);
switch (direction) {
case LEFT:
- return mListener.onGestureCompleted(AccessibilityService.GESTURE_SWIPE_LEFT);
+ return mListener.onGestureCompleted(
+ new AccessibilityGestureInfo(AccessibilityService.GESTURE_SWIPE_LEFT,
+ displayId));
case RIGHT:
- return mListener.onGestureCompleted(AccessibilityService.GESTURE_SWIPE_RIGHT);
+ return mListener.onGestureCompleted(
+ new AccessibilityGestureInfo(AccessibilityService.GESTURE_SWIPE_RIGHT,
+ displayId));
case UP:
- return mListener.onGestureCompleted(AccessibilityService.GESTURE_SWIPE_UP);
+ return mListener.onGestureCompleted(
+ new AccessibilityGestureInfo(AccessibilityService.GESTURE_SWIPE_UP,
+ displayId));
case DOWN:
- return mListener.onGestureCompleted(AccessibilityService.GESTURE_SWIPE_DOWN);
+ return mListener.onGestureCompleted(
+ new AccessibilityGestureInfo(AccessibilityService.GESTURE_SWIPE_DOWN,
+ displayId));
default:
// Do nothing.
}
@@ -596,7 +599,8 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen
int segmentDirection0 = toDirection(dX0, dY0);
int segmentDirection1 = toDirection(dX1, dY1);
int gestureId = DIRECTIONS_TO_GESTURE_ID[segmentDirection0][segmentDirection1];
- return mListener.onGestureCompleted(gestureId);
+ return mListener.onGestureCompleted(
+ new AccessibilityGestureInfo(gestureId, displayId));
}
// else if (path.size() < 2 || 3 < path.size()) then no gesture recognized.
return mListener.onGestureCancelled(event, policyFlags);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index b6cbbacde118..5111bec4913b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -114,7 +114,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
private final SparseArray<MagnificationGestureHandler> mMagnificationGestureHandler =
new SparseArray<>(0);
- private final SparseArray<MotionEventInjector> mMotionEventInjector = new SparseArray<>(0);
+ private final SparseArray<MotionEventInjector> mMotionEventInjectors = new SparseArray<>(0);
private AutoclickController mAutoclickController;
@@ -412,12 +412,14 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
MotionEventInjector injector = new MotionEventInjector(
mContext.getMainLooper());
addFirstEventHandler(displayId, injector);
- // TODO: Need to set MotionEventInjector per display.
- mAms.setMotionEventInjector(injector);
- mMotionEventInjector.put(displayId, injector);
+ mMotionEventInjectors.put(displayId, injector);
}
}
+ if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
+ mAms.setMotionEventInjectors(mMotionEventInjectors);
+ }
+
if ((mEnabledFeatures & FLAG_FEATURE_FILTER_KEY_EVENTS) != 0) {
mKeyboardInterceptor = new KeyboardInterceptor(mAms,
LocalServices.getService(WindowManagerPolicy.class));
@@ -462,15 +464,14 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
private void disableFeatures() {
- for (int i = mMotionEventInjector.size() - 1; i >= 0; i--) {
- final MotionEventInjector injector = mMotionEventInjector.valueAt(i);
- // TODO: Need to set MotionEventInjector per display.
- mAms.setMotionEventInjector(null);
+ for (int i = mMotionEventInjectors.size() - 1; i >= 0; i--) {
+ final MotionEventInjector injector = mMotionEventInjectors.valueAt(i);
if (injector != null) {
injector.onDestroy();
}
}
- mMotionEventInjector.clear();
+ mAms.setMotionEventInjectors(null);
+ mMotionEventInjectors.clear();
if (mAutoclickController != null) {
mAutoclickController.onDestroy();
mAutoclickController = null;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index a2204518e762..814853694347 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -27,6 +27,7 @@ import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest;
+import android.accessibilityservice.AccessibilityGestureInfo;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
@@ -210,7 +211,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private KeyEventDispatcher mKeyEventDispatcher;
- private MotionEventInjector mMotionEventInjector;
+ private SparseArray<MotionEventInjector> mMotionEventInjectors;
private FingerprintGestureDispatcher mFingerprintGestureDispatcher;
@@ -815,11 +816,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
- boolean onGesture(int gestureId) {
+ boolean onGesture(AccessibilityGestureInfo gestureInfo) {
synchronized (mLock) {
- boolean handled = notifyGestureLocked(gestureId, false);
+ boolean handled = notifyGestureLocked(gestureInfo, false);
if (!handled) {
- handled = notifyGestureLocked(gestureId, true);
+ handled = notifyGestureLocked(gestureInfo, true);
}
return handled;
}
@@ -860,30 +861,34 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector.
* Not using a getter because the AccessibilityInputFilter isn't thread-safe
*
- * @param motionEventInjector The new value of the motionEventInjector. May be null.
+ * @param motionEventInjectors The array of motionEventInjectors. May be null.
+ *
*/
- void setMotionEventInjector(MotionEventInjector motionEventInjector) {
+ void setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors) {
synchronized (mLock) {
- mMotionEventInjector = motionEventInjector;
+ mMotionEventInjectors = motionEventInjectors;
// We may be waiting on this object being set
mLock.notifyAll();
}
}
@Override
- public MotionEventInjector getMotionEventInjectorLocked() {
+ public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) {
final long endMillis = SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS;
- while ((mMotionEventInjector == null) && (SystemClock.uptimeMillis() < endMillis)) {
+ MotionEventInjector motionEventInjector = null;
+ while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) {
try {
mLock.wait(endMillis - SystemClock.uptimeMillis());
} catch (InterruptedException ie) {
/* ignore */
}
}
- if (mMotionEventInjector == null) {
+ if (mMotionEventInjectors == null) {
Slog.e(LOG_TAG, "MotionEventInjector installation timed out");
+ } else {
+ motionEventInjector = mMotionEventInjectors.get(displayId);
}
- return mMotionEventInjector;
+ return motionEventInjector;
}
/**
@@ -1010,7 +1015,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
- private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
+ private boolean notifyGestureLocked(AccessibilityGestureInfo gestureInfo, boolean isDefault) {
// TODO: Now we are giving the gestures to the last enabled
// service that can handle them which is the last one
// in our list since we write the last enabled as the
@@ -1024,7 +1029,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
AccessibilityServiceConnection service = state.mBoundServices.get(i);
if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
- service.notifyGesture(gestureId);
+ service.notifyGesture(gestureInfo);
return true;
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 02306c02fa6f..961168a46c7d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -238,7 +238,6 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
return (userState != null) ? userState.getSoftKeyboardShowMode() : 0;
}
-
@Override
public boolean isAccessibilityButtonAvailable() {
synchronized (mLock) {
@@ -354,12 +353,13 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
}
@Override
- public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
+ public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
+ final boolean isTouchableDisplay = mWindowManagerService.isTouchableDisplay(displayId);
synchronized (mLock) {
if (mSecurityPolicy.canPerformGestures(this)) {
MotionEventInjector motionEventInjector =
- mSystemSupport.getMotionEventInjectorLocked();
- if (motionEventInjector != null) {
+ mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
+ if (motionEventInjector != null && isTouchableDisplay) {
motionEventInjector.injectEvents(
gestureSteps.getList(), mServiceInterface, sequence);
} else {
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 7920bbb7b179..380e853820ff 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -20,6 +20,7 @@ import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.server.accessibility.TouchState.ALL_POINTER_ID_BITS;
+import android.accessibilityservice.AccessibilityGestureInfo;
import android.content.Context;
import android.graphics.Point;
import android.os.Handler;
@@ -356,14 +357,14 @@ class TouchExplorer extends BaseEventStreamTransformation
}
@Override
- public boolean onGestureCompleted(int gestureId) {
+ public boolean onGestureCompleted(AccessibilityGestureInfo gestureInfo) {
if (!mState.isGestureDetecting()) {
return false;
}
endGestureDetection(true);
- mAms.onGesture(gestureId);
+ mAms.onGesture(gestureInfo);
return true;
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 73f5cb8326ea..e2cdddb932d7 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -165,7 +165,13 @@ final class SaveUi {
mComponentName = componentName;
mCompatMode = compatMode;
- context = new ContextThemeWrapper(context, mThemeId);
+ context = new ContextThemeWrapper(context, mThemeId) {
+ @Override
+ public void startActivity(Intent intent) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ super.startActivity(intent);
+ }
+ };
final LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(R.layout.autofill_save, null);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 9855e4ea339a..474dbfe49d70 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -13,12 +13,14 @@ java_library_static {
},
srcs: [
"java/**/*.java",
+ ":platformcompat_aidl",
":dumpstate_aidl",
":idmap2_aidl",
":installd_aidl",
":storaged_aidl",
":vold_aidl",
":gsiservice_aidl",
+ ":platform-compat-config",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
"java/com/android/server/policy/EventLogTags.logtags",
@@ -80,3 +82,11 @@ prebuilt_etc {
name: "gps_debug.conf",
src: "java/com/android/server/location/gps_debug.conf",
}
+
+filegroup {
+ name: "platformcompat_aidl",
+ srcs: [
+ "java/com/android/server/compat/IPlatformCompat.aidl",
+ ],
+ path: "java",
+}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index ddfc3a631be6..a30371876955 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1742,6 +1742,12 @@ public class DeviceIdleController extends SystemService
return mConstants;
}
+
+ /** Returns the current elapsed realtime in milliseconds. */
+ long getElapsedRealtime() {
+ return SystemClock.elapsedRealtime();
+ }
+
LocationManager getLocationManager() {
if (mLocationManager == null) {
mLocationManager = mContext.getSystemService(LocationManager.class);
@@ -2023,7 +2029,7 @@ public class DeviceIdleController extends SystemService
private void unregisterDeviceIdleConstraintInternal(IDeviceIdleConstraint constraint) {
synchronized (this) {
- // Artifically force the constraint to inactive to unblock anything waiting for it.
+ // Artificially force the constraint to inactive to unblock anything waiting for it.
onConstraintStateChangedLocked(constraint, /* active= */ false);
// Let the constraint know that we are not listening to it any more.
@@ -2746,9 +2752,18 @@ public class DeviceIdleController extends SystemService
mState = STATE_QUICK_DOZE_DELAY;
// Make sure any motion sensing or locating is stopped.
resetIdleManagementLocked();
- // Wait a small amount of time in case something (eg: background service from
- // recently closed app) needs to finish running.
- scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+ if (isUpcomingAlarmClock()) {
+ // If there's an upcoming AlarmClock alarm, we won't go into idle, so
+ // setting a wakeup alarm before the upcoming alarm is futile. Set the quick
+ // doze alarm to after the upcoming AlarmClock alarm.
+ scheduleAlarmLocked(
+ mAlarmManager.getNextWakeFromIdleTime() - mInjector.getElapsedRealtime()
+ + mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+ } else {
+ // Wait a small amount of time in case something (eg: background service from
+ // recently closed app) needs to finish running.
+ scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+ }
EventLogTags.writeDeviceIdle(mState, "no activity");
} else if (mState == STATE_ACTIVE) {
mState = STATE_INACTIVE;
@@ -2758,7 +2773,16 @@ public class DeviceIdleController extends SystemService
if (shouldUseIdleTimeoutFactorLocked()) {
delay = (long) (mPreIdleFactor * delay);
}
- scheduleAlarmLocked(delay, false);
+ if (isUpcomingAlarmClock()) {
+ // If there's an upcoming AlarmClock alarm, we won't go into idle, so
+ // setting a wakeup alarm before the upcoming alarm is futile. Set the idle
+ // alarm to after the upcoming AlarmClock alarm.
+ scheduleAlarmLocked(
+ mAlarmManager.getNextWakeFromIdleTime() - mInjector.getElapsedRealtime()
+ + delay, false);
+ } else {
+ scheduleAlarmLocked(delay, false);
+ }
EventLogTags.writeDeviceIdle(mState, "no activity");
}
}
@@ -2906,13 +2930,21 @@ public class DeviceIdleController extends SystemService
return mState;
}
+ /**
+ * Returns true if there's an upcoming AlarmClock alarm that is soon enough to prevent the
+ * device from going into idle.
+ */
+ private boolean isUpcomingAlarmClock() {
+ return mInjector.getElapsedRealtime() + mConstants.MIN_TIME_TO_ALARM
+ >= mAlarmManager.getNextWakeFromIdleTime();
+ }
+
@VisibleForTesting
void stepIdleStateLocked(String reason) {
if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
EventLogTags.writeDeviceIdleStep();
- final long now = SystemClock.elapsedRealtime();
- if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
+ if (isUpcomingAlarmClock()) {
// Whoops, there is an upcoming alarm. We don't actually want to go idle.
if (mState != STATE_ACTIVE) {
mActiveReason = ACTIVE_REASON_ALARM;
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index f92d0e0ff6f1..173d5b053309 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -21,6 +21,7 @@ import android.content.pm.PackageManager;
import android.gsi.GsiInstallParams;
import android.gsi.GsiProgress;
import android.gsi.IGsiService;
+import android.gsi.IGsid;
import android.os.Environment;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
@@ -61,7 +62,9 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
* re-initialized in this case.
*/
binder.linkToDeath(recipient, 0);
- return IGsiService.Stub.asInterface(binder);
+
+ IGsid gsid = IGsid.Stub.asInterface(binder);
+ return gsid.getClient();
}
/** implements DeathRecipient */
@@ -159,7 +162,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
isInUse = getGsiService().isGsiRunning();
} finally {
if (!gsidWasRunning && !isInUse) {
- SystemProperties.set("ctl.stop", "gsid");
+ mGsiService = null;
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index f7e825eecc12..e66e596d5038 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1027,12 +1027,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log(str);
}
mLocalLog.log(str);
- // for service state updates, don't notify clients when subId is invalid. This prevents
- // us from sending incorrect notifications like b/133140128
- // In the future, we can remove this logic for every notification here and add a
- // callback so listeners know when their PhoneStateListener's subId becomes invalid, but
- // for now we use the simplest fix.
- if (validatePhoneId(phoneId) && SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (validatePhoneId(phoneId)) {
mServiceState[phoneId] = state;
for (Record r : mRecords) {
@@ -1064,8 +1059,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
} else {
- log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId
- + " or subId=" + subId);
+ log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId);
}
handleRemoveListLocked();
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 30a356325ada..b9d7c687704c 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -48,7 +48,6 @@ import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.Settings.Secure;
import android.service.dreams.Sandman;
import android.service.vr.IVrManager;
@@ -218,6 +217,15 @@ final class UiModeManagerService extends SystemService {
}
};
+ private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE,
+ mNightMode, 0);
+ SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode));
+ }
+ };
+
@Override
public void onSwitchUser(int userHandle) {
super.onSwitchUser(userHandle);
@@ -293,6 +301,9 @@ final class UiModeManagerService extends SystemService {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
context.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
+
+ context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE),
+ false, mDarkThemeObserver, 0);
}
// Records whether setup wizard has happened or not and adds an observer for this user if not.
@@ -417,11 +428,6 @@ final class UiModeManagerService extends SystemService {
if (!mCarModeEnabled) {
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE, mode, user);
-
- if (UserManager.get(getContext()).isPrimaryUser()) {
- SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME,
- Integer.toString(mode));
- }
}
mNightMode = mode;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 268e813c12dd..f3264e2be565 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7901,11 +7901,12 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void reportGlobalUsageEventLocked(int event) {
- mUsageStatsService.reportEvent("android", mUserController.getCurrentUserId(), event);
+ mUsageStatsService.reportEvent(Event.DEVICE_EVENT_PACKAGE_NAME,
+ mUserController.getCurrentUserId(), event);
int[] profiles = mUserController.getCurrentProfileIds();
if (profiles != null) {
for (int i = profiles.length - 1; i >= 0; i--) {
- mUsageStatsService.reportEvent((String)null, profiles[i], event);
+ mUsageStatsService.reportEvent(Event.DEVICE_EVENT_PACKAGE_NAME, profiles[i], event);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 33070dc6b757..0dd719994de2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -79,7 +79,6 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
-import android.text.format.Time;
import android.util.ArrayMap;
import android.util.DebugUtils;
import android.util.DisplayMetrics;
@@ -98,12 +97,16 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URISyntaxException;
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -116,10 +119,14 @@ import javax.microedition.khronos.egl.EGLSurface;
final class ActivityManagerShellCommand extends ShellCommand {
public static final String NO_CLASS_ERROR_CODE = "Error type 3";
+
private static final String SHELL_PACKAGE_NAME = "com.android.shell";
private static final int USER_OPERATION_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
+ private static final DateTimeFormatter LOG_NAME_TIME_FORMATTER =
+ DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss", Locale.ROOT);
+
// IPC interface to activity manager -- don't need to do additional security checks.
final IActivityManager mInterface;
final IActivityTaskManager mTaskInterface;
@@ -922,9 +929,9 @@ final class ActivityManagerShellCommand extends ShellCommand {
String process = getNextArgRequired();
String heapFile = getNextArg();
if (heapFile == null) {
- final Time t = new Time();
- t.set(System.currentTimeMillis());
- heapFile = "/data/local/tmp/heapdump-" + t.format("%Y%m%d-%H%M%S") + ".prof";
+ LocalDateTime localDateTime = LocalDateTime.now(Clock.systemDefaultZone());
+ String logNameTimeString = LOG_NAME_TIME_FORMATTER.format(localDateTime);
+ heapFile = "/data/local/tmp/heapdump-" + logNameTimeString + ".prof";
}
pw.println("File: " + heapFile);
pw.flush();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 770cb3da3362..97e529361a46 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -34,6 +34,7 @@ import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
import static android.os.Process.THREAD_GROUP_DEFAULT;
import static android.os.Process.THREAD_GROUP_RESTRICTED;
import static android.os.Process.THREAD_GROUP_TOP_APP;
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.setProcessGroup;
import static android.os.Process.setThreadPriority;
import static android.os.Process.setThreadScheduler;
@@ -1815,7 +1816,6 @@ public final class OomAdjuster {
if (app.renderThreadTid != 0) {
setThreadScheduler(app.renderThreadTid,
SCHED_OTHER, 0);
- setThreadPriority(app.renderThreadTid, -4);
}
} catch (IllegalArgumentException e) {
Slog.w(TAG,
@@ -1827,9 +1827,10 @@ public final class OomAdjuster {
} else {
// Reset priority for top app UI and render threads
setThreadPriority(app.pid, 0);
- if (app.renderThreadTid != 0) {
- setThreadPriority(app.renderThreadTid, 0);
- }
+ }
+
+ if (app.renderThreadTid != 0) {
+ setThreadPriority(app.renderThreadTid, THREAD_PRIORITY_DISPLAY);
}
}
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index bd3cd5439b32..af2f24f959b4 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -789,6 +789,23 @@ public class BiometricService extends SystemService {
return error;
}
+ @Override
+ public boolean hasEnrolledBiometrics(int userId) {
+ checkInternalPermission();
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ for (int i = 0; i < mAuthenticators.size(); i++) {
+ if (mAuthenticators.get(i).mAuthenticator.hasEnrolledTemplates(userId)) {
+ return true;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return false;
+ }
+
@Override // Binder call
public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)
throws RemoteException {
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 20eb6180832c..f3f9754bd32b 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -282,10 +282,10 @@ public abstract class BiometricServiceBase extends SystemService
public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
IBinder token, ServiceListener listener, int userId, int groupId,
byte[] cryptoToken, boolean restricted, String owner,
- final int[] disabledFeatures) {
+ final int[] disabledFeatures, int timeoutSec) {
super(context, getConstants(), daemon, halDeviceId, token, listener,
userId, groupId, cryptoToken, restricted, owner, getBiometricUtils(),
- disabledFeatures);
+ disabledFeatures, timeoutSec);
}
@Override
@@ -912,8 +912,12 @@ public abstract class BiometricServiceBase extends SystemService
}
protected void setActiveUserInternal(int userId) {
- // Do not put on handler, since it should finish before returning to caller.
- updateActiveGroup(userId, null /* clientPackage */);
+ mHandler.post(() -> {
+ if (DEBUG) {
+ Slog.d(getTag(), "setActiveUser(" + userId + ")");
+ }
+ updateActiveGroup(userId, null /* clientPackage */);
+ });
}
protected void removeInternal(RemovalClient client) {
diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
index 854528f0654d..7ebb7c059b4c 100644
--- a/services/core/java/com/android/server/biometrics/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -31,11 +31,11 @@ import java.util.Arrays;
* A class to keep track of the enrollment state for a given client.
*/
public abstract class EnrollClient extends ClientMonitor {
- private static final long MS_PER_SEC = 1000;
- private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
private final byte[] mCryptoToken;
private final BiometricUtils mBiometricUtils;
private final int[] mDisabledFeatures;
+ private final int mTimeoutSec;
+
private long mEnrollmentStartTimeMs;
public abstract boolean shouldVibrate();
@@ -44,12 +44,13 @@ public abstract class EnrollClient extends ClientMonitor {
BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
BiometricServiceBase.ServiceListener listener, int userId, int groupId,
byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils,
- final int[] disabledFeatures) {
+ final int[] disabledFeatures, int timeoutSec) {
super(context, constants, daemon, halDeviceId, token, listener, userId, groupId, restricted,
owner, 0 /* cookie */);
mBiometricUtils = utils;
mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length);
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
+ mTimeoutSec = timeoutSec;
}
@Override
@@ -94,14 +95,13 @@ public abstract class EnrollClient extends ClientMonitor {
@Override
public int start() {
mEnrollmentStartTimeMs = System.currentTimeMillis();
- final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
final ArrayList<Integer> disabledFeatures = new ArrayList<>();
for (int i = 0; i < mDisabledFeatures.length; i++) {
disabledFeatures.add(mDisabledFeatures[i]);
}
- final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), timeout,
+ final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), mTimeoutSec,
disabledFeatures);
if (result != 0) {
Slog.w(getLogTag(), "startEnroll failed, result=" + result);
diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
index 6c7cbc166241..ecf3864e3362 100644
--- a/services/core/java/com/android/server/biometrics/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
@@ -93,7 +93,7 @@ public abstract class LoggableMonitor {
statsAction(),
statsClient(),
acquiredInfo,
- 0 /* vendorCode */, // Don't log vendorCode for now
+ vendorCode,
Utils.isDebugEnabled(context, targetUserId));
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index a38abdc1bed0..a7065216f6a3 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -329,6 +329,7 @@ public class FaceService extends BiometricServiceBase {
* Receives the incoming binder calls from FaceManager.
*/
private final class FaceServiceWrapper extends IFaceService.Stub {
+ private static final int ENROLL_TIMEOUT_SEC = 75;
/**
* The following methods contain common code which is shared in biometrics/common.
@@ -343,16 +344,19 @@ public class FaceService extends BiometricServiceBase {
@Override // Binder call
public int revokeChallenge(IBinder token) {
checkPermission(MANAGE_BIOMETRIC);
- // TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks.
- if (getCurrentClient() == null) {
- // if we aren't handling any other HIDL calls (mCurrentClient == null), revoke the
- // challenge right away.
- return startRevokeChallenge(token);
- } else {
- // postpone revoking the challenge until we finish processing the current HIDL call.
- mRevokeChallengePending = true;
- return Status.OK;
- }
+ mHandler.post(() -> {
+ // TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks.
+ if (getCurrentClient() == null) {
+ // if we aren't handling any other HIDL calls (mCurrentClient == null), revoke
+ // the challenge right away.
+ startRevokeChallenge(token);
+ } else {
+ // postpone revoking the challenge until we finish processing the current HIDL
+ // call.
+ mRevokeChallengePending = true;
+ }
+ });
+ return Status.OK;
}
@Override // Binder call
@@ -368,7 +372,8 @@ public class FaceService extends BiometricServiceBase {
final boolean restricted = isRestricted();
final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId,
- 0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures) {
+ 0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures,
+ ENROLL_TIMEOUT_SEC) {
@Override
public int[] getAcquireIgnorelist() {
@@ -609,27 +614,32 @@ public class FaceService extends BiometricServiceBase {
public void resetLockout(byte[] token) {
checkPermission(MANAGE_BIOMETRIC);
- if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
- Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
- return;
- }
+ mHandler.post(() -> {
+ if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
+ Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
+ return;
+ }
- Slog.d(TAG, "Resetting lockout for user: " + mCurrentUserId);
+ Slog.d(TAG, "Resetting lockout for user: " + mCurrentUserId);
- try {
- mDaemonWrapper.resetLockout(token);
- } catch (RemoteException e) {
- Slog.e(getTag(), "Unable to reset lockout", e);
- }
+ try {
+ mDaemonWrapper.resetLockout(token);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to reset lockout", e);
+ }
+ });
}
@Override
public void setFeature(int userId, int feature, boolean enabled, final byte[] token,
IFaceServiceReceiver receiver, final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
- updateActiveGroup(userId, opPackageName);
mHandler.post(() -> {
+ if (DEBUG) {
+ Slog.d(TAG, "setFeature for user(" + userId + ")");
+ }
+ updateActiveGroup(userId, opPackageName);
if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature);
return;
@@ -660,9 +670,12 @@ public class FaceService extends BiometricServiceBase {
public void getFeature(int userId, int feature, IFaceServiceReceiver receiver,
final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
- updateActiveGroup(userId, opPackageName);
mHandler.post(() -> {
+ if (DEBUG) {
+ Slog.d(TAG, "getFeature for user(" + userId + ")");
+ }
+ updateActiveGroup(userId, opPackageName);
// This should ideally return tri-state, but the user isn't shown settings unless
// they are enrolled so it's fine for now.
if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 28336f459863..320e1022873c 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -176,6 +176,7 @@ public class FingerprintService extends BiometricServiceBase {
* Receives the incoming binder calls from FingerprintManager.
*/
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+ private static final int ENROLL_TIMEOUT_SEC = 60;
/**
* The following methods contain common code which is shared in biometrics/common.
@@ -203,7 +204,8 @@ public class FingerprintService extends BiometricServiceBase {
final int groupId = userId; // default group for fingerprint enrollment
final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
- cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */) {
+ cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */,
+ ENROLL_TIMEOUT_SEC) {
@Override
public boolean shouldVibrate() {
return true;
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 9730c9a1a380..1a1845ac3d5f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -28,7 +28,6 @@ import android.hardware.broadcastradio.V2_0.MetadataKey;
import android.hardware.broadcastradio.V2_0.ProgramFilter;
import android.hardware.broadcastradio.V2_0.ProgramIdentifier;
import android.hardware.broadcastradio.V2_0.ProgramInfo;
-import android.hardware.broadcastradio.V2_0.ProgramInfoFlags;
import android.hardware.broadcastradio.V2_0.ProgramListChunk;
import android.hardware.broadcastradio.V2_0.Properties;
import android.hardware.broadcastradio.V2_0.Result;
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
index b1bd39566ba6..8c9389101141 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
@@ -48,6 +48,10 @@ class ProgramInfoCache {
private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mProgramInfoMap =
new HashMap<>();
+ // Flag indicating whether mProgramInfoMap is considered complete based upon the received
+ // updates.
+ private boolean mComplete = true;
+
// Optional filter used in filterAndUpdateFrom(). Usually this field is null for a HAL-side
// cache and non-null for an AIDL-side cache.
private final ProgramList.Filter mFilter;
@@ -58,9 +62,10 @@ class ProgramInfoCache {
// Constructor for testing.
@VisibleForTesting
- ProgramInfoCache(@Nullable ProgramList.Filter filter,
+ ProgramInfoCache(@Nullable ProgramList.Filter filter, boolean complete,
RadioManager.ProgramInfo... programInfos) {
mFilter = filter;
+ mComplete = complete;
for (RadioManager.ProgramInfo programInfo : programInfos) {
mProgramInfoMap.put(programInfo.getSelector().getPrimaryId(), programInfo);
}
@@ -77,15 +82,23 @@ class ProgramInfoCache {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("ProgramInfoCache(");
+ StringBuilder sb = new StringBuilder("ProgramInfoCache(mComplete = ");
+ sb.append(mComplete);
+ sb.append(", mFilter = ");
+ sb.append(mFilter);
+ sb.append(", mProgramInfoMap = [");
mProgramInfoMap.forEach((id, programInfo) -> {
sb.append("\n");
sb.append(programInfo.toString());
});
- sb.append(")");
+ sb.append("]");
return sb.toString();
}
+ public boolean isComplete() {
+ return mComplete;
+ }
+
public @Nullable ProgramList.Filter getFilter() {
return mFilter;
}
@@ -102,6 +115,7 @@ class ProgramInfoCache {
for (android.hardware.broadcastradio.V2_0.ProgramIdentifier halProgramId : chunk.removed) {
mProgramInfoMap.remove(Convert.programIdentifierFromHal(halProgramId));
}
+ mComplete = chunk.complete;
}
@NonNull List<ProgramList.Chunk> filterAndUpdateFrom(@NonNull ProgramInfoCache other,
@@ -122,26 +136,18 @@ class ProgramInfoCache {
purge = true;
}
- Set<Integer> idTypes = mFilter != null ? mFilter.getIdentifierTypes() : null;
- Set<ProgramSelector.Identifier> ids = mFilter != null ? mFilter.getIdentifiers() : null;
- boolean includeCategories = mFilter != null ? mFilter.areCategoriesIncluded() : true;
- boolean includeModifications = mFilter != null ? !mFilter.areModificationsExcluded() : true;
-
Set<RadioManager.ProgramInfo> modified = new HashSet<>();
Set<ProgramSelector.Identifier> removed = new HashSet<>(mProgramInfoMap.keySet());
for (Map.Entry<ProgramSelector.Identifier, RadioManager.ProgramInfo> entry
: other.mProgramInfoMap.entrySet()) {
ProgramSelector.Identifier id = entry.getKey();
- if ((idTypes != null && !idTypes.isEmpty() && !idTypes.contains(id.getType()))
- || (ids != null && !ids.isEmpty() && !ids.contains(id))
- || (!includeCategories && id.isCategoryType())) {
+ if (!passesFilter(id)) {
continue;
}
-
removed.remove(id);
- RadioManager.ProgramInfo oldInfo = mProgramInfoMap.get(id);
+
RadioManager.ProgramInfo newInfo = entry.getValue();
- if (oldInfo != null && (!includeModifications || oldInfo.equals(newInfo))) {
+ if (!shouldIncludeInModified(newInfo)) {
continue;
}
mProgramInfoMap.put(id, newInfo);
@@ -150,14 +156,81 @@ class ProgramInfoCache {
for (ProgramSelector.Identifier rem : removed) {
mProgramInfoMap.remove(rem);
}
- return buildChunks(purge, modified, maxNumModifiedPerChunk, removed, maxNumRemovedPerChunk);
+ mComplete = other.mComplete;
+ return buildChunks(purge, mComplete, modified, maxNumModifiedPerChunk, removed,
+ maxNumRemovedPerChunk);
+ }
+
+ @Nullable List<ProgramList.Chunk> filterAndApplyChunk(@NonNull ProgramList.Chunk chunk) {
+ return filterAndApplyChunkInternal(chunk, MAX_NUM_MODIFIED_PER_CHUNK,
+ MAX_NUM_REMOVED_PER_CHUNK);
+ }
+
+ @VisibleForTesting
+ @Nullable List<ProgramList.Chunk> filterAndApplyChunkInternal(@NonNull ProgramList.Chunk chunk,
+ int maxNumModifiedPerChunk, int maxNumRemovedPerChunk) {
+ if (chunk.isPurge()) {
+ mProgramInfoMap.clear();
+ }
+
+ Set<RadioManager.ProgramInfo> modified = new HashSet<>();
+ Set<ProgramSelector.Identifier> removed = new HashSet<>();
+ for (RadioManager.ProgramInfo info : chunk.getModified()) {
+ ProgramSelector.Identifier id = info.getSelector().getPrimaryId();
+ if (!passesFilter(id) || !shouldIncludeInModified(info)) {
+ continue;
+ }
+ mProgramInfoMap.put(id, info);
+ modified.add(info);
+ }
+ for (ProgramSelector.Identifier id : chunk.getRemoved()) {
+ if (mProgramInfoMap.containsKey(id)) {
+ mProgramInfoMap.remove(id);
+ removed.add(id);
+ }
+ }
+ if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.isComplete()) {
+ return null;
+ }
+ mComplete = chunk.isComplete();
+ return buildChunks(chunk.isPurge(), mComplete, modified, maxNumModifiedPerChunk, removed,
+ maxNumRemovedPerChunk);
+ }
+
+ private boolean passesFilter(ProgramSelector.Identifier id) {
+ if (mFilter == null) {
+ return true;
+ }
+ if (!mFilter.getIdentifierTypes().isEmpty()
+ && !mFilter.getIdentifierTypes().contains(id.getType())) {
+ return false;
+ }
+ if (!mFilter.getIdentifiers().isEmpty() && !mFilter.getIdentifiers().contains(id)) {
+ return false;
+ }
+ if (!mFilter.areCategoriesIncluded() && id.isCategoryType()) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean shouldIncludeInModified(RadioManager.ProgramInfo newInfo) {
+ RadioManager.ProgramInfo oldInfo = mProgramInfoMap.get(
+ newInfo.getSelector().getPrimaryId());
+ if (oldInfo == null) {
+ return true;
+ }
+ if (mFilter != null && mFilter.areModificationsExcluded()) {
+ return false;
+ }
+ return !oldInfo.equals(newInfo);
}
private static int roundUpFraction(int numerator, int denominator) {
return (numerator / denominator) + (numerator % denominator > 0 ? 1 : 0);
}
- private @NonNull List<ProgramList.Chunk> buildChunks(boolean purge,
+ private static @NonNull List<ProgramList.Chunk> buildChunks(boolean purge, boolean complete,
@Nullable Collection<RadioManager.ProgramInfo> modified, int maxNumModifiedPerChunk,
@Nullable Collection<ProgramSelector.Identifier> removed, int maxNumRemovedPerChunk) {
// Communication protocol requires that if purge is set, removed is empty.
@@ -205,8 +278,8 @@ class ProgramInfoCache {
removedChunk.add(removedIter.next());
}
}
- chunks.add(new ProgramList.Chunk(purge && i == 0, i == numChunks - 1, modifiedChunk,
- removedChunk));
+ chunks.add(new ProgramList.Chunk(purge && i == 0, complete && (i == numChunks - 1),
+ modifiedChunk, removedChunk));
}
return chunks;
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index acb0207ff11f..53890a48a674 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -40,6 +40,7 @@ import android.util.MutableInt;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.HashSet;
@@ -64,7 +65,13 @@ class RadioModule {
private Boolean mAntennaConnected = null;
@GuardedBy("mLock")
- private RadioManager.ProgramInfo mProgramInfo = null;
+ private RadioManager.ProgramInfo mCurrentProgramInfo = null;
+
+ @GuardedBy("mLock")
+ private final ProgramInfoCache mProgramInfoCache = new ProgramInfoCache(null);
+
+ @GuardedBy("mLock")
+ private android.hardware.radio.ProgramList.Filter mUnionOfAidlProgramFilters = null;
// Callback registered with the HAL to relay callbacks to AIDL clients.
private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() {
@@ -78,17 +85,22 @@ class RadioModule {
public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo);
synchronized (mLock) {
- mProgramInfo = programInfo;
+ mCurrentProgramInfo = programInfo;
fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo));
}
}
@Override
public void onProgramListUpdated(ProgramListChunk programListChunk) {
- // TODO: Cache per-AIDL client filters, send union of filters to HAL, use filters to fan
- // back out to clients.
- fanoutAidlCallback(cb -> cb.onProgramListUpdated(Convert.programListChunkFromHal(
- programListChunk)));
+ synchronized (mLock) {
+ android.hardware.radio.ProgramList.Chunk chunk =
+ Convert.programListChunkFromHal(programListChunk);
+ mProgramInfoCache.filterAndApplyChunk(chunk);
+
+ for (TunerSession tunerSession : mAidlTunerSessions) {
+ tunerSession.onMergedProgramListUpdateFromHal(chunk);
+ }
+ }
}
@Override
@@ -109,8 +121,9 @@ class RadioModule {
@GuardedBy("mLock")
private final Set<TunerSession> mAidlTunerSessions = new HashSet<>();
- private RadioModule(@NonNull IBroadcastRadio service,
- @NonNull RadioManager.ModuleProperties properties) throws RemoteException {
+ @VisibleForTesting
+ RadioModule(@NonNull IBroadcastRadio service,
+ @NonNull RadioManager.ModuleProperties properties) {
mProperties = Objects.requireNonNull(properties);
mService = Objects.requireNonNull(service);
}
@@ -163,8 +176,8 @@ class RadioModule {
if (mAntennaConnected != null) {
userCb.onAntennaState(mAntennaConnected);
}
- if (mProgramInfo != null) {
- userCb.onCurrentProgramInfoChanged(mProgramInfo);
+ if (mCurrentProgramInfo != null) {
+ userCb.onCurrentProgramInfoChanged(mCurrentProgramInfo);
}
return tunerSession;
@@ -186,18 +199,114 @@ class RadioModule {
}
}
+ private @Nullable android.hardware.radio.ProgramList.Filter
+ buildUnionOfTunerSessionFiltersLocked() {
+ Set<Integer> idTypes = null;
+ Set<android.hardware.radio.ProgramSelector.Identifier> ids = null;
+ boolean includeCategories = false;
+ boolean excludeModifications = true;
+
+ for (TunerSession tunerSession : mAidlTunerSessions) {
+ android.hardware.radio.ProgramList.Filter filter =
+ tunerSession.getProgramListFilter();
+ if (filter == null) {
+ continue;
+ }
+
+ if (idTypes == null) {
+ idTypes = new HashSet<>(filter.getIdentifierTypes());
+ ids = new HashSet<>(filter.getIdentifiers());
+ includeCategories = filter.areCategoriesIncluded();
+ excludeModifications = filter.areModificationsExcluded();
+ continue;
+ }
+ if (!idTypes.isEmpty()) {
+ if (filter.getIdentifierTypes().isEmpty()) {
+ idTypes.clear();
+ } else {
+ idTypes.addAll(filter.getIdentifierTypes());
+ }
+ }
+
+ if (!ids.isEmpty()) {
+ if (filter.getIdentifiers().isEmpty()) {
+ ids.clear();
+ } else {
+ ids.addAll(filter.getIdentifiers());
+ }
+ }
+
+ includeCategories |= filter.areCategoriesIncluded();
+ excludeModifications &= filter.areModificationsExcluded();
+ }
+
+ return idTypes == null ? null : new android.hardware.radio.ProgramList.Filter(idTypes, ids,
+ includeCategories, excludeModifications);
+ }
+
+ void onTunerSessionProgramListFilterChanged(@Nullable TunerSession session) {
+ synchronized (mLock) {
+ onTunerSessionProgramListFilterChangedLocked(session);
+ }
+ }
+
+ private void onTunerSessionProgramListFilterChangedLocked(@Nullable TunerSession session) {
+ android.hardware.radio.ProgramList.Filter newFilter =
+ buildUnionOfTunerSessionFiltersLocked();
+ if (newFilter == null) {
+ // If there are no AIDL clients remaining, we can stop updates from the HAL as well.
+ if (mUnionOfAidlProgramFilters == null) {
+ return;
+ }
+ mUnionOfAidlProgramFilters = null;
+ try {
+ mHalTunerSession.stopProgramListUpdates();
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "mHalTunerSession.stopProgramListUpdates() failed: ", ex);
+ }
+ return;
+ }
+
+ // If the HAL filter doesn't change, we can immediately send an update to the AIDL
+ // client.
+ if (newFilter.equals(mUnionOfAidlProgramFilters)) {
+ if (session != null) {
+ session.updateProgramInfoFromHalCache(mProgramInfoCache);
+ }
+ return;
+ }
+
+ // Otherwise, update the HAL's filter, and AIDL clients will be updated when
+ // mHalTunerCallback.onProgramListUpdated() is called.
+ mUnionOfAidlProgramFilters = newFilter;
+ try {
+ int halResult = mHalTunerSession.startProgramListUpdates(Convert.programFilterToHal(
+ newFilter));
+ Convert.throwOnError("startProgramListUpdates", halResult);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "mHalTunerSession.startProgramListUpdates() failed: ", ex);
+ }
+ }
+
void onTunerSessionClosed(TunerSession tunerSession) {
synchronized (mLock) {
+ onTunerSessionsClosedLocked(tunerSession);
+ }
+ }
+
+ private void onTunerSessionsClosedLocked(TunerSession... tunerSessions) {
+ for (TunerSession tunerSession : tunerSessions) {
mAidlTunerSessions.remove(tunerSession);
- if (mAidlTunerSessions.isEmpty() && mHalTunerSession != null) {
- Slog.v(TAG, "closing HAL tuner session");
- try {
- mHalTunerSession.close();
- } catch (RemoteException ex) {
- Slog.e(TAG, "mHalTunerSession.close() failed: ", ex);
- }
- mHalTunerSession = null;
+ }
+ onTunerSessionProgramListFilterChanged(null);
+ if (mAidlTunerSessions.isEmpty() && mHalTunerSession != null) {
+ Slog.v(TAG, "closing HAL tuner session");
+ try {
+ mHalTunerSession.close();
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "mHalTunerSession.close() failed: ", ex);
}
+ mHalTunerSession = null;
}
}
@@ -213,18 +322,25 @@ class RadioModule {
}
private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
+ List<TunerSession> deadSessions = null;
for (TunerSession tunerSession : mAidlTunerSessions) {
try {
runnable.run(tunerSession.mCallback);
} catch (DeadObjectException ex) {
- // The other side died without calling close(), so just purge it from our
- // records.
+ // The other side died without calling close(), so just purge it from our records.
Slog.e(TAG, "Removing dead TunerSession");
- mAidlTunerSessions.remove(tunerSession);
+ if (deadSessions == null) {
+ deadSessions = new ArrayList<>();
+ }
+ deadSessions.add(tunerSession);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to invoke ITunerCallback: ", ex);
}
}
+ if (deadSessions != null) {
+ onTunerSessionsClosedLocked(deadSessions.toArray(
+ new TunerSession[deadSessions.size()]));
+ }
}
public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 008fea5831ad..764fca9a66b2 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -46,6 +46,7 @@ class TunerSession extends ITuner.Stub {
final android.hardware.radio.ITunerCallback mCallback;
private boolean mIsClosed = false;
private boolean mIsMuted = false;
+ private ProgramInfoCache mProgramInfoCache = null;
// necessary only for older APIs compatibility
private RadioManager.BandConfig mDummyConfig = null;
@@ -187,8 +188,51 @@ class TunerSession extends ITuner.Stub {
public void startProgramListUpdates(ProgramList.Filter filter) throws RemoteException {
synchronized (mLock) {
checkNotClosedLocked();
- int halResult = mHwSession.startProgramListUpdates(Convert.programFilterToHal(filter));
- Convert.throwOnError("startProgramListUpdates", halResult);
+ mProgramInfoCache = new ProgramInfoCache(filter);
+ }
+ // Note: RadioModule.onTunerSessionProgramListFilterChanged() must be called without mLock
+ // held since it can call getProgramListFilter() and onHalProgramInfoUpdated().
+ mModule.onTunerSessionProgramListFilterChanged(this);
+ }
+
+ ProgramList.Filter getProgramListFilter() {
+ synchronized (mLock) {
+ return mProgramInfoCache == null ? null : mProgramInfoCache.getFilter();
+ }
+ }
+
+ void onMergedProgramListUpdateFromHal(ProgramList.Chunk mergedChunk) {
+ List<ProgramList.Chunk> clientUpdateChunks = null;
+ synchronized (mLock) {
+ if (mProgramInfoCache == null) {
+ return;
+ }
+ clientUpdateChunks = mProgramInfoCache.filterAndApplyChunk(mergedChunk);
+ }
+ dispatchClientUpdateChunks(clientUpdateChunks);
+ }
+
+ void updateProgramInfoFromHalCache(ProgramInfoCache halCache) {
+ List<ProgramList.Chunk> clientUpdateChunks = null;
+ synchronized (mLock) {
+ if (mProgramInfoCache == null) {
+ return;
+ }
+ clientUpdateChunks = mProgramInfoCache.filterAndUpdateFrom(halCache, true);
+ }
+ dispatchClientUpdateChunks(clientUpdateChunks);
+ }
+
+ private void dispatchClientUpdateChunks(@Nullable List<ProgramList.Chunk> chunks) {
+ if (chunks == null) {
+ return;
+ }
+ for (ProgramList.Chunk chunk : chunks) {
+ try {
+ mCallback.onProgramListUpdated(chunk);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "mCallback.onProgramListUpdated() failed: ", ex);
+ }
}
}
@@ -196,8 +240,11 @@ class TunerSession extends ITuner.Stub {
public void stopProgramListUpdates() throws RemoteException {
synchronized (mLock) {
checkNotClosedLocked();
- mHwSession.stopProgramListUpdates();
+ mProgramInfoCache = null;
}
+ // Note: RadioModule.onTunerSessionProgramListFilterChanged() must be called without mLock
+ // held since it can call getProgramListFilter() and onHalProgramInfoUpdated().
+ mModule.onTunerSessionProgramListFilterChanged(this);
}
@Override
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 2a866f390283..6f32beea66d3 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -20,6 +20,8 @@ import android.annotation.Nullable;
import android.compat.annotation.EnabledAfter;
import android.content.pm.ApplicationInfo;
+import com.android.server.compat.config.Change;
+
import java.util.HashMap;
import java.util.Map;
@@ -60,6 +62,16 @@ public final class CompatChange {
mDisabled = disabled;
}
+ /**
+ * @param change an object generated by services/core/xsd/platform-compat-config.xsd
+ */
+ public CompatChange(Change change) {
+ mChangeId = change.getId();
+ mName = change.getName();
+ mEnableAfterTargetSdk = change.getEnableAfterTargetSdk();
+ mDisabled = change.getDisabled();
+ }
+
long getId() {
return mChangeId;
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index bcf1d80781a6..044e41789bb2 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -17,13 +17,27 @@
package com.android.server.compat;
import android.content.pm.ApplicationInfo;
+import android.os.Environment;
import android.text.TextUtils;
import android.util.LongArray;
import android.util.LongSparseArray;
+import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.compat.config.Change;
+import com.android.server.compat.config.XmlParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+
+import javax.xml.datatype.DatatypeConfigurationException;
/**
* This class maintains state relating to platform compatibility changes.
*
@@ -32,7 +46,12 @@ import com.android.internal.annotations.VisibleForTesting;
*/
public final class CompatConfig {
- private static final CompatConfig sInstance = new CompatConfig();
+ private static final String TAG = "CompatConfig";
+ private static final String CONFIG_FILE_SUFFIX = "platform_compat_config.xml";
+
+ private static final CompatConfig sInstance = new CompatConfig().initConfigFromLib(
+ Environment.buildPath(
+ Environment.getRootDirectory(), "etc", "sysconfig"));
@GuardedBy("mChanges")
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
@@ -169,4 +188,47 @@ public final class CompatConfig {
return overrideExists;
}
+ /**
+ * Dumps the current list of compatibility config information.
+ *
+ * @param pw The {@link PrintWriter} instance to which the information will be dumped.
+ */
+ public void dumpConfig(PrintWriter pw) {
+ synchronized (mChanges) {
+ if (mChanges.size() == 0) {
+ pw.println("No compat overrides.");
+ return;
+ }
+ for (int i = 0; i < mChanges.size(); ++i) {
+ CompatChange c = mChanges.valueAt(i);
+ pw.println(c.toString());
+ }
+ }
+ }
+
+ CompatConfig initConfigFromLib(File libraryDir) {
+ if (!libraryDir.exists() || !libraryDir.isDirectory()) {
+ Slog.e(TAG, "No directory " + libraryDir + ", skipping");
+ return this;
+ }
+ for (File f : libraryDir.listFiles()) {
+ //TODO(b/138222363): Handle duplicate ids across config files.
+ if (f.getPath().endsWith(CONFIG_FILE_SUFFIX)) {
+ readConfig(f);
+ }
+ }
+ return this;
+ }
+
+ private void readConfig(File configFile) {
+ try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
+ for (Change change : XmlParser.read(in).getCompatChange()) {
+ Slog.w(TAG, "Adding: " + change.toString());
+ addChange(new CompatChange(change));
+ }
+ } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
+ Slog.e(TAG, "Encountered an error while reading/parsing compat config file", e);
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/compat/IPlatformCompat.aidl b/services/core/java/com/android/server/compat/IPlatformCompat.aidl
new file mode 100644
index 000000000000..8ab08f9047cb
--- /dev/null
+++ b/services/core/java/com/android/server/compat/IPlatformCompat.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 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.compat;
+
+import android.content.pm.ApplicationInfo;
+
+/**
+ * System private API for talking with the PlatformCompat service.
+ * {@hide}
+ */
+interface IPlatformCompat
+{
+
+ /**
+ * Reports that a compatibility change is affecting an app process now.
+ *
+ * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
+ * you do not need to call this API directly. The change will be reported for you in the case
+ * that {@link #isChangeEnabled(long, ApplicationInfo)} returns {@code true}.
+ *
+ * @param changeId The ID of the compatibility change taking effect.
+ * @param appInfo Representing the affected app.
+ */
+ void reportChange(long changeId, in ApplicationInfo appInfo);
+
+ /**
+ * Query if a given compatibility change is enabled for an app process. This method should
+ * be called when implementing functionality on behalf of the affected app.
+ *
+ * <p>If this method returns {@code true}, the calling code should implement the compatibility
+ * change, resulting in differing behaviour compared to earlier releases. If this method returns
+ * {@code false}, the calling code should behave as it did in earlier releases.
+ *
+ * <p>When this method returns {@code true}, it will also report the change as
+ * {@link #reportChange(long, ApplicationInfo)} would, so there is no need to call that method
+ * directly.
+ *
+ * @param changeId The ID of the compatibility change in question.
+ * @param appInfo Representing the app in question.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ boolean isChangeEnabled(long changeId, in ApplicationInfo appInfo);
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 456d15e4fba8..3eea194fd73e 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -16,52 +16,46 @@
package com.android.server.compat;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.Slog;
+import com.android.internal.util.DumpUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* System server internal API for gating and reporting compatibility changes.
*/
-public class PlatformCompat {
+public class PlatformCompat extends IPlatformCompat.Stub {
private static final String TAG = "Compatibility";
- /**
- * Reports that a compatibility change is affecting an app process now.
- *
- * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
- * you do not need to call this API directly. The change will be reported for you in the case
- * that {@link #isChangeEnabled(long, ApplicationInfo)} returns {@code true}.
- *
- * @param changeId The ID of the compatibility change taking effect.
- * @param appInfo Representing the affected app.
- */
- public static void reportChange(long changeId, ApplicationInfo appInfo) {
+ private final Context mContext;
+
+ public PlatformCompat(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void reportChange(long changeId, ApplicationInfo appInfo) {
Slog.d(TAG, "Compat change reported: " + changeId + "; UID " + appInfo.uid);
// TODO log via StatsLog
}
- /**
- * Query if a given compatibility change is enabled for an app process. This method should
- * be called when implementing functionality on behalf of the affected app.
- *
- * <p>If this method returns {@code true}, the calling code should implement the compatibility
- * change, resulting in differing behaviour compared to earlier releases. If this method returns
- * {@code false}, the calling code should behave as it did in earlier releases.
- *
- * <p>When this method returns {@code true}, it will also report the change as
- * {@link #reportChange(long, ApplicationInfo)} would, so there is no need to call that method
- * directly.
- *
- * @param changeId The ID of the compatibility change in question.
- * @param appInfo Representing the app in question.
- * @return {@code true} if the change is enabled for the current app.
- */
- public static boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
+ @Override
+ public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
reportChange(changeId, appInfo);
return true;
}
return false;
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
+ CompatConfig.get().dumpConfig(pw);
+ }
}
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 7be1b8a3d371..c46fc20b3cc8 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -29,6 +29,7 @@ import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.os.IBinder;
import android.util.Slog;
+import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
@@ -72,6 +73,9 @@ final class ColorFade {
// See code for details.
private static final int DEJANK_FRAMES = 3;
+ private static final int EGL_GL_COLORSPACE_KHR = 0x309D;
+ private static final int EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT = 0x3490;
+
private final int mDisplayId;
// Set to true when the animation context has been fully prepared.
@@ -93,6 +97,7 @@ final class ColorFade {
private EGLSurface mEglSurface;
private boolean mSurfaceVisible;
private float mSurfaceAlpha;
+ private boolean mIsWideColor;
// Texture names. We only use one texture, which contains the screenshot.
private final int[] mTexNames = new int[1];
@@ -482,6 +487,8 @@ final class ColorFade {
return false;
}
+ mIsWideColor = SurfaceControl.getActiveColorMode(token)
+ == Display.COLOR_MODE_DISPLAY_P3;
SurfaceControl.screenshot(token, s);
st.updateTexImage();
st.getTransformMatrix(mTexMatrix);
@@ -608,8 +615,16 @@ final class ColorFade {
private boolean createEglSurface() {
if (mEglSurface == null) {
int[] eglSurfaceAttribList = new int[] {
+ EGL14.EGL_NONE,
+ EGL14.EGL_NONE,
EGL14.EGL_NONE
};
+
+ // If the current display is in wide color, then so is the screenshot.
+ if (mIsWideColor) {
+ eglSurfaceAttribList[0] = EGL_GL_COLORSPACE_KHR;
+ eglSurfaceAttribList[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
+ }
// turn our SurfaceControl into a Surface
mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
eglSurfaceAttribList, 0);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index 2c0cacdd26e5..52cede2121bd 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -290,8 +290,7 @@ final class HdmiCecKeycode {
new KeycodeEntry(KeyEvent.KEYCODE_CHANNEL_UP, CEC_KEYCODE_CHANNEL_UP),
new KeycodeEntry(KeyEvent.KEYCODE_CHANNEL_DOWN, CEC_KEYCODE_CHANNEL_DOWN),
new KeycodeEntry(KeyEvent.KEYCODE_LAST_CHANNEL, CEC_KEYCODE_PREVIOUS_CHANNEL),
- // No Android keycode defined for CEC_KEYCODE_SOUND_SELECT
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SOUND_SELECT),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK, CEC_KEYCODE_SOUND_SELECT),
new KeycodeEntry(KeyEvent.KEYCODE_TV_INPUT, CEC_KEYCODE_INPUT_SELECT),
new KeycodeEntry(KeyEvent.KEYCODE_INFO, CEC_KEYCODE_DISPLAY_INFORMATION),
// No Android keycode defined for CEC_KEYCODE_HELP
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 6911b7c8f565..461f19bf8b08 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1608,13 +1608,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
mHandler.post(() -> {
setupNativeGnssService(/* reinitializeGnssServiceHandle = */ true);
+ // resend configuration into the restarted HAL service.
+ reloadGpsProperties();
if (isGpsEnabled()) {
setGpsEnabled(false);
-
updateEnabled();
-
- // resend configuration into the restarted HAL service.
- reloadGpsProperties();
}
});
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 433ce811c8d7..9510db09aa25 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -446,7 +446,7 @@ public class LockSettingsService extends ILockSettings.Stub {
public boolean hasEnrolledBiometrics(int userId) {
BiometricManager bm = mContext.getSystemService(BiometricManager.class);
- return bm.canAuthenticate(userId) == BiometricManager.BIOMETRIC_SUCCESS;
+ return bm.hasEnrolledBiometrics(userId);
}
public int binderGetCallingUid() {
diff --git a/services/core/java/com/android/server/locksettings/TEST_MAPPING b/services/core/java/com/android/server/locksettings/TEST_MAPPING
new file mode 100644
index 000000000000..c1cba5f7f22d
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsDevicePolicyManagerTestCases",
+ "options": [
+ {
+ "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index c54bfc01e031..0ad6c2a69556 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -19,6 +19,7 @@ package com.android.server.locksettings.recoverablekeystore;
import android.app.KeyguardManager;
import android.content.Context;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.security.GateKeeper;
import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyPermanentlyInvalidatedException;
@@ -437,25 +438,31 @@ public class PlatformKeyManager {
// so it may live in memory for some time.
SecretKey secretKey = generateAesKey();
- long secureUserId = getGateKeeperService().getSecureUserId(userId);
- // TODO(b/124095438): Propagate this failure instead of silently failing.
- if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
- Log.e(TAG, "No SID available for user " + userId);
- return;
- }
-
- // Store decryption key first since it is more likely to fail.
- mKeyStore.setEntry(
- decryptAlias,
- new KeyStore.SecretKeyEntry(secretKey),
+ KeyProtection.Builder decryptionKeyProtection =
new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(
USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
+ if (userId != UserHandle.USER_SYSTEM) {
+ // Bind decryption key to secondary profile lock screen secret.
+ long secureUserId = getGateKeeperService().getSecureUserId(userId);
+ // TODO(b/124095438): Propagate this failure instead of silently failing.
+ if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
+ Log.e(TAG, "No SID available for user " + userId);
+ return;
+ }
+ decryptionKeyProtection
.setBoundToSpecificSecureUserId(secureUserId)
- .build());
+ // Ignore caller uid which always belongs to the primary profile.
+ .setCriticalToDeviceEncryption(true);
+ }
+ // Store decryption key first since it is more likely to fail.
+ mKeyStore.setEntry(
+ decryptAlias,
+ new KeyStore.SecretKeyEntry(secretKey),
+ decryptionKeyProtection.build());
mKeyStore.setEntry(
encryptAlias,
new KeyStore.SecretKeyEntry(secretKey),
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 4a6eb276bd02..4828bbfff676 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -196,18 +196,20 @@ abstract public class ManagedServices {
public void dump(PrintWriter pw, DumpFilter filter) {
pw.println(" Allowed " + getCaption() + "s:");
- final int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int userId = mApproved.keyAt(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- if (approvedByType != null) {
- final int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final boolean isPrimary = approvedByType.keyAt(j);
- final ArraySet<String> approved = approvedByType.valueAt(j);
- if (approvedByType != null && approvedByType.size() > 0) {
- pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
- + " (user: " + userId + " isPrimary: " + isPrimary + ")");
+ synchronized (mApproved) {
+ final int N = mApproved.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = mApproved.keyAt(i);
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+ if (approvedByType != null) {
+ final int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final boolean isPrimary = approvedByType.keyAt(j);
+ final ArraySet<String> approved = approvedByType.valueAt(j);
+ if (approvedByType != null && approvedByType.size() > 0) {
+ pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
+ + " (user: " + userId + " isPrimary: " + isPrimary + ")");
+ }
}
}
}
@@ -240,23 +242,25 @@ abstract public class ManagedServices {
public void dump(ProtoOutputStream proto, DumpFilter filter) {
proto.write(ManagedServicesProto.CAPTION, getCaption());
- final int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int userId = mApproved.keyAt(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- if (approvedByType != null) {
- final int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final boolean isPrimary = approvedByType.keyAt(j);
- final ArraySet<String> approved = approvedByType.valueAt(j);
- if (approvedByType != null && approvedByType.size() > 0) {
- final long sToken = proto.start(ManagedServicesProto.APPROVED);
- for (String s : approved) {
- proto.write(ServiceProto.NAME, s);
+ synchronized (mApproved) {
+ final int N = mApproved.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = mApproved.keyAt(i);
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+ if (approvedByType != null) {
+ final int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final boolean isPrimary = approvedByType.keyAt(j);
+ final ArraySet<String> approved = approvedByType.valueAt(j);
+ if (approvedByType != null && approvedByType.size() > 0) {
+ final long sToken = proto.start(ManagedServicesProto.APPROVED);
+ for (String s : approved) {
+ proto.write(ServiceProto.NAME, s);
+ }
+ proto.write(ServiceProto.USER_ID, userId);
+ proto.write(ServiceProto.IS_PRIMARY, isPrimary);
+ proto.end(sToken);
}
- proto.write(ServiceProto.USER_ID, userId);
- proto.write(ServiceProto.IS_PRIMARY, isPrimary);
- proto.end(sToken);
}
}
}
@@ -315,33 +319,36 @@ abstract public class ManagedServices {
trimApprovedListsAccordingToInstalledServices(userId);
}
- final int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int approvedUserId = mApproved.keyAt(i);
- if (forBackup && approvedUserId != userId) {
- continue;
- }
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- if (approvedByType != null) {
- final int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final boolean isPrimary = approvedByType.keyAt(j);
- final Set<String> approved = approvedByType.valueAt(j);
- if (approved != null) {
- String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
- out.startTag(null, TAG_MANAGED_SERVICES);
- out.attribute(null, ATT_APPROVED_LIST, allowedItems);
- out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
- out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
- writeExtraAttributes(out, approvedUserId);
- out.endTag(null, TAG_MANAGED_SERVICES);
-
- if (!forBackup && isPrimary) {
- // Also write values to settings, for observers who haven't migrated yet
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- getConfig().secureSettingName, allowedItems, approvedUserId);
- }
+ synchronized (mApproved) {
+ final int N = mApproved.size();
+ for (int i = 0; i < N; i++) {
+ final int approvedUserId = mApproved.keyAt(i);
+ if (forBackup && approvedUserId != userId) {
+ continue;
+ }
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+ if (approvedByType != null) {
+ final int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final boolean isPrimary = approvedByType.keyAt(j);
+ final Set<String> approved = approvedByType.valueAt(j);
+ if (approved != null) {
+ String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ out.startTag(null, TAG_MANAGED_SERVICES);
+ out.attribute(null, ATT_APPROVED_LIST, allowedItems);
+ out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
+ out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
+ writeExtraAttributes(out, approvedUserId);
+ out.endTag(null, TAG_MANAGED_SERVICES);
+
+ if (!forBackup && isPrimary) {
+ // Also write values to settings, for observers who haven't migrated yet
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ getConfig().secureSettingName, allowedItems,
+ approvedUserId);
+ }
+ }
}
}
}
@@ -440,23 +447,25 @@ abstract public class ManagedServices {
if (TextUtils.isEmpty(approved)) {
approved = "";
}
- ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
- if (approvedByType == null) {
- approvedByType = new ArrayMap<>();
- mApproved.put(userId, approvedByType);
- }
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ approvedByType = new ArrayMap<>();
+ mApproved.put(userId, approvedByType);
+ }
- ArraySet<String> approvedList = approvedByType.get(isPrimary);
- if (approvedList == null) {
- approvedList = new ArraySet<>();
- approvedByType.put(isPrimary, approvedList);
- }
+ ArraySet<String> approvedList = approvedByType.get(isPrimary);
+ if (approvedList == null) {
+ approvedList = new ArraySet<>();
+ approvedByType.put(isPrimary, approvedList);
+ }
- String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
- for (String pkgOrComponent : approvedArray) {
- String approvedItem = getApprovedValue(pkgOrComponent);
- if (approvedItem != null) {
- approvedList.add(approvedItem);
+ String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
+ for (String pkgOrComponent : approvedArray) {
+ String approvedItem = getApprovedValue(pkgOrComponent);
+ if (approvedItem != null) {
+ approvedList.add(approvedItem);
+ }
}
}
}
@@ -469,23 +478,25 @@ abstract public class ManagedServices {
boolean isPrimary, boolean enabled) {
Slog.i(TAG,
(enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
- ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
- if (allowedByType == null) {
- allowedByType = new ArrayMap<>();
- mApproved.put(userId, allowedByType);
- }
- ArraySet<String> approved = allowedByType.get(isPrimary);
- if (approved == null) {
- approved = new ArraySet<>();
- allowedByType.put(isPrimary, approved);
- }
- String approvedItem = getApprovedValue(pkgOrComponent);
-
- if (approvedItem != null) {
- if (enabled) {
- approved.add(approvedItem);
- } else {
- approved.remove(approvedItem);
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
+ if (allowedByType == null) {
+ allowedByType = new ArrayMap<>();
+ mApproved.put(userId, allowedByType);
+ }
+ ArraySet<String> approved = allowedByType.get(isPrimary);
+ if (approved == null) {
+ approved = new ArraySet<>();
+ allowedByType.put(isPrimary, approved);
+ }
+ String approvedItem = getApprovedValue(pkgOrComponent);
+
+ if (approvedItem != null) {
+ if (enabled) {
+ approved.add(approvedItem);
+ } else {
+ approved.remove(approvedItem);
+ }
}
}
@@ -504,22 +515,26 @@ abstract public class ManagedServices {
}
protected String getApproved(int userId, boolean primary) {
- final ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
- return String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
+ return String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ }
}
protected List<ComponentName> getAllowedComponents(int userId) {
final List<ComponentName> allowedComponents = new ArrayList<>();
- final ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- final ArraySet<String> allowed = allowedByType.valueAt(i);
- for (int j = 0; j < allowed.size(); j++) {
- ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
- if (cn != null) {
- allowedComponents.add(cn);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
+ if (cn != null) {
+ allowedComponents.add(cn);
+ }
}
}
}
@@ -528,14 +543,16 @@ abstract public class ManagedServices {
protected List<String> getAllowedPackages(int userId) {
final List<String> allowedPackages = new ArrayList<>();
- final ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- final ArraySet<String> allowed = allowedByType.valueAt(i);
- for (int j = 0; j < allowed.size(); j++) {
- String pkgName = getPackageName(allowed.valueAt(j));
- if (!TextUtils.isEmpty(pkgName)) {
- allowedPackages.add(pkgName);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ String pkgName = getPackageName(allowed.valueAt(j));
+ if (!TextUtils.isEmpty(pkgName)) {
+ allowedPackages.add(pkgName);
+ }
}
}
}
@@ -543,12 +560,14 @@ abstract public class ManagedServices {
}
protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
- ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- ArraySet<String> allowed = allowedByType.valueAt(i);
- if (allowed.contains(pkgOrComponent)) {
- return true;
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ ArraySet<String> allowed = allowedByType.valueAt(i);
+ if (allowed.contains(pkgOrComponent)) {
+ return true;
+ }
}
}
return false;
@@ -558,19 +577,21 @@ abstract public class ManagedServices {
if (pkg == null) {
return false;
}
- ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- ArraySet<String> allowed = allowedByType.valueAt(i);
- for (String allowedEntry : allowed) {
- ComponentName component = ComponentName.unflattenFromString(allowedEntry);
- if (component != null) {
- if (pkg.equals(component.getPackageName())) {
- return true;
- }
- } else {
- if (pkg.equals(allowedEntry)) {
- return true;
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (String allowedEntry : allowed) {
+ ComponentName component = ComponentName.unflattenFromString(allowedEntry);
+ if (component != null) {
+ if (pkg.equals(component.getPackageName())) {
+ return true;
+ }
+ } else {
+ if (pkg.equals(allowedEntry)) {
+ return true;
+ }
}
}
}
@@ -616,7 +637,9 @@ abstract public class ManagedServices {
public void onUserRemoved(int user) {
Slog.i(TAG, "Removing approved services for removed user " + user);
- mApproved.remove(user);
+ synchronized (mApproved) {
+ mApproved.remove(user);
+ }
rebindServices(true, user);
}
@@ -797,14 +820,16 @@ abstract public class ManagedServices {
protected Set<String> getAllowedPackages() {
final Set<String> allowedPackages = new ArraySet<>();
- for (int k = 0; k < mApproved.size(); k++) {
- ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
- for (int i = 0; i < allowedByType.size(); i++) {
- final ArraySet<String> allowed = allowedByType.valueAt(i);
- for (int j = 0; j < allowed.size(); j++) {
- String pkgName = getPackageName(allowed.valueAt(j));
- if (!TextUtils.isEmpty(pkgName)) {
- allowedPackages.add(pkgName);
+ synchronized (mApproved) {
+ for (int k = 0; k < mApproved.size(); k++) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ String pkgName = getPackageName(allowed.valueAt(j));
+ if (!TextUtils.isEmpty(pkgName)) {
+ allowedPackages.add(pkgName);
+ }
}
}
}
@@ -813,22 +838,24 @@ abstract public class ManagedServices {
}
private void trimApprovedListsAccordingToInstalledServices(int userId) {
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
- if (approvedByType == null) {
- return;
- }
- for (int i = 0; i < approvedByType.size(); i++) {
- final ArraySet<String> approved = approvedByType.valueAt(i);
- for (int j = approved.size() - 1; j >= 0; j--) {
- final String approvedPackageOrComponent = approved.valueAt(j);
- if (!isValidEntry(approvedPackageOrComponent, userId)){
- approved.removeAt(j);
- Slog.v(TAG, "Removing " + approvedPackageOrComponent
- + " from approved list; no matching services found");
- } else {
- if (DEBUG) {
- Slog.v(TAG, "Keeping " + approvedPackageOrComponent
- + " on approved list; matching services found");
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ return;
+ }
+ for (int i = 0; i < approvedByType.size(); i++) {
+ final ArraySet<String> approved = approvedByType.valueAt(i);
+ for (int j = approved.size() - 1; j >= 0; j--) {
+ final String approvedPackageOrComponent = approved.valueAt(j);
+ if (!isValidEntry(approvedPackageOrComponent, userId)) {
+ approved.removeAt(j);
+ Slog.v(TAG, "Removing " + approvedPackageOrComponent
+ + " from approved list; no matching services found");
+ } else {
+ if (DEBUG) {
+ Slog.v(TAG, "Keeping " + approvedPackageOrComponent
+ + " on approved list; matching services found");
+ }
}
}
}
@@ -837,20 +864,23 @@ abstract public class ManagedServices {
private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
boolean removed = false;
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId);
- if (approvedByType != null) {
- int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final ArraySet<String> approved = approvedByType.valueAt(j);
- int O = approved.size();
- for (int k = O - 1; k >= 0; k--) {
- final String packageOrComponent = approved.valueAt(k);
- final String packageName = getPackageName(packageOrComponent);
- if (TextUtils.equals(pkg, packageName)) {
- approved.removeAt(k);
- if (DEBUG) {
- Slog.v(TAG, "Removing " + packageOrComponent
- + " from approved list; uninstalled");
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(
+ uninstalledUserId);
+ if (approvedByType != null) {
+ int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final ArraySet<String> approved = approvedByType.valueAt(j);
+ int O = approved.size();
+ for (int k = O - 1; k >= 0; k--) {
+ final String packageOrComponent = approved.valueAt(k);
+ final String packageName = getPackageName(packageOrComponent);
+ if (TextUtils.equals(pkg, packageName)) {
+ approved.removeAt(k);
+ if (DEBUG) {
+ Slog.v(TAG, "Removing " + packageOrComponent
+ + " from approved list; uninstalled");
+ }
}
}
}
@@ -887,17 +917,19 @@ abstract public class ManagedServices {
for (int i = 0; i < nUserIds; ++i) {
final int userId = userIds.get(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
- if (approvedLists != null) {
- final int N = approvedLists.size();
- for (int j = 0; j < N; j++) {
- ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
- if (approvedByUser == null) {
- approvedByUser = new ArraySet<>();
- componentsByUser.put(userId, approvedByUser);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
+ if (approvedLists != null) {
+ final int N = approvedLists.size();
+ for (int j = 0; j < N; j++) {
+ ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
+ if (approvedByUser == null) {
+ approvedByUser = new ArraySet<>();
+ componentsByUser.put(userId, approvedByUser);
+ }
+ approvedByUser.addAll(
+ loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
}
- approvedByUser.addAll(
- loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d30895efbdc3..217c0bdceede 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -473,6 +473,8 @@ public class NotificationManagerService extends SystemService {
private MetricsLogger mMetricsLogger;
private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
+ private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable();
+
private static class Archive {
final int mBufferSize;
final ArrayDeque<StatusBarNotification> mBuffer;
@@ -666,7 +668,14 @@ public class NotificationManagerService extends SystemService {
@VisibleForTesting
protected void handleSavePolicyFile() {
- IoThread.getHandler().post(() -> {
+ if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) {
+ IoThread.getHandler().post(mSavePolicyFile);
+ }
+ }
+
+ private final class SavePolicyFileRunnable implements Runnable {
+ @Override
+ public void run() {
if (DBG) Slog.d(TAG, "handleSavePolicyFile");
synchronized (mPolicyFile) {
final FileOutputStream stream;
@@ -686,7 +695,7 @@ public class NotificationManagerService extends SystemService {
}
}
BackupManager.dataChanged(getContext().getPackageName());
- });
+ }
}
private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
@@ -1845,6 +1854,7 @@ public class NotificationManagerService extends SystemService {
}
if (properties.getKeyset()
.contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
+ mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE);
mAssistants.resetDefaultAssistantsIfNecessary();
}
});
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 6f28675d051b..934511bf88d1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -296,22 +296,12 @@ final class OverlayManagerServiceImpl {
*/
private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName,
final int userId, final int flags) {
- final List<OverlayInfo> ois = new ArrayList<>();
-
- // Framework overlays added first because order matters when resolving a resource
- if (!"android".equals(targetPackageName)) {
- ois.addAll(mSettings.getOverlaysForTarget("android", userId));
- }
-
- // Then add the targeted, non-framework overlays which have higher priority
- ois.addAll(mSettings.getOverlaysForTarget(targetPackageName, userId));
-
- final List<String> enabledBaseCodePaths = new ArrayList<>(ois.size());
+ final List<OverlayInfo> targetOverlays = mSettings.getOverlaysForTarget(targetPackageName,
+ userId);
+ // Update the state for any overlay that targets this package.
boolean modified = false;
- final int n = ois.size();
- for (int i = 0; i < n; i++) {
- final OverlayInfo oi = ois.get(i);
+ for (final OverlayInfo oi : targetOverlays) {
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName,
userId);
if (overlayPackage == null) {
@@ -324,25 +314,39 @@ final class OverlayManagerServiceImpl {
Slog.e(TAG, "failed to update settings", e);
modified |= mSettings.remove(oi.packageName, userId);
}
-
- if (oi.isEnabled() && overlayPackage.applicationInfo != null) {
- enabledBaseCodePaths.add(overlayPackage.applicationInfo.getBaseCodePath());
- }
}
}
if (!modified) {
+ // Update the overlay paths of the target within package manager if necessary.
+ final List<String> enabledOverlayPaths = new ArrayList<>(targetOverlays.size());
+
+ // Framework overlays are first in the overlay paths of a package within PackageManager.
+ for (final OverlayInfo oi : mSettings.getOverlaysForTarget("android", userId)) {
+ if (oi.isEnabled()) {
+ enabledOverlayPaths.add(oi.baseCodePath);
+ }
+ }
+
+ for (final OverlayInfo oi : targetOverlays) {
+ if (oi.isEnabled()) {
+ enabledOverlayPaths.add(oi.baseCodePath);
+ }
+ }
+
+ // TODO(): Use getEnabledOverlayPaths(userId, targetPackageName) instead of
+ // resourceDirs if in the future resourceDirs contains APKs other than overlays
PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, userId);
ApplicationInfo appInfo = packageInfo == null ? null : packageInfo.applicationInfo;
String[] resourceDirs = appInfo == null ? null : appInfo.resourceDirs;
// If the lists aren't the same length, the enabled overlays have changed
- if (ArrayUtils.size(resourceDirs) != enabledBaseCodePaths.size()) {
+ if (ArrayUtils.size(resourceDirs) != enabledOverlayPaths.size()) {
modified = true;
} else if (resourceDirs != null) {
// If any element isn't equal, an overlay or the order of overlays has changed
for (int index = 0; index < resourceDirs.length; index++) {
- if (!resourceDirs[index].equals(enabledBaseCodePaths.get(index))) {
+ if (!resourceDirs[index].equals(enabledOverlayPaths.get(index))) {
modified = true;
break;
}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
new file mode 100644
index 000000000000..ab8cc5374ec9
--- /dev/null
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2019 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 android.Manifest;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Build;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.permission.IPermissionManager;
+import android.provider.DeviceConfig;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The entity responsible for filtering visibility between apps based on declarations in their
+ * manifests.
+ */
+class AppsFilter {
+
+ private static final String TAG = PackageManagerService.TAG;
+ /**
+ * This contains a list of packages that are implicitly queryable because another app explicitly
+ * interacted with it. For example, if application A starts a service in application B,
+ * application B is implicitly allowed to query for application A; regardless of any manifest
+ * entries.
+ */
+ private final SparseArray<HashMap<String, ArrayList<String>>> mImplicitlyQueryable =
+ new SparseArray<>();
+
+ /**
+ * A mapping from the set of packages that query other packages via package name to the
+ * list of packages that they can see.
+ */
+ private final HashMap<String, List<String>> mQueriesViaPackage = new HashMap<>();
+
+ /**
+ * A mapping from the set of packages that query others via intent to the list
+ * of packages that the intents resolve to.
+ */
+ private final HashMap<String, List<String>> mQueriesViaIntent = new HashMap<>();
+
+ /**
+ * A set of packages that are always queryable by any package, regardless of their manifest
+ * content.
+ */
+ private final HashSet<String> mForceQueryable;
+ /**
+ * A set of packages that are always queryable by any package, regardless of their manifest
+ * content.
+ */
+ private final Set<String> mForceQueryableByDevice;
+
+ /** True if all system apps should be made queryable by default. */
+ private final boolean mSystemAppsQueryable;
+
+ private final IPermissionManager mPermissionManager;
+
+ private final AppOpsManager mAppOpsManager;
+ private final ConfigProvider mConfigProvider;
+
+ AppsFilter(ConfigProvider configProvider, IPermissionManager permissionManager,
+ AppOpsManager appOpsManager, String[] forceQueryableWhitelist,
+ boolean systemAppsQueryable) {
+ mConfigProvider = configProvider;
+ mAppOpsManager = appOpsManager;
+ final HashSet<String> forceQueryableByDeviceSet = new HashSet<>();
+ Collections.addAll(forceQueryableByDeviceSet, forceQueryableWhitelist);
+ this.mForceQueryableByDevice = Collections.unmodifiableSet(forceQueryableByDeviceSet);
+ this.mForceQueryable = new HashSet<>();
+ mPermissionManager = permissionManager;
+ mSystemAppsQueryable = systemAppsQueryable;
+ }
+
+ public static AppsFilter create(Context context) {
+ final boolean forceSystemAppsQueryable =
+ context.getResources().getBoolean(R.bool.config_forceSystemPackagesQueryable);
+ final ConfigProvider configProvider = () -> DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
+ "package_query_filtering_enabled",
+ false);
+ final String[] forcedQueryablePackageNames;
+ if (forceSystemAppsQueryable) {
+ // all system apps already queryable, no need to read and parse individual exceptions
+ forcedQueryablePackageNames = new String[]{};
+ } else {
+ forcedQueryablePackageNames =
+ context.getResources().getStringArray(R.array.config_forceQueryablePackages);
+ for (int i = 0; i < forcedQueryablePackageNames.length; i++) {
+ forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern();
+ }
+ }
+ IPermissionManager permissionmgr =
+ (IPermissionManager) ServiceManager.getService("permissionmgr");
+ return new AppsFilter(configProvider, permissionmgr,
+ context.getSystemService(AppOpsManager.class), forcedQueryablePackageNames,
+ forceSystemAppsQueryable);
+ }
+
+ /** Returns true if the querying package may query for the potential target package */
+ private static boolean canQuery(PackageParser.Package querying,
+ PackageParser.Package potentialTarget) {
+ if (querying.mQueriesIntents == null) {
+ return false;
+ }
+ for (Intent intent : querying.mQueriesIntents) {
+ for (PackageParser.Activity activity : potentialTarget.activities) {
+ if (activity.intents != null) {
+ for (PackageParser.ActivityIntentInfo filter : activity.intents) {
+ if (matches(intent, filter)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /** Returns true if the given intent matches the given filter. */
+ private static boolean matches(Intent intent, PackageParser.ActivityIntentInfo filter) {
+ return filter.match(intent.getAction(), intent.getType(), intent.getScheme(),
+ intent.getData(), intent.getCategories(), "AppsFilter") > 0;
+ }
+
+ /**
+ * Marks that a package initiated an interaction with another package, granting visibility of
+ * the prior from the former.
+ *
+ * @param initiatingPackage the package initiating the interaction
+ * @param targetPackage the package being interacted with and thus gaining visibility of the
+ * initiating package.
+ * @param userId the user in which this interaction was taking place
+ */
+ private void markAppInteraction(
+ PackageSetting initiatingPackage, PackageSetting targetPackage, int userId) {
+ HashMap<String, ArrayList<String>> currentUser = mImplicitlyQueryable.get(userId);
+ if (currentUser == null) {
+ currentUser = new HashMap<>();
+ mImplicitlyQueryable.put(userId, currentUser);
+ }
+ if (!currentUser.containsKey(targetPackage.pkg.packageName)) {
+ currentUser.put(targetPackage.pkg.packageName, new ArrayList<>());
+ }
+ currentUser.get(targetPackage.pkg.packageName).add(initiatingPackage.pkg.packageName);
+ }
+
+ /**
+ * Adds a package that should be considered when filtering visibility between apps.
+ *
+ * @param newPkg the new package being added
+ * @param existing all other packages currently on the device.
+ */
+ public void addPackage(PackageParser.Package newPkg,
+ Map<String, PackageParser.Package> existing) {
+ // let's re-evaluate the ability of already added packages to see this new package
+ if (newPkg.mForceQueryable
+ || (mSystemAppsQueryable && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) {
+ mForceQueryable.add(newPkg.packageName);
+ } else {
+ for (String packageName : mQueriesViaIntent.keySet()) {
+ if (packageName == newPkg.packageName) {
+ continue;
+ }
+ final PackageParser.Package existingPackage = existing.get(packageName);
+ if (canQuery(existingPackage, newPkg)) {
+ mQueriesViaIntent.get(packageName).add(newPkg.packageName);
+ }
+ }
+ }
+ // if the new package declares them, let's evaluate its ability to see existing packages
+ mQueriesViaIntent.put(newPkg.packageName, new ArrayList<>());
+ for (PackageParser.Package existingPackage : existing.values()) {
+ if (existingPackage.packageName == newPkg.packageName) {
+ continue;
+ }
+ if (existingPackage.mForceQueryable
+ || (mSystemAppsQueryable
+ && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) {
+ continue;
+ }
+ if (canQuery(newPkg, existingPackage)) {
+ mQueriesViaIntent.get(newPkg.packageName).add(existingPackage.packageName);
+ }
+ }
+ final ArrayList<String> queriesPackages = new ArrayList<>(
+ newPkg.mQueriesPackages == null ? 0 : newPkg.mQueriesPackages.size());
+ if (newPkg.mQueriesPackages != null) {
+ queriesPackages.addAll(newPkg.mQueriesPackages);
+ }
+ mQueriesViaPackage.put(newPkg.packageName, queriesPackages);
+ }
+
+ /**
+ * Removes a package for consideration when filtering visibility between apps.
+ *
+ * @param packageName the name of the package being removed.
+ */
+ public void removePackage(String packageName) {
+ mForceQueryable.remove(packageName);
+
+ for (int i = 0; i < mImplicitlyQueryable.size(); i++) {
+ mImplicitlyQueryable.valueAt(i).remove(packageName);
+ for (ArrayList<String> initiators : mImplicitlyQueryable.valueAt(i).values()) {
+ initiators.remove(packageName);
+ }
+ }
+
+ mQueriesViaIntent.remove(packageName);
+ for (List<String> declarators : mQueriesViaIntent.values()) {
+ declarators.remove(packageName);
+ }
+
+ mQueriesViaPackage.remove(packageName);
+ }
+
+ /**
+ * Returns true if the calling package should not be able to see the target package, false if no
+ * filtering should be done.
+ *
+ * @param callingUid the uid of the caller attempting to access a package
+ * @param callingSetting the setting attempting to access a package or null if it could not be
+ * found
+ * @param targetPkgSetting the package being accessed
+ * @param userId the user in which this access is being attempted
+ */
+ public boolean shouldFilterApplication(int callingUid, @Nullable SettingBase callingSetting,
+ PackageSetting targetPkgSetting, int userId) {
+ if (callingUid < Process.FIRST_APPLICATION_UID) {
+ return false;
+ }
+ if (callingSetting == null) {
+ Slog.wtf(TAG, "No setting found for non system uid " + callingUid);
+ return true;
+ }
+ PackageSetting callingPkgSetting = null;
+ if (callingSetting instanceof PackageSetting) {
+ callingPkgSetting = (PackageSetting) callingSetting;
+ if (!shouldFilterApplicationInternal(callingPkgSetting, targetPkgSetting,
+ userId)) {
+ // TODO: actually base this on a start / launch (not just a query)
+ markAppInteraction(callingPkgSetting, targetPkgSetting, userId);
+ return false;
+ }
+ } else if (callingSetting instanceof SharedUserSetting) {
+ final ArraySet<PackageSetting> packageSettings =
+ ((SharedUserSetting) callingSetting).packages;
+ if (packageSettings != null && packageSettings.size() > 0) {
+ for (PackageSetting packageSetting : packageSettings) {
+ if (!shouldFilterApplicationInternal(packageSetting, targetPkgSetting,
+ userId)) {
+ // TODO: actually base this on a start / launch (not just a query)
+ markAppInteraction(packageSetting, targetPkgSetting, userId);
+ return false;
+ }
+ if (callingPkgSetting == null && packageSetting.pkg != null) {
+ callingPkgSetting = packageSetting;
+ }
+ }
+ } else {
+ return true;
+ }
+ }
+ if (callingPkgSetting == null) {
+ Slog.wtf(TAG, "What... " + callingSetting);
+ return true;
+ }
+ final int mode = mAppOpsManager
+ .checkOpNoThrow(AppOpsManager.OP_QUERY_ALL_PACKAGES, callingUid,
+ callingPkgSetting.pkg.packageName);
+ switch (mode) {
+ case AppOpsManager.MODE_DEFAULT:
+ // if default, let's rely on remote feature toggle to determine whether to
+ // actually filter
+ return mConfigProvider.isEnabled();
+ case AppOpsManager.MODE_ALLOWED:
+ // explicitly allowed to see all packages, don't filter
+ return false;
+ case AppOpsManager.MODE_ERRORED:
+ // deny / error: let's log so developer can audit usages
+ Slog.i(TAG, callingPkgSetting.pkg.packageName
+ + " blocked from accessing " + targetPkgSetting.pkg.packageName);
+ case AppOpsManager.MODE_IGNORED:
+ // fall through
+ default:
+ return true;
+ }
+ }
+
+ private boolean shouldFilterApplicationInternal(
+ PackageSetting callingPkgSetting, PackageSetting targetPkgSetting, int userId) {
+ final String callingName = callingPkgSetting.pkg.packageName;
+ final String targetName = targetPkgSetting.pkg.packageName;
+ if (callingPkgSetting.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) {
+ return false;
+ }
+ if (isImplicitlyQueryableSystemApp(targetPkgSetting)) {
+ return false;
+ }
+ if (targetPkgSetting.pkg.mForceQueryable) {
+ return false;
+ }
+ if (mForceQueryable.contains(targetName)) {
+ return false;
+ }
+ if (mQueriesViaPackage.containsKey(callingName)
+ && mQueriesViaPackage.get(callingName).contains(
+ targetName)) {
+ // the calling package has explicitly declared the target package; allow
+ return false;
+ } else if (mQueriesViaIntent.containsKey(callingName)
+ && mQueriesViaIntent.get(callingName).contains(targetName)) {
+ return false;
+ }
+ if (mImplicitlyQueryable.get(userId) != null
+ && mImplicitlyQueryable.get(userId).containsKey(callingName)
+ && mImplicitlyQueryable.get(userId).get(callingName).contains(targetName)) {
+ return false;
+ }
+ try {
+ if (mPermissionManager.checkPermission(
+ Manifest.permission.QUERY_ALL_PACKAGES, callingName, userId)
+ == PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ } catch (RemoteException e) {
+ return true;
+ }
+ return true;
+ }
+
+ private boolean isImplicitlyQueryableSystemApp(PackageSetting targetPkgSetting) {
+ return targetPkgSetting.isSystem() && (mSystemAppsQueryable
+ || mForceQueryableByDevice.contains(targetPkgSetting.pkg.packageName));
+ }
+
+ public interface ConfigProvider {
+ boolean isEnabled();
+ }
+
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 2b33aced7151..984f22f01465 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -345,40 +345,55 @@ public class BackgroundDexOptService extends JobService {
private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
long lowStorageThreshold, boolean isForPrimaryDex) {
ArraySet<String> updatedPackages = new ArraySet<>();
- Set<String> unusedPackages = pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
- boolean hadSomeLowSpaceFailure = false;
- Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
- // Only downgrade apps when space is low on device.
- // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
- // up disk before user hits the actual lowStorageThreshold.
- final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE *
- lowStorageThreshold;
- boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
- Log.d(TAG, "Should Downgrade " + shouldDowngrade);
- boolean dex_opt_performed = false;
- for (String pkg : pkgs) {
- int abort_code = abortIdleOptimizations(lowStorageThreshold);
- if (abort_code == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
- return abort_code;
- }
- // Downgrade unused packages.
- if (unusedPackages.contains(pkg) && shouldDowngrade) {
- dex_opt_performed = downgradePackage(pm, pkg, isForPrimaryDex);
- } else {
- if (abort_code == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
- // can't dexopt because of low space.
- hadSomeLowSpaceFailure = true;
- continue;
+
+ try {
+ // Only downgrade apps when space is low on device.
+ // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
+ // up disk before user hits the actual lowStorageThreshold.
+ final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE
+ * lowStorageThreshold;
+ boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
+ Log.d(TAG, "Should Downgrade " + shouldDowngrade);
+ if (shouldDowngrade) {
+ Set<String> unusedPackages =
+ pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
+ Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
+
+ for (String pkg : unusedPackages) {
+ int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1);
+ if (abortCode != OPTIMIZE_CONTINUE) {
+ // Should be aborted by the scheduler.
+ return abortCode;
+ }
+ if (downgradePackage(pm, pkg, isForPrimaryDex)) {
+ updatedPackages.add(pkg);
+ }
+ }
+
+ if (!unusedPackages.isEmpty()) {
+ pkgs = new ArraySet<>(pkgs);
+ pkgs.removeAll(unusedPackages);
}
- dex_opt_performed = optimizePackage(pm, pkg, isForPrimaryDex);
}
- if (dex_opt_performed) {
- updatedPackages.add(pkg);
+
+ for (String pkg : pkgs) {
+ int abortCode = abortIdleOptimizations(lowStorageThreshold);
+ if (abortCode != OPTIMIZE_CONTINUE) {
+ // Either aborted by the scheduler or no space left.
+ return abortCode;
+ }
+
+ boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex);
+ if (dexOptPerformed) {
+ updatedPackages.add(pkg);
+ }
}
- }
- notifyPinService(updatedPackages);
- return hadSomeLowSpaceFailure ? OPTIMIZE_ABORT_NO_SPACE_LEFT : OPTIMIZE_PROCESSED;
+ return OPTIMIZE_PROCESSED;
+ } finally {
+ // Always let the pinner service know about changes.
+ notifyPinService(updatedPackages);
+ }
}
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 8b9af7a435e4..8f38026b365f 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -112,7 +112,7 @@ class InstantAppRegistry {
private final CookiePersistence mCookiePersistence;
/** State for uninstalled instant apps */
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private SparseArray<List<UninstalledInstantAppState>> mUninstalledInstantApps;
/**
@@ -121,11 +121,11 @@ class InstantAppRegistry {
* The value is a set of instant app UIDs.
* UserID -> TargetAppId -> InstantAppId
*/
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private SparseArray<SparseArray<SparseBooleanArray>> mInstantGrants;
/** The set of all installed instant apps. UserID -> AppID */
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private SparseArray<SparseBooleanArray> mInstalledInstantAppUids;
public InstantAppRegistry(PackageManagerService service) {
@@ -133,7 +133,7 @@ class InstantAppRegistry {
mCookiePersistence = new CookiePersistence(BackgroundThread.getHandler().getLooper());
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
public byte[] getInstantAppCookieLPw(@NonNull String packageName,
@UserIdInt int userId) {
// Only installed packages can get their own cookie
@@ -157,7 +157,7 @@ class InstantAppRegistry {
return null;
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
public boolean setInstantAppCookieLPw(@NonNull String packageName,
@Nullable byte[] cookie, @UserIdInt int userId) {
if (cookie != null && cookie.length > 0) {
@@ -182,7 +182,7 @@ class InstantAppRegistry {
private void persistInstantApplicationCookie(@Nullable byte[] cookie,
@NonNull String packageName, @NonNull File cookieFile, @UserIdInt int userId) {
- synchronized (mService.mPackages) {
+ synchronized (mService.mLock) {
File appDir = getInstantApplicationDir(packageName, userId);
if (!appDir.exists() && !appDir.mkdirs()) {
Slog.e(LOG_TAG, "Cannot create instant app cookie directory");
@@ -250,7 +250,7 @@ class InstantAppRegistry {
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
public @Nullable List<InstantAppInfo> getInstantAppsLPr(@UserIdInt int userId) {
List<InstantAppInfo> installedApps = getInstalledInstantApplicationsLPr(userId);
List<InstantAppInfo> uninstalledApps = getUninstalledInstantApplicationsLPr(userId);
@@ -263,7 +263,7 @@ class InstantAppRegistry {
return uninstalledApps;
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
public void onPackageInstalledLPw(@NonNull PackageParser.Package pkg, @NonNull int[] userIds) {
PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
@@ -334,7 +334,7 @@ class InstantAppRegistry {
}
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
public void onPackageUninstalledLPw(@NonNull PackageParser.Package pkg,
@NonNull int[] userIds) {
PackageSetting ps = (PackageSetting) pkg.mExtras;
@@ -360,7 +360,7 @@ class InstantAppRegistry {
}
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
public void onUserRemovedLPw(int userId) {
if (mUninstalledInstantApps != null) {
mUninstalledInstantApps.remove(userId);
@@ -399,7 +399,7 @@ class InstantAppRegistry {
return instantGrantList.get(instantAppId);
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
public void grantInstantAccessLPw(@UserIdInt int userId, @Nullable Intent intent,
int targetAppId, int instantAppId) {
if (mInstalledInstantAppUids == null) {
@@ -434,7 +434,7 @@ class InstantAppRegistry {
instantGrantList.put(instantAppId, true /*granted*/);
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
public void addInstantAppLPw(@UserIdInt int userId, int instantAppId) {
if (mInstalledInstantAppUids == null) {
mInstalledInstantAppUids = new SparseArray<>();
@@ -447,7 +447,7 @@ class InstantAppRegistry {
instantAppList.put(instantAppId, true /*installed*/);
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private void removeInstantAppLPw(@UserIdInt int userId, int instantAppId) {
// remove from the installed list
if (mInstalledInstantAppUids == null) {
@@ -473,7 +473,7 @@ class InstantAppRegistry {
}
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private void removeAppLPw(@UserIdInt int userId, int targetAppId) {
// remove from the installed list
if (mInstantGrants == null) {
@@ -486,7 +486,7 @@ class InstantAppRegistry {
targetAppList.delete(targetAppId);
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private void addUninstalledInstantAppLPw(@NonNull PackageParser.Package pkg,
@UserIdInt int userId) {
InstantAppInfo uninstalledApp = createInstantAppInfoForPackage(
@@ -541,13 +541,13 @@ class InstantAppRegistry {
}
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
boolean hasInstantApplicationMetadataLPr(String packageName, int userId) {
return hasUninstalledInstantAppStateLPr(packageName, userId)
|| hasInstantAppMetadataLPr(packageName, userId);
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
public void deleteInstantApplicationMetadataLPw(@NonNull String packageName,
@UserIdInt int userId) {
removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) ->
@@ -564,7 +564,7 @@ class InstantAppRegistry {
}
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private void removeUninstalledInstantAppStateLPw(
@NonNull Predicate<UninstalledInstantAppState> criteria, @UserIdInt int userId) {
if (mUninstalledInstantApps == null) {
@@ -592,7 +592,7 @@ class InstantAppRegistry {
}
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private boolean hasUninstalledInstantAppStateLPr(String packageName, @UserIdInt int userId) {
if (mUninstalledInstantApps == null) {
return false;
@@ -685,7 +685,7 @@ class InstantAppRegistry {
final long now = System.currentTimeMillis();
// Prune first installed instant apps
- synchronized (mService.mPackages) {
+ synchronized (mService.mLock) {
allUsers = PackageManagerService.sUserManager.getUserIds();
final int packageCount = mService.mPackages.size();
@@ -768,7 +768,7 @@ class InstantAppRegistry {
}
// Prune uninstalled instant apps
- synchronized (mService.mPackages) {
+ synchronized (mService.mLock) {
// TODO: Track last used time for uninstalled instant apps for better pruning
for (int userId : UserManagerService.getInstance().getUserIds()) {
// Prune in-memory state
@@ -811,7 +811,7 @@ class InstantAppRegistry {
return false;
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private @Nullable List<InstantAppInfo> getInstalledInstantApplicationsLPr(
@UserIdInt int userId) {
List<InstantAppInfo> result = null;
@@ -866,7 +866,7 @@ class InstantAppRegistry {
}
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private @Nullable List<InstantAppInfo> getUninstalledInstantApplicationsLPr(
@UserIdInt int userId) {
List<UninstalledInstantAppState> uninstalledAppStates =
@@ -939,7 +939,7 @@ class InstantAppRegistry {
return uninstalledAppState.mInstantAppInfo;
}
- @GuardedBy("mService.mPackages")
+ @GuardedBy("mService.mLock")
private @Nullable List<UninstalledInstantAppState> getUninstalledInstantAppStatesLPr(
@UserIdInt int userId) {
List<UninstalledInstantAppState> uninstalledAppStates = null;
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index f326f1d20c46..ec48713b0874 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -22,11 +22,11 @@ import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArraySet;
+import dalvik.system.VMRuntime;
+
import java.util.ArrayList;
import java.util.List;
-import dalvik.system.VMRuntime;
-
/**
* Provides various methods for obtaining and converting of instruction sets.
*
@@ -113,12 +113,15 @@ public class InstructionSets {
return allInstructionSets;
}
- public static String getPrimaryInstructionSet(ApplicationInfo info) {
- if (info.primaryCpuAbi == null) {
+ /**
+ * Calculates the primary instruction set based on the computed Abis of a given package.
+ */
+ public static String getPrimaryInstructionSet(PackageAbiHelper.Abis abis) {
+ if (abis.primary == null) {
return getPreferredInstructionSet();
}
- return VMRuntime.getInstructionSet(info.primaryCpuAbi);
+ return VMRuntime.getInstructionSet(abis.primary);
}
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index e5a2e777a796..d49ecdda679d 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -120,7 +120,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
}
final List<PackageParser.Package> important;
final List<PackageParser.Package> others;
- synchronized (mPackageManagerService.mPackages) {
+ synchronized (mPackageManagerService.mLock) {
// Important: the packages we need to run with ab-ota compiler-reason.
important = PackageManagerServiceUtils.getPackagesForDexopt(
mPackageManagerService.mPackages.values(), mPackageManagerService,
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
new file mode 100644
index 000000000000..6f46564068d9
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2019 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 android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.util.Pair;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.util.Set;
+
+@VisibleForTesting
+interface PackageAbiHelper {
+ /**
+ * Derive and get the location of native libraries for the given package,
+ * which varies depending on where and how the package was installed.
+ */
+ NativeLibraryPaths getNativeLibraryPaths(
+ PackageParser.Package pkg, File appLib32InstallDir);
+
+ /**
+ * Calculate the abis for a bundled app. These can uniquely be determined from the contents of
+ * the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not
+ * validate any of this information, and instead assume that the system was built sensibly.
+ */
+ Abis getBundledAppAbis(PackageParser.Package pkg);
+
+ /**
+ * Derive the ABI of a non-system package located at {@code pkg}. This information
+ * is derived purely on the basis of the contents of {@code pkg} and {@code cpuAbiOverride}.
+ *
+ * If {@code extractLibs} is true, native libraries are extracted from the app if required.
+ */
+ Pair<Abis, NativeLibraryPaths> derivePackageAbi(
+ PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+ throws PackageManagerException;
+
+ /**
+ * Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
+ * match. i.e, so that all packages can be run inside a single process if required.
+ *
+ * Optionally, callers can pass in a parsed package via {@code scannedPackage} in which case
+ * this function will either try and make the ABI for all packages in
+ * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
+ * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
+ * variant is used when installing or updating a package that belongs to a shared user.
+ *
+ * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+ * adds unnecessary complexity.
+ *
+ * @return the calculated primary abi that should be set for all non-specified packages
+ * belonging to the shared user.
+ */
+ @Nullable
+ String getAdjustedAbiForSharedUser(
+ Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
+
+ /**
+ * The native library paths and related properties that should be set on a
+ * {@link android.content.pm.PackageParser.Package}.
+ */
+ final class NativeLibraryPaths {
+ public final String nativeLibraryRootDir;
+ public final boolean nativeLibraryRootRequiresIsa;
+ public final String nativeLibraryDir;
+ public final String secondaryNativeLibraryDir;
+
+ @VisibleForTesting
+ NativeLibraryPaths(String nativeLibraryRootDir,
+ boolean nativeLibraryRootRequiresIsa, String nativeLibraryDir,
+ String secondaryNativeLibraryDir) {
+ this.nativeLibraryRootDir = nativeLibraryRootDir;
+ this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+ this.nativeLibraryDir = nativeLibraryDir;
+ this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+ }
+
+ public void applyTo(PackageParser.Package pkg) {
+ pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
+ pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+ pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir;
+ pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+ }
+ }
+
+ /**
+ * The primary and secondary ABIs that should be set on a package and its package setting.
+ */
+ final class Abis {
+ public final String primary;
+ public final String secondary;
+
+ @VisibleForTesting
+ Abis(String primary, String secondary) {
+ this.primary = primary;
+ this.secondary = secondary;
+ }
+
+ Abis(PackageParser.Package pkg) {
+ this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi);
+ }
+
+ public void applyTo(PackageParser.Package pkg) {
+ pkg.applicationInfo.primaryCpuAbi = primary;
+ pkg.applicationInfo.secondaryCpuAbi = secondary;
+ }
+ public void applyTo(PackageSetting pkgSetting) {
+ // pkgSetting might be null during rescan following uninstall of updates
+ // to a bundled app, so accommodate that possibility. The settings in
+ // that case will be established later from the parsed package.
+ //
+ // If the settings aren't null, sync them up with what we've derived.
+ if (pkgSetting != null) {
+ pkgSetting.primaryCpuAbiString = primary;
+ pkgSetting.secondaryCpuAbiString = secondary;
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
new file mode 100644
index 000000000000..1d3d24c27041
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2019 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.INSTALL_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageParser.isApkFile;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
+import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
+import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
+
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Build;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Trace;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.util.ArrayUtils;
+
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+final class PackageAbiHelperImpl implements PackageAbiHelper {
+
+ private static String calculateBundledApkRoot(final String codePathString) {
+ final File codePath = new File(codePathString);
+ final File codeRoot;
+ if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
+ codeRoot = Environment.getRootDirectory();
+ } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
+ codeRoot = Environment.getOemDirectory();
+ } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
+ codeRoot = Environment.getVendorDirectory();
+ } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+ codeRoot = Environment.getOdmDirectory();
+ } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
+ codeRoot = Environment.getProductDirectory();
+ } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
+ codeRoot = Environment.getSystemExtDirectory();
+ } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+ codeRoot = Environment.getOdmDirectory();
+ } else {
+ // Unrecognized code path; take its top real segment as the apk root:
+ // e.g. /something/app/blah.apk => /something
+ try {
+ File f = codePath.getCanonicalFile();
+ File parent = f.getParentFile(); // non-null because codePath is a file
+ File tmp;
+ while ((tmp = parent.getParentFile()) != null) {
+ f = parent;
+ parent = tmp;
+ }
+ codeRoot = f;
+ Slog.w(PackageManagerService.TAG, "Unrecognized code path "
+ + codePath + " - using " + codeRoot);
+ } catch (IOException e) {
+ // Can't canonicalize the code path -- shenanigans?
+ Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
+ return Environment.getRootDirectory().getPath();
+ }
+ }
+ return codeRoot.getPath();
+ }
+
+ // Utility method that returns the relative package path with respect
+ // to the installation directory. Like say for /data/data/com.test-1.apk
+ // string com.test-1 is returned.
+ private static String deriveCodePathName(String codePath) {
+ if (codePath == null) {
+ return null;
+ }
+ final File codeFile = new File(codePath);
+ final String name = codeFile.getName();
+ if (codeFile.isDirectory()) {
+ return name;
+ } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
+ final int lastDot = name.lastIndexOf('.');
+ return name.substring(0, lastDot);
+ } else {
+ Slog.w(PackageManagerService.TAG, "Odd, " + codePath + " doesn't look like an APK");
+ return null;
+ }
+ }
+
+ private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
+ PackageManagerException {
+ if (copyRet < 0) {
+ if (copyRet != PackageManager.NO_NATIVE_LIBRARIES
+ && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+ throw new PackageManagerException(copyRet, message);
+ }
+ }
+ }
+
+ @Override
+ public NativeLibraryPaths getNativeLibraryPaths(
+ PackageParser.Package pkg, File appLib32InstallDir) {
+ return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath,
+ pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
+ pkg.applicationInfo.isUpdatedSystemApp());
+ }
+
+ private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
+ final File appLib32InstallDir, final String codePath, final String sourceDir,
+ final boolean isSystemApp, final boolean isUpdatedSystemApp) {
+ final File codeFile = new File(codePath);
+ final boolean bundledApp = isSystemApp && !isUpdatedSystemApp;
+
+ final String nativeLibraryRootDir;
+ final boolean nativeLibraryRootRequiresIsa;
+ final String nativeLibraryDir;
+ final String secondaryNativeLibraryDir;
+
+ if (isApkFile(codeFile)) {
+ // Monolithic install
+ if (bundledApp) {
+ // If "/system/lib64/apkname" exists, assume that is the per-package
+ // native library directory to use; otherwise use "/system/lib/apkname".
+ final String apkRoot = calculateBundledApkRoot(sourceDir);
+ final boolean is64Bit = VMRuntime.is64BitInstructionSet(
+ getPrimaryInstructionSet(abis));
+
+ // This is a bundled system app so choose the path based on the ABI.
+ // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
+ // is just the default path.
+ final String apkName = deriveCodePathName(codePath);
+ final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
+ nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
+ apkName).getAbsolutePath();
+
+ if (abis.secondary != null) {
+ final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
+ secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
+ secondaryLibDir, apkName).getAbsolutePath();
+ } else {
+ secondaryNativeLibraryDir = null;
+ }
+ } else {
+ final String apkName = deriveCodePathName(codePath);
+ nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
+ .getAbsolutePath();
+ secondaryNativeLibraryDir = null;
+ }
+
+ nativeLibraryRootRequiresIsa = false;
+ nativeLibraryDir = nativeLibraryRootDir;
+ } else {
+ // Cluster install
+ nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
+ nativeLibraryRootRequiresIsa = true;
+
+ nativeLibraryDir = new File(nativeLibraryRootDir,
+ getPrimaryInstructionSet(abis)).getAbsolutePath();
+
+ if (abis.secondary != null) {
+ secondaryNativeLibraryDir = new File(nativeLibraryRootDir,
+ VMRuntime.getInstructionSet(abis.secondary)).getAbsolutePath();
+ } else {
+ secondaryNativeLibraryDir = null;
+ }
+ }
+ return new NativeLibraryPaths(nativeLibraryRootDir, nativeLibraryRootRequiresIsa,
+ nativeLibraryDir, secondaryNativeLibraryDir);
+ }
+
+ @Override
+ public Abis getBundledAppAbis(PackageParser.Package pkg) {
+ final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+
+ // If "/system/lib64/apkname" exists, assume that is the per-package
+ // native library directory to use; otherwise use "/system/lib/apkname".
+ final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
+ final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
+ return abis;
+ }
+
+ /**
+ * Deduces the ABI of a bundled app and sets the relevant fields on the
+ * parsed pkg object.
+ *
+ * @param apkRoot the root of the installed apk, something like {@code /system} or
+ * {@code /oem} under which system libraries are installed.
+ * @param apkName the name of the installed package.
+ */
+ private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
+ final File codeFile = new File(pkg.codePath);
+
+ final boolean has64BitLibs;
+ final boolean has32BitLibs;
+
+ final String primaryCpuAbi;
+ final String secondaryCpuAbi;
+ if (isApkFile(codeFile)) {
+ // Monolithic install
+ has64BitLibs =
+ (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
+ has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
+ } else {
+ // Cluster install
+ final File rootDir = new File(codeFile, LIB_DIR_NAME);
+ if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
+ && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
+ final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
+ has64BitLibs = (new File(rootDir, isa)).exists();
+ } else {
+ has64BitLibs = false;
+ }
+ if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
+ && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
+ final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
+ has32BitLibs = (new File(rootDir, isa)).exists();
+ } else {
+ has32BitLibs = false;
+ }
+ }
+
+ if (has64BitLibs && !has32BitLibs) {
+ // The package has 64 bit libs, but not 32 bit libs. Its primary
+ // ABI should be 64 bit. We can safely assume here that the bundled
+ // native libraries correspond to the most preferred ABI in the list.
+
+ primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ secondaryCpuAbi = null;
+ } else if (has32BitLibs && !has64BitLibs) {
+ // The package has 32 bit libs but not 64 bit libs. Its primary
+ // ABI should be 32 bit.
+
+ primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ secondaryCpuAbi = null;
+ } else if (has32BitLibs && has64BitLibs) {
+ // The application has both 64 and 32 bit bundled libraries. We check
+ // here that the app declares multiArch support, and warn if it doesn't.
+ //
+ // We will be lenient here and record both ABIs. The primary will be the
+ // ABI that's higher on the list, i.e, a device that's configured to prefer
+ // 64 bit apps will see a 64 bit primary ABI,
+
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+ Slog.e(PackageManagerService.TAG,
+ "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
+ }
+
+ if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
+ primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ } else {
+ primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ }
+ } else {
+ primaryCpuAbi = null;
+ secondaryCpuAbi = null;
+ }
+ return new Abis(primaryCpuAbi, secondaryCpuAbi);
+ }
+
+ @Override
+ public Pair<Abis, NativeLibraryPaths> derivePackageAbi(
+ PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+ throws PackageManagerException {
+ // Give ourselves some initial paths; we'll come back for another
+ // pass once we've determined ABI below.
+ final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg),
+ PackageManagerService.sAppLib32InstallDir, pkg.codePath,
+ pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
+ pkg.applicationInfo.isUpdatedSystemApp());
+
+ // We shouldn't attempt to extract libs from system app when it was not updated.
+ if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
+ extractLibs = false;
+ }
+
+ final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
+ final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
+
+ String primaryCpuAbi = null;
+ String secondaryCpuAbi = null;
+
+ NativeLibraryHelper.Handle handle = null;
+ try {
+ handle = NativeLibraryHelper.Handle.create(pkg);
+ // TODO(multiArch): This can be null for apps that didn't go through the
+ // usual installation process. We can calculate it again, like we
+ // do during install time.
+ //
+ // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
+ // unnecessary.
+ final File nativeLibraryRoot = new File(nativeLibraryRootStr);
+
+ // Null out the abis so that they can be recalculated.
+ primaryCpuAbi = null;
+ secondaryCpuAbi = null;
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
+ // Warn if we've set an abiOverride for multi-lib packages..
+ // By definition, we need to copy both 32 and 64 bit libraries for
+ // such packages.
+ if (pkg.cpuAbiOverride != null
+ && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+ Slog.w(PackageManagerService.TAG,
+ "Ignoring abiOverride for multi arch application.");
+ }
+
+ int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
+ int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
+ if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ if (extractLibs) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+ abi32 = NativeLibraryHelper.findSupportedAbi(
+ handle, Build.SUPPORTED_32_BIT_ABIS);
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // Shared library native code should be in the APK zip aligned
+ if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Shared library native lib extraction not supported");
+ }
+
+ maybeThrowExceptionForMultiArchCopy(
+ "Error unpackaging 32 bit native libs for multiarch app.", abi32);
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ if (extractLibs) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+ abi64 = NativeLibraryHelper.findSupportedAbi(
+ handle, Build.SUPPORTED_64_BIT_ABIS);
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ maybeThrowExceptionForMultiArchCopy(
+ "Error unpackaging 64 bit native libs for multiarch app.", abi64);
+
+ if (abi64 >= 0) {
+ // Shared library native libs should be in the APK zip aligned
+ if (extractLibs && pkg.isLibrary()) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Shared library native lib extraction not supported");
+ }
+ primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
+ }
+
+ if (abi32 >= 0) {
+ final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
+ if (abi64 >= 0) {
+ if (pkg.use32bitAbi) {
+ secondaryCpuAbi = primaryCpuAbi;
+ primaryCpuAbi = abi;
+ } else {
+ secondaryCpuAbi = abi;
+ }
+ } else {
+ primaryCpuAbi = abi;
+ }
+ }
+ } else {
+ String[] abiList = (cpuAbiOverride != null)
+ ? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS;
+
+ // Enable gross and lame hacks for apps that are built with old
+ // SDK tools. We must scan their APKs for renderscript bitcode and
+ // not launch them if it's present. Don't bother checking on devices
+ // that don't have 64 bit support.
+ boolean needsRenderScriptOverride = false;
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null
+ && NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+ abiList = Build.SUPPORTED_32_BIT_ABIS;
+ needsRenderScriptOverride = true;
+ }
+
+ final int copyRet;
+ if (extractLibs) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+ copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+ if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Error unpackaging native libs for app, errorCode=" + copyRet);
+ }
+
+ if (copyRet >= 0) {
+ // Shared libraries that have native libs must be multi-architecture
+ if (pkg.isLibrary()) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Shared library with native libs must be multiarch");
+ }
+ primaryCpuAbi = abiList[copyRet];
+ } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES
+ && cpuAbiOverride != null) {
+ primaryCpuAbi = cpuAbiOverride;
+ } else if (needsRenderScriptOverride) {
+ primaryCpuAbi = abiList[0];
+ }
+ }
+ } catch (IOException ioe) {
+ Slog.e(PackageManagerService.TAG, "Unable to get canonical file " + ioe.toString());
+ } finally {
+ IoUtils.closeQuietly(handle);
+ }
+
+ // Now that we've calculated the ABIs and determined if it's an internal app,
+ // we will go ahead and populate the nativeLibraryPath.
+
+ final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
+ return new Pair<>(abis,
+ getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
+ pkg.codePath, pkg.applicationInfo.sourceDir,
+ pkg.applicationInfo.isSystemApp(),
+ pkg.applicationInfo.isUpdatedSystemApp()));
+ }
+
+ /**
+ * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
+ * i.e, so that all packages can be run inside a single process if required.
+ *
+ * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
+ * this function will either try and make the ABI for all packages in
+ * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
+ * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
+ * variant is used when installing or updating a package that belongs to a shared user.
+ *
+ * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+ * adds unnecessary complexity.
+ */
+ @Override
+ @Nullable
+ public String getAdjustedAbiForSharedUser(
+ Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
+ String requiredInstructionSet = null;
+ if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
+ requiredInstructionSet = VMRuntime.getInstructionSet(
+ scannedPackage.applicationInfo.primaryCpuAbi);
+ }
+
+ PackageSetting requirer = null;
+ for (PackageSetting ps : packagesForUser) {
+ // If packagesForUser contains scannedPackage, we skip it. This will happen
+ // when scannedPackage is an update of an existing package. Without this check,
+ // we will never be able to change the ABI of any package belonging to a shared
+ // user, even if it's compatible with other packages.
+ if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) {
+ continue;
+ }
+ if (ps.primaryCpuAbiString == null) {
+ continue;
+ }
+
+ final String instructionSet =
+ VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
+ if (requiredInstructionSet != null && !requiredInstructionSet.equals(instructionSet)) {
+ // We have a mismatch between instruction sets (say arm vs arm64) warn about
+ // this but there's not much we can do.
+ String errorMessage = "Instruction set mismatch, "
+ + ((requirer == null) ? "[caller]" : requirer)
+ + " requires " + requiredInstructionSet + " whereas " + ps
+ + " requires " + instructionSet;
+ Slog.w(PackageManagerService.TAG, errorMessage);
+ }
+
+ if (requiredInstructionSet == null) {
+ requiredInstructionSet = instructionSet;
+ requirer = ps;
+ }
+ }
+
+ if (requiredInstructionSet == null) {
+ return null;
+ }
+ final String adjustedAbi;
+ if (requirer != null) {
+ // requirer != null implies that either scannedPackage was null or that
+ // scannedPackage did not require an ABI, in which case we have to adjust
+ // scannedPackage to match the ABI of the set (which is the same as
+ // requirer's ABI)
+ adjustedAbi = requirer.primaryCpuAbiString;
+ } else {
+ // requirer == null implies that we're updating all ABIs in the set to
+ // match scannedPackage.
+ adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
+ }
+ return adjustedAbi;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dfdefe12f072..8960dfb7106c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -94,14 +94,12 @@ import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
-import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
@@ -277,6 +275,7 @@ import android.view.Display;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
@@ -314,6 +313,8 @@ import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.permission.PermissionsState;
+import com.android.server.policy.PermissionPolicyInternal;
+import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
import com.android.server.security.VerityUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -429,7 +430,7 @@ public class PackageManagerService extends IPackageManager.Stub
// user, but by default initialize to this.
public static final boolean DEBUG_DEXOPT = false;
- private static final boolean DEBUG_ABI_SELECTION = false;
+ static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_APP_DATA = false;
@@ -641,7 +642,7 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean mIsPreNMR1Upgrade;
final boolean mIsPreQUpgrade;
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private boolean mDexOptDialogShown;
// Used for privilege escalation. MUST NOT BE CALLED WITH mPackages
@@ -653,7 +654,8 @@ public class PackageManagerService extends IPackageManager.Stub
private static final File sAppInstallDir =
new File(Environment.getDataDirectory(), "app");
/** Directory where installed application's 32-bit native libraries are copied. */
- private static final File sAppLib32InstallDir =
+ @VisibleForTesting
+ static final File sAppLib32InstallDir =
new File(Environment.getDataDirectory(), "app-lib");
// ----------------------------------------------------------------
@@ -665,15 +667,18 @@ public class PackageManagerService extends IPackageManager.Stub
// ----------------------------------------------------------------
- // Keys are String (package name), values are Package. This also serves
- // as the lock for the global state. Methods that must be called with
- // this lock held have the prefix "LP".
- @GuardedBy("mPackages")
+ // Lock for global state used when modifying package state or settings.
+ // Methods that must be called with this lock held have
+ // the suffix "Locked". Some methods may use the legacy the suffix "LP"
+ final Object mLock;
+
+ // Keys are String (package name), values are Package.
+ @GuardedBy("mLock")
final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();
// Keys are isolated uids and values are the uid of the application
// that created the isolated proccess.
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
final SparseIntArray mIsolatedOwners = new SparseIntArray();
/**
@@ -692,7 +697,7 @@ public class PackageManagerService extends IPackageManager.Stub
*/
boolean mPromoteSystemApps;
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
final Settings mSettings;
/**
@@ -702,7 +707,7 @@ public class PackageManagerService extends IPackageManager.Stub
*
* @see PackageFreezer
*/
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
final ArraySet<String> mFrozenPackages = new ArraySet<>();
final ProtectedPackages mProtectedPackages;
@@ -719,31 +724,57 @@ public class PackageManagerService extends IPackageManager.Stub
private final InstantAppRegistry mInstantAppRegistry;
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
int mChangedPackagesSequenceNumber;
/**
* List of changed [installed, removed or updated] packages.
* mapping from user id -> sequence number -> package name
*/
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
final SparseArray<SparseArray<String>> mChangedPackages = new SparseArray<>();
/**
* The sequence number of the last change to a package.
* mapping from user id -> package name -> sequence number
*/
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
final SparseArray<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private final SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray();
private final ModuleInfoProvider mModuleInfoProvider;
private final ApexManager mApexManager;
+ private final Injector mInjector;
+
+ /**
+ * Unit tests will instantiate and / or extend to mock dependencies / behaviors.
+ */
+ @VisibleForTesting
+ static class Injector {
+ private final UserManagerInternal mUserManager;
+ private final PackageAbiHelper mAbiHelper;
+
+ Injector(UserManagerInternal userManager, PackageAbiHelper abiHelper) {
+ mUserManager = userManager;
+ mAbiHelper = abiHelper;
+ }
+
+ public UserManagerInternal getUserManager() {
+ return mUserManager;
+ }
+
+ public PackageAbiHelper getAbiHelper() {
+ return mAbiHelper;
+ }
+ }
+
+ private final AppsFilter mAppsFilter;
+
class PackageParserCallback implements PackageParser.Callback {
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -813,7 +844,7 @@ public class PackageManagerService extends IPackageManager.Stub
String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
List<PackageParser.Package> overlayPackages;
synchronized (mInstallLock) {
- synchronized (mPackages) {
+ synchronized (mLock) {
overlayPackages = getStaticOverlayPackages(
mPackages.values(), targetPackageName);
}
@@ -837,7 +868,7 @@ public class PackageManagerService extends IPackageManager.Stub
List<PackageParser.Package> mOverlayPackages = null;
void findStaticOverlayPackages() {
- synchronized (mPackages) {
+ synchronized (mLock) {
for (PackageParser.Package p : mPackages.values()) {
if (p.mOverlayIsStatic) {
if (mOverlayPackages == null) {
@@ -1021,7 +1052,7 @@ public class PackageManagerService extends IPackageManager.Stub
PackageParser.ActivityIntentInfo filter = filters.get(m);
domainsSet.addAll(filter.getHostsList());
}
- synchronized (mPackages) {
+ synchronized (mLock) {
if (mSettings.createIntentFilterVerificationIfNeededLPw(
packageName, domainsSet) != null) {
scheduleWriteSettingsLocked();
@@ -1089,7 +1120,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageName = ivs.getPackageName();
IntentFilterVerificationInfo ivi;
- synchronized (mPackages) {
+ synchronized (mLock) {
ivi = mSettings.getIntentFilterVerificationLPr(packageName);
}
if (ivi == null) {
@@ -1098,7 +1129,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
if (verified) {
ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS);
} else {
@@ -1210,7 +1241,7 @@ public class PackageManagerService extends IPackageManager.Stub
IntentFilterVerificationState ivs = new IntentFilterVerificationState(
verifierUid, userId, packageName);
ivs.setPendingState();
- synchronized (mPackages) {
+ synchronized (mLock) {
mIntentFilterVerificationStates.append(verificationId, ivs);
mCurrentIntentFilterVerifications.add(verificationId);
}
@@ -1423,7 +1454,7 @@ public class PackageManagerService extends IPackageManager.Stub
int size = 0;
int uids[];
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- synchronized (mPackages) {
+ synchronized (mLock) {
size = mPendingBroadcasts.size();
if (size <= 0) {
// Nothing to be done. Just return
@@ -1531,7 +1562,7 @@ public class PackageManagerService extends IPackageManager.Stub
} break;
case WRITE_SETTINGS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- synchronized (mPackages) {
+ synchronized (mLock) {
removeMessages(WRITE_SETTINGS);
removeMessages(WRITE_PACKAGE_RESTRICTIONS);
mSettings.writeLPr();
@@ -1541,7 +1572,7 @@ public class PackageManagerService extends IPackageManager.Stub
} break;
case WRITE_PACKAGE_RESTRICTIONS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- synchronized (mPackages) {
+ synchronized (mLock) {
removeMessages(WRITE_PACKAGE_RESTRICTIONS);
for (int userId : mDirtyUsers) {
mSettings.writePackageRestrictionsLPr(userId);
@@ -1552,7 +1583,7 @@ public class PackageManagerService extends IPackageManager.Stub
} break;
case WRITE_PACKAGE_LIST: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- synchronized (mPackages) {
+ synchronized (mLock) {
removeMessages(WRITE_PACKAGE_LIST);
mSettings.writePackageListLPr(msg.arg1);
}
@@ -1789,7 +1820,7 @@ public class PackageManagerService extends IPackageManager.Stub
res.pkg, callingUid);
}
- synchronized (mPackages) {
+ synchronized (mLock) {
mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
}
@@ -1950,7 +1981,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageIsBrowser(packageName, userId)) {
// If this browser is restored from user's backup, do not clear
// default-browser state for this user
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting.getInstallReason(userId)
!= PackageManager.INSTALL_REASON_DEVICE_RESTORE) {
@@ -2007,8 +2038,8 @@ public class PackageManagerService extends IPackageManager.Stub
// survive long enough to benefit of background optimizations.
for (int userId : firstUserIds) {
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
- // There's a race currently where some install events may interleave with an uninstall.
- // This can lead to package info being null (b/36642664).
+ // There's a race currently where some install events may interleave with an
+ // uninstall. This can lead to package info being null (b/36642664).
if (info != null) {
mDexManager.notifyPackageInstalled(info, userId);
}
@@ -2030,7 +2061,8 @@ public class PackageManagerService extends IPackageManager.Stub
for (String packageName : packages) {
PackageSetting setting = mSettings.mPackages.get(packageName);
- if (setting != null && filterAppAccessLPr(setting, callingUid, callingUserId)) {
+ if (setting != null
+ && shouldFilterApplicationLocked(setting, callingUid, callingUserId)) {
notifyInstallObserver(packageName);
}
}
@@ -2078,6 +2110,7 @@ public class PackageManagerService extends IPackageManager.Stub
* external/removable/unprotected storage.
* @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
* corresponding {@link StorageEnum} storage type value if it is.
+ * corresponding {@link StorageEnum} storage type value if it is.
*/
private static int getPackageExternalStorageType(VolumeInfo packageVolume,
boolean packageIsExternal) {
@@ -2130,7 +2163,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Remove any apps installed on the forgotten volume
- synchronized (mPackages) {
+ synchronized (mLock) {
final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(fsUuid);
for (PackageSetting ps : packages) {
Slog.d(TAG, "Destroying " + ps.name + " because volume was forgotten");
@@ -2206,9 +2239,10 @@ public class PackageManagerService extends IPackageManager.Stub
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
+ final Object packageLock = new Object();
PackageManagerService m = new PackageManagerService(context, installer,
- factoryTest, onlyCore);
+ factoryTest, onlyCore, packageLock);
m.enableSystemUserPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
@@ -2241,7 +2275,7 @@ public class PackageManagerService extends IPackageManager.Stub
List<String> allAps = queryHelper.queryApps(0, /* systemAppsOnly */ false,
UserHandle.SYSTEM);
final int allAppsSize = allAps.size();
- synchronized (mPackages) {
+ synchronized (mLock) {
for (int i = 0; i < allAppsSize; i++) {
String pName = allAps.get(i);
PackageSetting pkgSetting = mSettings.mPackages.get(pName);
@@ -2300,11 +2334,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
public PackageManagerService(Context context, Installer installer, boolean factoryTest,
- boolean onlyCore) {
+ boolean onlyCore, Object packageLock) {
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
Trace.TRACE_TAG_PACKAGE_MANAGER);
t.traceBegin("create package manager");
- LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
+ mLock = packageLock;
+ LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
@@ -2313,7 +2348,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
mContext = context;
-
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mMetrics = new DisplayMetrics();
@@ -2323,23 +2357,28 @@ public class PackageManagerService extends IPackageManager.Stub
t.traceBegin("createSubComponents");
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
- synchronized (mPackages) {
+ synchronized (mLock) {
// Expose private service for system components to use.
LocalServices.addService(
PackageManagerInternal.class, new PackageManagerInternalImpl());
sUserManager = new UserManagerService(context, this,
- new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
+ new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore),
+ mLock);
mComponentResolver = new ComponentResolver(sUserManager,
LocalServices.getService(PackageManagerInternal.class),
- mPackages);
+ mLock);
mPermissionManager = PermissionManagerService.create(context,
- mPackages /*externalLock*/);
+ mLock /*externalLock*/);
mPermissionManagerService =
(IPermissionManager) ServiceManager.getService("permissionmgr");
mSettings = new Settings(Environment.getDataDirectory(),
- mPermissionManager.getPermissionSettings(), mPackages);
+ mPermissionManager.getPermissionSettings(), mLock);
}
}
+
+ // TODO(b/137961986): We should pass this via constructor, but would first need to create
+ // a packages lock that could also be passed in.
+ mInjector = new Injector(getUserManagerInternal(), new PackageAbiHelperImpl());
// CHECKSTYLE:ON IndentationCheck
t.traceEnd();
@@ -2397,10 +2436,12 @@ public class PackageManagerService extends IPackageManager.Stub
mProtectedPackages = new ProtectedPackages(mContext);
mApexManager = ApexManager.create(context);
+ mAppsFilter = AppsFilter.create(context);
+
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
@@ -3048,7 +3089,9 @@ public class PackageManagerService extends IPackageManager.Stub
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
final List<String> changedAbiCodePath =
- adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
+ applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/,
+ mInjector.getAbiHelper().getAdjustedAbiForSharedUser(
+ setting.packages, null /*scannedPackage*/));
if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
final String codePathString = changedAbiCodePath.get(i);
@@ -3131,7 +3174,7 @@ public class PackageManagerService extends IPackageManager.Stub
int count = 0;
for (String pkgName : deferPackages) {
PackageParser.Package pkg = null;
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting ps = mSettings.getPackageLPr(pkgName);
if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
pkg = ps.pkg;
@@ -3278,7 +3321,7 @@ public class PackageManagerService extends IPackageManager.Stub
MetricsLogger.histogram(null, "ota_package_manager_init_time",
(int) (SystemClock.uptimeMillis() - startTime));
}
- } // synchronized (mPackages)
+ } // synchronized (mLock)
} // synchronized (mInstallLock)
// CHECKSTYLE:ON IndentationCheck
@@ -3294,7 +3337,7 @@ public class PackageManagerService extends IPackageManager.Stub
// The initial scanning above does many calls into installd while
// holding the mPackages lock, but we're mostly interested in yelling
// once we have a booted system.
- mInstaller.setWarnIfHeld(mPackages);
+ mInstaller.setWarnIfHeld(mLock);
PackageParser.readConfigUseRoundIcon(mContext.getResources());
@@ -3376,7 +3419,7 @@ public class PackageManagerService extends IPackageManager.Stub
try (PackageFreezer freezer =
freezePackage(stubPkg.packageName, "setEnabledSetting")) {
pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
- synchronized (mPackages) {
+ synchronized (mLock) {
prepareAppDataAfterInstallLIF(pkg);
try {
updateSharedLibrariesLocked(pkg, null, mPackages);
@@ -3390,7 +3433,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Whoops! Something went very wrong; roll back to the stub and disable the package
try (PackageFreezer freezer =
freezePackage(stubPkg.packageName, "setEnabledSetting")) {
- synchronized (mPackages) {
+ synchronized (mLock) {
// NOTE: Ensure the system package is enabled; even for a compressed stub.
// If we don't, installing the system package fails during scan
enableSystemPackageLPw(stubPkg);
@@ -3403,7 +3446,7 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.packageName, pme);
} finally {
// Disable the package; the stub by itself is not runnable
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
if (stubPs != null) {
stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
@@ -3433,7 +3476,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (scanFile == null) {
throw new PackageManagerException("Unable to decompress stub at " + stubPkg.codePath);
}
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.disableSystemPackageLPw(stubPkg.packageName, true /*replaced*/);
}
removePackageLI(stubPkg, true /*chatty*/);
@@ -3510,7 +3553,7 @@ public class PackageManagerService extends IPackageManager.Stub
return dstCodePath;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void updateInstantAppInstallerLocked(String modifiedPackage) {
// we're only interested in updating the installer appliction when 1) it's not
// already set or 2) the modified package is the installer
@@ -3631,7 +3674,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private @NonNull String getRequiredSharedLibraryLPr(String name, int version) {
- synchronized (mPackages) {
+ synchronized (mLock) {
SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(name, version);
if (libraryInfo == null) {
throw new IllegalStateException("Missing required shared library:" + name);
@@ -3731,7 +3774,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
final Pair<ComponentName, String> instantAppResolver = getInstantAppResolverLPr();
if (instantAppResolver == null) {
return null;
@@ -3796,7 +3839,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private @Nullable ActivityInfo getInstantAppInstallerLPr() {
String[] orderedActions = Build.IS_ENG
? new String[]{
@@ -3863,7 +3906,7 @@ public class PackageManagerService extends IPackageManager.Stub
return matches.get(0).getComponentInfo().getComponentName();
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void primeDomainVerificationsLPw(int userId) {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.d(TAG, "Priming domain verifications in user " + userId);
@@ -3993,7 +4036,7 @@ public class PackageManagerService extends IPackageManager.Stub
// and 2) ephemeral apps that have explicitly interacted with it
// * Ephemeral apps can only see their own data and exposed installed apps
// * Holding a signature permission allows seeing instant apps
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return null;
}
@@ -4058,9 +4101,9 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException("Instant applications don't have access to this method");
}
final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId);
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
throw new SecurityException("Package " + packageName + " was not found!");
}
@@ -4089,11 +4132,11 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "is package available");
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Package p = mPackages.get(packageName);
if (p != null) {
final PackageSetting ps = (PackageSetting) p.mExtras;
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return false;
}
if (ps != null) {
@@ -4134,7 +4177,7 @@ public class PackageManagerService extends IPackageManager.Stub
false /* requireFullPermission */, false /* checkShell */, "get package info");
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
// Normalize package name to handle renamed packages and static libs
packageName = resolveInternalPackageNameLPr(packageName, versionCode);
@@ -4150,7 +4193,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
- if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
@@ -4168,7 +4211,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
- if (ps != null && filterAppAccessLPr(ps, filterCallingUid, userId)) {
+ if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
@@ -4179,7 +4222,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
- if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
@@ -4250,8 +4293,8 @@ public class PackageManagerService extends IPackageManager.Stub
*
* @see #canViewInstantApps(int, int)
*/
- @GuardedBy("mPackages")
- private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid,
+ @GuardedBy("mLock")
+ private boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid,
@Nullable ComponentName component, @ComponentType int componentType, int userId) {
// if we're in an isolated process, get the real calling UID
if (Process.isIsolated(callingUid)) {
@@ -4302,18 +4345,21 @@ public class PackageManagerService extends IPackageManager.Stub
return !mInstantAppRegistry.isInstantAccessGranted(
userId, UserHandle.getAppId(callingUid), ps.appId);
}
- return false;
+ int appId = UserHandle.getAppId(callingUid);
+ final SettingBase callingPs = mSettings.getSettingLPr(appId);
+ return mAppsFilter.shouldFilterApplication(callingUid, callingPs, ps, userId);
}
/**
- * @see #filterAppAccessLPr(PackageSetting, int, ComponentName, int, int)
+ * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int)
*/
- @GuardedBy("mPackages")
- private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid, int userId) {
- return filterAppAccessLPr(ps, callingUid, null, TYPE_UNKNOWN, userId);
+ @GuardedBy("mLock")
+ private boolean shouldFilterApplicationLocked(
+ @Nullable PackageSetting ps, int callingUid, int userId) {
+ return shouldFilterApplicationLocked(ps, callingUid, null, TYPE_UNKNOWN, userId);
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
int flags) {
// Callers can access only the libs they depend on, otherwise they need to explicitly
@@ -4376,7 +4422,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final String[] out = new String[names.length];
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final int callingUserId = UserHandle.getUserId(callingUid);
final boolean canViewInstantApps = canViewInstantApps(callingUid, callingUserId);
for (int i=names.length-1; i>=0; i--) {
@@ -4403,7 +4449,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final String[] out = new String[names.length];
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final int callingUserId = UserHandle.getUserId(callingUid);
final boolean canViewInstantApps = canViewInstantApps(callingUid, callingUserId);
for (int i=names.length-1; i>=0; i--) {
@@ -4433,11 +4479,11 @@ public class PackageManagerService extends IPackageManager.Stub
false /*requireFullPermission*/, false /*checkShell*/, "getPackageUid");
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.Package p = mPackages.get(packageName);
if (p != null && p.isMatch(flags)) {
PackageSetting ps = (PackageSetting) p.mExtras;
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return -1;
}
return UserHandle.getUid(userId, p.applicationInfo.uid);
@@ -4445,7 +4491,7 @@ public class PackageManagerService extends IPackageManager.Stub
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null && ps.isMatch(flags)
- && !filterAppAccessLPr(ps, callingUid, userId)) {
+ && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
return UserHandle.getUid(userId, ps.appId);
}
}
@@ -4463,11 +4509,11 @@ public class PackageManagerService extends IPackageManager.Stub
false /*requireFullPermission*/, false /*checkShell*/, "getPackageGids");
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.Package p = mPackages.get(packageName);
if (p != null && p.isMatch(flags)) {
PackageSetting ps = (PackageSetting) p.mExtras;
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return null;
}
// TODO: Shouldn't this be checking for package installed state for userId and
@@ -4477,7 +4523,7 @@ public class PackageManagerService extends IPackageManager.Stub
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null && ps.isMatch(flags)
- && !filterAppAccessLPr(ps, callingUid, userId)) {
+ && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
return ps.getPermissionsState().computeGids(userId);
}
}
@@ -4497,7 +4543,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
@@ -4506,7 +4552,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
- if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
if (ps.pkg == null) {
@@ -4549,7 +4595,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
// Normalize package name to handle renamed packages and static libs
packageName = resolveInternalPackageNameLPr(packageName,
PackageManager.VERSION_CODE_HIGHEST);
@@ -4564,7 +4610,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
- if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
return null;
}
// Note: isEnabledLP() does not apply here - always return info
@@ -4587,7 +4633,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private String normalizePackageNameLPr(String packageName) {
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
return normalizedPackageName != null ? normalizedPackageName : packageName;
@@ -4742,7 +4788,7 @@ public class PackageManagerService extends IPackageManager.Stub
List<VersionedPackage> packagesToDelete = null;
final long now = System.currentTimeMillis();
- synchronized (mPackages) {
+ synchronized (mLock) {
final int[] allUsers = sUserManager.getUserIds();
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
@@ -4980,14 +5026,15 @@ public class PackageManagerService extends IPackageManager.Stub
false /* requireFullPermission */, false /* checkShell */, "get activity info");
}
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Activity a = mComponentResolver.getActivity(component);
if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- if (filterAppAccessLPr(ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
+ if (shouldFilterApplicationLocked(
+ ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
return null;
}
return PackageParser.generateActivityInfo(
@@ -5020,7 +5067,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean activitySupportsIntent(ComponentName component, Intent intent,
String resolvedType) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if (component.equals(mResolveComponentName)) {
// The resolver supports EVERYTHING!
return true;
@@ -5035,7 +5082,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (ps == null) {
return false;
}
- if (filterAppAccessLPr(ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) {
return false;
}
for (int i=0; i<a.intents.size(); i++) {
@@ -5055,14 +5103,15 @@ public class PackageManagerService extends IPackageManager.Stub
flags = updateFlagsForComponent(flags, userId, component);
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get receiver info");
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Activity a = mComponentResolver.getReceiver(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getReceiverInfo " + component + ": " + a);
if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- if (filterAppAccessLPr(ps, callingUid, component, TYPE_RECEIVER, userId)) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, component, TYPE_RECEIVER, userId)) {
return null;
}
return PackageParser.generateActivityInfo(
@@ -5096,7 +5145,7 @@ public class PackageManagerService extends IPackageManager.Stub
|| mContext.checkCallingOrSelfPermission(
Manifest.permission.ACCESS_SHARED_LIBRARIES) == PERMISSION_GRANTED;
- synchronized (mPackages) {
+ synchronized (mLock) {
List<SharedLibraryInfo> result = null;
final int libCount = mSharedLibraries.size();
@@ -5165,7 +5214,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
List<SharedLibraryInfo> result = null;
int libraryCount = mSharedLibraries.size();
@@ -5214,7 +5263,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private List<VersionedPackage> getPackagesUsingSharedLibraryLPr(
SharedLibraryInfo libInfo, int flags, int userId) {
List<VersionedPackage> versionedPackages = null;
@@ -5269,14 +5318,15 @@ public class PackageManagerService extends IPackageManager.Stub
flags = updateFlagsForComponent(flags, userId, component);
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get service info");
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Service s = mComponentResolver.getService(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getServiceInfo " + component + ": " + s);
if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- if (filterAppAccessLPr(ps, callingUid, component, TYPE_SERVICE, userId)) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, component, TYPE_SERVICE, userId)) {
return null;
}
return PackageParser.generateServiceInfo(
@@ -5293,14 +5343,15 @@ public class PackageManagerService extends IPackageManager.Stub
flags = updateFlagsForComponent(flags, userId, component);
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get provider info");
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Provider p = mComponentResolver.getProvider(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getProviderInfo " + component + ": " + p);
if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, component, TYPE_PROVIDER, userId)) {
return null;
}
return PackageParser.generateProviderInfo(
@@ -5323,7 +5374,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String[] getSystemSharedLibraryNames() {
// allow instant applications
- synchronized (mPackages) {
+ synchronized (mLock) {
Set<String> libs = null;
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
@@ -5367,7 +5418,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public @NonNull String getServicesSystemSharedLibraryPackageName() {
// allow instant applications
- synchronized (mPackages) {
+ synchronized (mLock) {
return mServicesSystemSharedLibraryPackageName;
}
}
@@ -5375,12 +5426,12 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public @NonNull String getSharedSystemSharedLibraryPackageName() {
// allow instant applications
- synchronized (mPackages) {
+ synchronized (mLock) {
return mSharedSystemSharedLibraryPackageName;
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
for (int i = userList.length - 1; i >= 0; --i) {
final int userId = userList[i];
@@ -5413,7 +5464,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
if (sequenceNumber >= mChangedPackagesSequenceNumber) {
return null;
}
@@ -5487,13 +5538,13 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String getPermissionControllerPackageName() {
- synchronized (mPackages) {
+ synchronized (mLock) {
return mRequiredPermissionControllerPackage;
}
}
String getPackageInstallerPackageName() {
- synchronized (mPackages) {
+ synchronized (mLock) {
return mRequiredInstallerPackage;
}
}
@@ -5561,7 +5612,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public int checkSignatures(String pkg1, String pkg2) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.Package p1 = mPackages.get(pkg1);
final PackageParser.Package p2 = mPackages.get(pkg2);
if (p1 == null || p1.mExtras == null
@@ -5572,8 +5623,8 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUserId = UserHandle.getUserId(callingUid);
final PackageSetting ps1 = (PackageSetting) p1.mExtras;
final PackageSetting ps2 = (PackageSetting) p2.mExtras;
- if (filterAppAccessLPr(ps1, callingUid, callingUserId)
- || filterAppAccessLPr(ps2, callingUid, callingUserId)) {
+ if (shouldFilterApplicationLocked(ps1, callingUid, callingUserId)
+ || shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures);
@@ -5589,7 +5640,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int appId1 = UserHandle.getAppId(uid1);
final int appId2 = UserHandle.getAppId(uid2);
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
Signature[] s1;
Signature[] s2;
Object obj = mSettings.getSettingLPr(appId1);
@@ -5601,7 +5652,7 @@ public class PackageManagerService extends IPackageManager.Stub
s1 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
s1 = ps.signatures.mSigningDetails.signatures;
@@ -5620,7 +5671,7 @@ public class PackageManagerService extends IPackageManager.Stub
s2 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
s2 = ps.signatures.mSigningDetails.signatures;
@@ -5638,7 +5689,7 @@ public class PackageManagerService extends IPackageManager.Stub
public boolean hasSigningCertificate(
String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.Package p = mPackages.get(packageName);
if (p == null || p.mExtras == null) {
return false;
@@ -5646,7 +5697,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final PackageSetting ps = (PackageSetting) p.mExtras;
- if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return false;
}
switch (type) {
@@ -5668,7 +5719,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Map to base uids.
final int appId = UserHandle.getAppId(uid);
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.SigningDetails signingDetails;
final Object obj = mSettings.getSettingLPr(appId);
if (obj != null) {
@@ -5680,7 +5731,7 @@ public class PackageManagerService extends IPackageManager.Stub
signingDetails = ((SharedUserSetting)obj).signatures.mSigningDetails;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return false;
}
signingDetails = ps.signatures.mSigningDetails;
@@ -5726,7 +5777,7 @@ public class PackageManagerService extends IPackageManager.Stub
public List<String> getAllPackages() {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- synchronized (mPackages) {
+ synchronized (mLock) {
if (canViewInstantApps(callingUid, callingUserId)) {
return new ArrayList<>(mPackages.keySet());
}
@@ -5775,7 +5826,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int userId = UserHandle.getUserId(uid);
final int appId = UserHandle.getAppId(uid);
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
@@ -5797,7 +5848,8 @@ public class PackageManagerService extends IPackageManager.Stub
return res;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (ps.getInstalled(userId) && !filterAppAccessLPr(ps, callingUid, userId)) {
+ if (ps.getInstalled(userId)
+ && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
return new String[]{ps.name};
}
}
@@ -5812,14 +5864,15 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
final int appId = UserHandle.getAppId(uid);
- synchronized (mPackages) {
+ synchronized (mLock) {
final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.name + ":" + sus.userId;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, UserHandle.getUserId(callingUid))) {
return null;
}
return ps.name;
@@ -5838,7 +5891,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
final String[] names = new String[uids.length];
- synchronized (mPackages) {
+ synchronized (mLock) {
for (int i = uids.length - 1; i >= 0; i--) {
final int appId = UserHandle.getAppId(uids[i]);
final Object obj = mSettings.getSettingLPr(appId);
@@ -5847,7 +5900,8 @@ public class PackageManagerService extends IPackageManager.Stub
names[i] = "shared:" + sus.name;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, UserHandle.getUserId(callingUid))) {
names[i] = null;
} else {
names[i] = ps.name;
@@ -5869,7 +5923,7 @@ public class PackageManagerService extends IPackageManager.Stub
return -1;
}
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
SharedUserSetting suid;
try {
suid = mSettings.getSharedUserLPw(sharedUserName, 0, 0, false);
@@ -5890,14 +5944,15 @@ public class PackageManagerService extends IPackageManager.Stub
return 0;
}
final int appId = UserHandle.getAppId(uid);
- synchronized (mPackages) {
+ synchronized (mLock) {
final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.pkgFlags;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, UserHandle.getUserId(callingUid))) {
return 0;
}
return ps.pkgFlags;
@@ -5913,14 +5968,15 @@ public class PackageManagerService extends IPackageManager.Stub
return 0;
}
final int appId = UserHandle.getAppId(uid);
- synchronized (mPackages) {
+ synchronized (mLock) {
final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.pkgPrivateFlags;
} else if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
- if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, UserHandle.getUserId(callingUid))) {
return 0;
}
return ps.pkgPrivateFlags;
@@ -5936,7 +5992,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final int appId = UserHandle.getAppId(uid);
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
@@ -6017,7 +6073,7 @@ public class PackageManagerService extends IPackageManager.Stub
0, userId, intent, callingUid, false /*includeInstantApps*/);
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
userId);
- synchronized (mPackages) {
+ synchronized (mLock) {
return findPersistentPreferredActivityLP(intent, resolvedType, flags, query, false,
userId);
}
@@ -6104,7 +6160,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
// Or if there's already an ephemeral app installed that handles the action
- synchronized (mPackages) {
+ synchronized (mLock) {
final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
for (int n = 0; n < count; n++) {
final ResolveInfo info = resolvedActivities.get(n);
@@ -6246,7 +6302,7 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
final int N = query.size();
@@ -6316,7 +6372,7 @@ public class PackageManagerService extends IPackageManager.Stub
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
List<ResolveInfo> query, int priority, boolean always,
boolean removeMatches, boolean debug, int userId) {
- if (Thread.holdsLock(mPackages)) {
+ if (Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mPackages", new Throwable());
}
@@ -6331,7 +6387,7 @@ public class PackageManagerService extends IPackageManager.Stub
flags, userId, intent, callingUid, false /*includeInstantApps*/);
intent = updateIntentForResolve(intent);
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
// Try to find a matching persistent preferred activity.
ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query,
debug, userId);
@@ -6535,7 +6591,7 @@ public class PackageManagerService extends IPackageManager.Stub
// cross-profile app linking works only towards the parent.
final int callingUid = Binder.getCallingUid();
final UserInfo parent = getProfileParent(sourceUserId);
- synchronized(mPackages) {
+ synchronized (mLock) {
int flags = updateFlagsForResolve(0, parent.id, intent, callingUid,
false /*includeInstantApps*/);
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
@@ -6582,7 +6638,7 @@ public class PackageManagerService extends IPackageManager.Stub
* instant, returns {@code null}.
*/
private String getInstantAppPackageName(int callingUid) {
- synchronized (mPackages) {
+ synchronized (mLock) {
// If the caller is an isolated app use the owner's uid for the lookup.
if (Process.isIsolated(callingUid)) {
callingUid = mIsolatedOwners.get(callingUid);
@@ -6673,7 +6729,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean sortResult = false;
boolean addInstant = false;
List<ResolveInfo> result;
- synchronized (mPackages) {
+ synchronized (mLock) {
if (pkgName == null) {
List<CrossProfileIntentFilter> matchingFilters =
getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
@@ -7112,7 +7168,7 @@ public class PackageManagerService extends IPackageManager.Stub
final ArrayList<ResolveInfo> neverList = new ArrayList<>();
final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
- synchronized (mPackages) {
+ synchronized (mLock) {
final int count = candidates.size();
// First, try to use linked apps. Partition the candidates into four lists:
// one for the final results, one for the "do not use ever", one for "undefined status"
@@ -7631,7 +7687,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
String pkgName = intent.getPackage();
if (pkgName == null) {
final List<ResolveInfo> result =
@@ -7735,7 +7791,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
String pkgName = intent.getPackage();
if (pkgName == null) {
return applyPostServiceResolutionFilter(
@@ -7853,7 +7909,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
String pkgName = intent.getPackage();
if (pkgName == null) {
return applyPostContentProviderResolutionFilter(
@@ -7931,7 +7987,7 @@ public class PackageManagerService extends IPackageManager.Stub
"get installed packages");
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
ArrayList<PackageInfo> list;
if (listUninstalled) {
list = new ArrayList<>(mSettings.mPackages.size());
@@ -7939,7 +7995,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
final PackageInfo pi = generatePackageInfo(ps, flags, userId);
@@ -7954,7 +8010,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
final PackageInfo pi = generatePackageInfo((PackageSetting)
@@ -8028,7 +8084,7 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
ArrayList<PackageInfo> list = new ArrayList<>();
boolean[] tmpBools = new boolean[permissions.length];
if (listUninstalled) {
@@ -8074,7 +8130,7 @@ public class PackageManagerService extends IPackageManager.Stub
"get installed application info");
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
ArrayList<ApplicationInfo> list;
if (listUninstalled) {
list = new ArrayList<>(mSettings.mPackages.size());
@@ -8088,7 +8144,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
@@ -8114,7 +8170,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
continue;
}
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
continue;
}
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
@@ -8143,7 +8199,7 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getEphemeralApplications");
- synchronized (mPackages) {
+ synchronized (mLock) {
List<InstantAppInfo> instantApps = mInstantAppRegistry
.getInstantAppsLPr(userId);
if (instantApps != null) {
@@ -8162,7 +8218,7 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
int callingUid = Binder.getCallingUid();
if (Process.isIsolated(callingUid)) {
callingUid = mIsolatedOwners.get(callingUid);
@@ -8194,7 +8250,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
return null;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
return mInstantAppRegistry.getInstantAppCookieLPw(
packageName, userId);
}
@@ -8212,7 +8268,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
return false;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
return mInstantAppRegistry.setInstantAppCookieLPw(
packageName, cookie, userId);
}
@@ -8232,7 +8288,7 @@ public class PackageManagerService extends IPackageManager.Stub
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppIcon");
- synchronized (mPackages) {
+ synchronized (mLock) {
return mInstantAppRegistry.getInstantAppIconLPw(
packageName, userId);
}
@@ -8256,7 +8312,7 @@ public class PackageManagerService extends IPackageManager.Stub
final ArrayList<ApplicationInfo> finalList = new ArrayList<>();
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final Iterator<PackageParser.Package> i = mPackages.values().iterator();
final int userId = UserHandle.getCallingUserId();
while (i.hasNext()) {
@@ -8302,11 +8358,11 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
return null;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
final ComponentName component =
new ComponentName(providerInfo.packageName, providerInfo.name);
- if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, component, TYPE_PROVIDER, userId)) {
return null;
}
return providerInfo;
@@ -8337,7 +8393,7 @@ public class PackageManagerService extends IPackageManager.Stub
final List<ProviderInfo> matchList =
mComponentResolver.queryProviders(processName, metaDataKey, uid, flags, userId);
final int listSize = (matchList == null ? 0 : matchList.size());
- synchronized (mPackages) {
+ synchronized (mLock) {
for (int i = 0; i < listSize; i++) {
final ProviderInfo providerInfo = matchList.get(i);
if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
@@ -8346,7 +8402,8 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
final ComponentName component =
new ComponentName(providerInfo.packageName, providerInfo.name);
- if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, component, TYPE_PROVIDER, userId)) {
continue;
}
if (finalList == null) {
@@ -8367,12 +8424,13 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public InstrumentationInfo getInstrumentationInfo(ComponentName component, int flags) {
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- if (filterAppAccessLPr(ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
return null;
}
final PackageParser.Instrumentation i = mInstrumentation.get(component);
@@ -8386,7 +8444,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final PackageSetting ps = mSettings.mPackages.get(targetPackage);
- if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return ParceledListSlice.emptyList();
}
return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
@@ -8397,7 +8455,7 @@ public class PackageManagerService extends IPackageManager.Stub
ArrayList<InstrumentationInfo> finalList = new ArrayList<>();
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
while (i.hasNext()) {
final PackageParser.Instrumentation p = i.next();
@@ -8562,7 +8620,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Traces a package scan.
* @see #scanPackageLI(File, int, int, long, UserHandle)
*/
- @GuardedBy({"mInstallLock", "mPackages"})
+ @GuardedBy({"mInstallLock", "mLock"})
private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
@@ -8577,7 +8635,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Scans a package and returns the newly parsed package.
* Returns {@code null} in case of errors and the error code is stored in mLastScanError
*/
- @GuardedBy({"mInstallLock", "mPackages"})
+ @GuardedBy({"mInstallLock", "mLock"})
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
@@ -8609,7 +8667,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Scans a package and returns the newly parsed package.
* @throws PackageManagerException on a parse error.
*/
- @GuardedBy({"mInstallLock", "mPackages"})
+ @GuardedBy({"mInstallLock", "mLock"})
private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
@@ -8705,7 +8763,7 @@ public class PackageManagerService extends IPackageManager.Stub
* structures and the package is made available to the rest of the system.
* <p>NOTE: The return value should be removed. It's the passed in package object.
*/
- @GuardedBy({"mInstallLock", "mPackages"})
+ @GuardedBy({"mInstallLock", "mLock"})
private PackageParser.Package addForInitLI(PackageParser.Package pkg,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
@@ -8730,7 +8788,7 @@ public class PackageManagerService extends IPackageManager.Stub
pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
- synchronized (mPackages) {
+ synchronized (mLock) {
renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
final String realPkgName = getRealPackageName(pkg, renamedPkgName);
if (realPkgName != null) {
@@ -8791,7 +8849,8 @@ public class PackageManagerService extends IPackageManager.Stub
null /* originalPkgSetting */, null, parseFlags, scanFlags,
(pkg == mPlatformPackage), user);
applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
- final ScanResult scanResult = scanPackageOnlyLI(request, mFactoryTest, -1L);
+ final ScanResult scanResult =
+ scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
}
@@ -8810,7 +8869,7 @@ public class PackageManagerService extends IPackageManager.Stub
// /data. Switch back to the application on /system.
// It's safe to assume the application on /system will correctly scan. If not,
// there won't be a working copy of the application.
- synchronized (mPackages) {
+ synchronized (mLock) {
// just remove the loaded entries from package lists
mPackages.remove(pkgSetting.name);
}
@@ -8825,7 +8884,7 @@ public class PackageManagerService extends IPackageManager.Stub
pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
args.cleanUpResourcesLI();
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.enableSystemPackageLPw(pkgSetting.name);
}
}
@@ -8914,7 +8973,7 @@ public class PackageManagerService extends IPackageManager.Stub
final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);
if (scanResult.success) {
- synchronized (mPackages) {
+ synchronized (mLock) {
boolean appIdCreated = false;
try {
final String pkgName = scanResult.pkgSetting.name;
@@ -8940,7 +8999,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (shouldHideSystemApp) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.disableSystemPackageLPw(pkg.packageName, true);
}
}
@@ -9011,7 +9070,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (doTrim) {
final boolean dexOptDialogShown;
- synchronized (mPackages) {
+ synchronized (mLock) {
dexOptDialogShown = mDexOptDialogShown;
}
if (!isFirstBoot() && dexOptDialogShown) {
@@ -9052,7 +9111,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
List<PackageParser.Package> pkgs;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}
@@ -9180,7 +9239,7 @@ public class PackageManagerService extends IPackageManager.Stub
numberOfPackagesVisited, numberOfPackagesToDexopt), true);
} catch (RemoteException e) {
}
- synchronized (mPackages) {
+ synchronized (mLock) {
mDexOptDialogShown = true;
}
}
@@ -9233,7 +9292,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void notifyPackageUse(String packageName, int reason) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
if (getInstantAppPackageName(callingUid) != null) {
@@ -9249,7 +9308,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void notifyPackageUseLocked(String packageName, int reason) {
final PackageParser.Package p = mPackages.get(packageName);
if (p == null) {
@@ -9336,7 +9395,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean compileLayouts(String packageName) {
PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
return false;
@@ -9383,7 +9442,7 @@ public class PackageManagerService extends IPackageManager.Stub
// if the package can now be considered up to date for the given filter.
private int performDexOptInternal(DexoptOptions options) {
PackageParser.Package p;
- synchronized (mPackages) {
+ synchronized (mLock) {
p = mPackages.get(options.getPackageName());
if (p == null) {
// Package could not be found. Report failure.
@@ -9404,7 +9463,7 @@ public class PackageManagerService extends IPackageManager.Stub
public ArraySet<String> getOptimizablePackages() {
ArraySet<String> pkgs = new ArraySet<>();
- synchronized (mPackages) {
+ synchronized (mLock) {
for (PackageParser.Package p : mPackages.values()) {
if (PackageDexOptimizer.canOptimizePackage(p)) {
pkgs.add(p.packageName);
@@ -9439,7 +9498,7 @@ public class PackageManagerService extends IPackageManager.Stub
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
for (SharedLibraryInfo info : deps) {
PackageParser.Package depPackage = null;
- synchronized (mPackages) {
+ synchronized (mLock) {
depPackage = mPackages.get(info.getPackageName());
}
if (depPackage != null) {
@@ -9527,7 +9586,7 @@ public class PackageManagerService extends IPackageManager.Stub
List<SharedLibraryInfo> deps = findSharedLibraries(pkg);
if (!deps.isEmpty()) {
ArrayList<PackageParser.Package> retValue = new ArrayList<>();
- synchronized (mPackages) {
+ synchronized (mLock) {
for (SharedLibraryInfo info : deps) {
PackageParser.Package depPackage = mPackages.get(info.getPackageName());
if (depPackage != null) {
@@ -9591,7 +9650,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Nullable
private PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
PackageSetting sharedLibPackage = null;
- synchronized (mPackages) {
+ synchronized (mLock) {
final SharedLibraryInfo latestSharedLibraVersionLPr =
getLatestSharedLibraVersionLPr(scanResult.pkgSetting.pkg);
if (latestSharedLibraVersionLPr != null) {
@@ -9609,7 +9668,7 @@ public class PackageManagerService extends IPackageManager.Stub
PackageWatchdog.getInstance(mContext).writeNow();
// This is the last chance to write out pending restriction settings
- synchronized (mPackages) {
+ synchronized (mLock) {
if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
for (int userId : mDirtyUsers) {
@@ -9623,7 +9682,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void dumpProfiles(String packageName) {
PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -9649,7 +9708,7 @@ public class PackageManagerService extends IPackageManager.Stub
enforceSystemOrRoot("forceDexOpt");
PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -9674,7 +9733,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
Slog.w(TAG, "Unable to update from " + oldPkg.name
@@ -9725,7 +9784,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
final PackageSetting ps;
- synchronized (mPackages) {
+ synchronized (mLock) {
ps = mSettings.mPackages.get(pkg.packageName);
}
for (int realUserId : resolveUserIds(userId)) {
@@ -9753,7 +9812,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void destroyAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
final PackageSetting ps;
- synchronized (mPackages) {
+ synchronized (mLock) {
ps = mSettings.mPackages.get(pkg.packageName);
}
for (int realUserId : resolveUserIds(userId)) {
@@ -9820,7 +9879,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void applyDefiningSharedLibraryUpdateLocked(
PackageParser.Package pkg, SharedLibraryInfo libInfo,
BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
@@ -9849,7 +9908,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
if (libInfo.getPath() != null) {
@@ -9878,7 +9937,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void updateSharedLibrariesLocked(PackageParser.Package pkg,
PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages)
throws PackageManagerException {
@@ -9940,7 +9999,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(
@NonNull List<String> requestedLibraries,
@Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests,
@@ -10050,7 +10109,7 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked(
PackageParser.Package updatedPkg,
Map<String, PackageParser.Package> availablePackages) {
@@ -10110,7 +10169,7 @@ public class PackageManagerService extends IPackageManager.Stub
return resultList;
}
- @GuardedBy({"mInstallLock", "mPackages"})
+ @GuardedBy({"mInstallLock", "mLock"})
private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user) throws PackageManagerException {
@@ -10151,7 +10210,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
/** The result of a package scan. */
- private static class ScanResult {
+ @VisibleForTesting
+ static class ScanResult {
/** The request that initiated the scan that produced this result. */
public final ScanRequest request;
/** Whether or not the package scan was successful */
@@ -10190,7 +10250,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
/** A package to be scanned */
- private static class ScanRequest {
+ @VisibleForTesting
+ static class ScanRequest {
/** The parsed package */
@NonNull public final PackageParser.Package pkg;
/** The package this package replaces */
@@ -10325,7 +10386,7 @@ public class PackageManagerService extends IPackageManager.Stub
// TODO(b/72378145) Fix this exemption. Force signature apps
// to whitelist their privileged permissions just like other
// priv-apps.
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) {
@@ -10342,7 +10403,7 @@ public class PackageManagerService extends IPackageManager.Stub
// the results / removing app data needs to be moved up a level to the callers of this
// method. Also, we need to solve the problem of potentially creating a new shared user
// setting. That can probably be done later and patch things up after the fact.
- @GuardedBy({"mInstallLock", "mPackages"})
+ @GuardedBy({"mInstallLock", "mLock"})
private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user) throws PackageManagerException {
@@ -10363,7 +10424,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);
- synchronized (mPackages) {
+ synchronized (mLock) {
applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
assertPackageIsValid(pkg, parseFlags, scanFlags);
@@ -10383,7 +10444,7 @@ public class PackageManagerService extends IPackageManager.Stub
pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
originalPkgSetting, realPkgName, parseFlags, scanFlags,
(pkg == mPlatformPackage), user);
- return scanPackageOnlyLI(request, mFactoryTest, currentTime);
+ return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
}
}
@@ -10424,7 +10485,7 @@ public class PackageManagerService extends IPackageManager.Stub
* This needs to be fixed so, once we get to this point, no errors are
* possible and the system is not left in an inconsistent state.
*/
- @GuardedBy({"mPackages", "mInstallLock"})
+ @GuardedBy({"mLock", "mInstallLock"})
private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) {
final ScanResult result = reconciledPkg.scanResult;
final ScanRequest request = result.request;
@@ -10512,7 +10573,7 @@ public class PackageManagerService extends IPackageManager.Stub
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
if (oldPkgSetting != null) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting);
}
}
@@ -10553,7 +10614,7 @@ public class PackageManagerService extends IPackageManager.Stub
* <p>An original package must be signed identically and it must have the same
* shared user [if any].
*/
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private @Nullable PackageSetting getOriginalPackageLocked(@NonNull PackageParser.Package pkg,
@Nullable String renamedPkgName) {
if (!isPackageRenamed(pkg, renamedPkgName)) {
@@ -10604,20 +10665,70 @@ public class PackageManagerService extends IPackageManager.Stub
}
/**
+ * Applies the adjusted ABI calculated by
+ * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all
+ * relevant packages and settings.
+ * @param sharedUserSetting The {@code SharedUserSetting} to adjust
+ * @param scannedPackage the package being scanned or null
+ * @param adjustedAbi the adjusted ABI calculated by {@link PackageAbiHelper}
+ * @return the list of code paths that belong to packages that had their ABIs adjusted.
+ */
+ private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
+ PackageParser.Package scannedPackage, String adjustedAbi) {
+ if (scannedPackage != null) {
+ scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
+ }
+ List<String> changedAbiCodePath = null;
+ for (PackageSetting ps : sharedUserSetting.packages) {
+ if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
+ if (ps.primaryCpuAbiString != null) {
+ continue;
+ }
+
+ ps.primaryCpuAbiString = adjustedAbi;
+ if (ps.pkg != null && ps.pkg.applicationInfo != null
+ && !TextUtils.equals(
+ adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
+ ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
+ if (DEBUG_ABI_SELECTION) {
+ Slog.i(TAG,
+ "Adjusting ABI for " + ps.name + " to " + adjustedAbi
+ + " (scannedPackage="
+ + (scannedPackage != null ? scannedPackage : "null")
+ + ")");
+ }
+ if (changedAbiCodePath == null) {
+ changedAbiCodePath = new ArrayList<>();
+ }
+ changedAbiCodePath.add(ps.codePathString);
+ }
+ }
+ }
+ return changedAbiCodePath;
+ }
+
+
+ /**
* Just scans the package without any side effects.
* <p>Not entirely true at the moment. There is still one side effect -- this
* method potentially modifies a live {@link PackageSetting} object representing
* the package being scanned. This will be resolved in the future.
*
+ * @param injector injector for acquiring dependencies
* @param request Information about the package to be scanned
* @param isUnderFactoryTest Whether or not the device is under factory test
* @param currentTime The current time, in millis
* @return The results of the scan
*/
@GuardedBy("mInstallLock")
- private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+ @VisibleForTesting
+ @NonNull
+ static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+ Injector injector,
boolean isUnderFactoryTest, long currentTime)
- throws PackageManagerException {
+ throws PackageManagerException {
+ final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
+ final UserManagerInternal userManager = injector.getUserManager();
final PackageParser.Package pkg = request.pkg;
PackageSetting pkgSetting = request.pkgSetting;
final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
@@ -10723,7 +10834,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!createNewPackage) {
final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
- setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+ setInstantAppForUser(userManager, pkgSetting, userId, instantApp, fullApp);
}
// TODO(patb): see if we can do away with disabled check here.
if (disabledPkgSetting != null
@@ -10769,7 +10880,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+ final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
+ packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+ derivedAbi.first.applyTo(pkg);
+ derivedAbi.second.applyTo(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Some system apps still use directory structure for native libraries
@@ -10777,8 +10891,13 @@ public class PackageManagerService extends IPackageManager.Stub
// structure. Try to detect abi based on directory structure.
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
pkg.applicationInfo.primaryCpuAbi == null) {
- setBundledAppAbisAndRoots(pkg, pkgSetting);
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
+ pkg);
+ abis.applyTo(pkg);
+ abis.applyTo(pkgSetting);
+ final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+ packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ nativeLibraryPaths.applyTo(pkg);
}
} else {
// This is not a first boot or an upgrade, don't bother deriving the
@@ -10787,7 +10906,9 @@ public class PackageManagerService extends IPackageManager.Stub
pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+ packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ nativeLibraryPaths.applyTo(pkg);
if (DEBUG_ABI_SELECTION) {
Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
@@ -10808,7 +10929,9 @@ public class PackageManagerService extends IPackageManager.Stub
// ABIs we've determined above. For non-moves, the path will be updated based on the
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+ packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ nativeLibraryPaths.applyTo(pkg);
}
// This is a special case for the "system" package, where the ABI is
@@ -10862,8 +10985,9 @@ public class PackageManagerService extends IPackageManager.Stub
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
- changedAbiCodePath =
- adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
+ changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg,
+ packageAbiHelper.getAdjustedAbiForSharedUser(
+ pkgSetting.sharedUser.packages, pkg));
}
if (isUnderFactoryTest && pkg.requestedPermissions.contains(
@@ -11142,7 +11266,7 @@ public class PackageManagerService extends IPackageManager.Stub
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.assertScannedPackageValid(pkg);
- synchronized (mPackages) {
+ synchronized (mLock) {
// The special "android" package can only be defined once
if (pkg.packageName.equals("android")) {
if (mAndroidApplication != null) {
@@ -11458,7 +11582,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private boolean addBuiltInSharedLibraryLocked(String path, String name) {
if (nonStaticSharedLibExistsLocked(name)) {
return false;
@@ -11473,7 +11597,7 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private boolean nonStaticSharedLibExistsLocked(String name) {
return sharedLibExists(name, SharedLibraryInfo.VERSION_UNDEFINED, mSharedLibraries);
}
@@ -11487,7 +11611,7 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void commitSharedLibraryInfoLocked(SharedLibraryInfo libraryInfo) {
final String name = libraryInfo.getName();
LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
@@ -11537,7 +11661,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (pkg.packageName.equals("android")) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
// Set up information for our fall-back user intent resolution activity.
mPlatformPackage = pkg;
@@ -11575,7 +11699,7 @@ public class PackageManagerService extends IPackageManager.Stub
ArrayList<PackageParser.Package> clientLibPkgs = null;
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
commitSharedLibraryInfoLocked(info);
@@ -11621,7 +11745,7 @@ public class PackageManagerService extends IPackageManager.Stub
// writer
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
- synchronized (mPackages) {
+ synchronized (mLock) {
// We don't expect installation to fail beyond this point
// Add the new setting to mSettings
@@ -11634,6 +11758,7 @@ public class PackageManagerService extends IPackageManager.Stub
ksms.addScannedPackageLPw(pkg);
mComponentResolver.addAllComponents(pkg, chatty);
+ mAppsFilter.addPackage(pkg, mPackages);
// Don't allow ephemeral applications to define new permissions groups.
if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
@@ -11713,266 +11838,8 @@ public class PackageManagerService extends IPackageManager.Stub
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- /**
- * Derive the ABI of a non-system package located at {@code scanFile}. This information
- * is derived purely on the basis of the contents of {@code scanFile} and
- * {@code cpuAbiOverride}.
- *
- * If {@code extractLibs} is true, native libraries are extracted from the app if required.
- */
- private static void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
- boolean extractLibs)
- throws PackageManagerException {
- // Give ourselves some initial paths; we'll come back for another
- // pass once we've determined ABI below.
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
-
- // We shouldn't attempt to extract libs from system app when it was not updated.
- if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
- extractLibs = false;
- }
-
- final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
- final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
-
- NativeLibraryHelper.Handle handle = null;
- try {
- handle = NativeLibraryHelper.Handle.create(pkg);
- // TODO(multiArch): This can be null for apps that didn't go through the
- // usual installation process. We can calculate it again, like we
- // do during install time.
- //
- // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
- // unnecessary.
- final File nativeLibraryRoot = new File(nativeLibraryRootStr);
-
- // Null out the abis so that they can be recalculated.
- pkg.applicationInfo.primaryCpuAbi = null;
- pkg.applicationInfo.secondaryCpuAbi = null;
- if (isMultiArch(pkg.applicationInfo)) {
- // Warn if we've set an abiOverride for multi-lib packages..
- // By definition, we need to copy both 32 and 64 bit libraries for
- // such packages.
- if (pkg.cpuAbiOverride != null
- && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
- Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
- }
-
- int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
- int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
- if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
- if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
- useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
- abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- // Shared library native code should be in the APK zip aligned
- if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Shared library native lib extraction not supported");
- }
-
- maybeThrowExceptionForMultiArchCopy(
- "Error unpackaging 32 bit native libs for multiarch app.", abi32);
-
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
- if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
- useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
- abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- maybeThrowExceptionForMultiArchCopy(
- "Error unpackaging 64 bit native libs for multiarch app.", abi64);
-
- if (abi64 >= 0) {
- // Shared library native libs should be in the APK zip aligned
- if (extractLibs && pkg.isLibrary()) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Shared library native lib extraction not supported");
- }
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
- }
-
- if (abi32 >= 0) {
- final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
- if (abi64 >= 0) {
- if (pkg.use32bitAbi) {
- pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
- pkg.applicationInfo.primaryCpuAbi = abi;
- } else {
- pkg.applicationInfo.secondaryCpuAbi = abi;
- }
- } else {
- pkg.applicationInfo.primaryCpuAbi = abi;
- }
- }
- } else {
- String[] abiList = (cpuAbiOverride != null) ?
- new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
-
- // Enable gross and lame hacks for apps that are built with old
- // SDK tools. We must scan their APKs for renderscript bitcode and
- // not launch them if it's present. Don't bother checking on devices
- // that don't have 64 bit support.
- boolean needsRenderScriptOverride = false;
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
- NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
- abiList = Build.SUPPORTED_32_BIT_ABIS;
- needsRenderScriptOverride = true;
- }
-
- final int copyRet;
- if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
- copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
- if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Error unpackaging native libs for app, errorCode=" + copyRet);
- }
-
- if (copyRet >= 0) {
- // Shared libraries that have native libs must be multi-architecture
- if (pkg.isLibrary()) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Shared library with native libs must be multiarch");
- }
- pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
- } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) {
- pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
- } else if (needsRenderScriptOverride) {
- pkg.applicationInfo.primaryCpuAbi = abiList[0];
- }
- }
- } catch (IOException ioe) {
- Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
- } finally {
- IoUtils.closeQuietly(handle);
- }
-
- // Now that we've calculated the ABIs and determined if it's an internal app,
- // we will go ahead and populate the nativeLibraryPath.
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
- }
-
- /**
- * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
- * i.e, so that all packages can be run inside a single process if required.
- *
- * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
- * this function will either try and make the ABI for all packages in {@code packagesForUser}
- * match {@code scannedPackage} or will update the ABI of {@code scannedPackage} to match
- * the ABI selected for {@code packagesForUser}. This variant is used when installing or
- * updating a package that belongs to a shared user.
- *
- * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
- * adds unnecessary complexity.
- */
- private static @Nullable List<String> adjustCpuAbisForSharedUserLPw(
- Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
- List<String> changedAbiCodePath = null;
- String requiredInstructionSet = null;
- if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
- requiredInstructionSet = VMRuntime.getInstructionSet(
- scannedPackage.applicationInfo.primaryCpuAbi);
- }
-
- PackageSetting requirer = null;
- for (PackageSetting ps : packagesForUser) {
- // If packagesForUser contains scannedPackage, we skip it. This will happen
- // when scannedPackage is an update of an existing package. Without this check,
- // we will never be able to change the ABI of any package belonging to a shared
- // user, even if it's compatible with other packages.
- if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
- if (ps.primaryCpuAbiString == null) {
- continue;
- }
-
- final String instructionSet = VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
- if (requiredInstructionSet != null && !instructionSet.equals(requiredInstructionSet)) {
- // We have a mismatch between instruction sets (say arm vs arm64) warn about
- // this but there's not much we can do.
- String errorMessage = "Instruction set mismatch, "
- + ((requirer == null) ? "[caller]" : requirer)
- + " requires " + requiredInstructionSet + " whereas " + ps
- + " requires " + instructionSet;
- Slog.w(TAG, errorMessage);
- }
-
- if (requiredInstructionSet == null) {
- requiredInstructionSet = instructionSet;
- requirer = ps;
- }
- }
- }
-
- if (requiredInstructionSet != null) {
- String adjustedAbi;
- if (requirer != null) {
- // requirer != null implies that either scannedPackage was null or that scannedPackage
- // did not require an ABI, in which case we have to adjust scannedPackage to match
- // the ABI of the set (which is the same as requirer's ABI)
- adjustedAbi = requirer.primaryCpuAbiString;
- if (scannedPackage != null) {
- scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
- }
- } else {
- // requirer == null implies that we're updating all ABIs in the set to
- // match scannedPackage.
- adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
- }
-
- for (PackageSetting ps : packagesForUser) {
- if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
- if (ps.primaryCpuAbiString != null) {
- continue;
- }
-
- ps.primaryCpuAbiString = adjustedAbi;
- if (ps.pkg != null && ps.pkg.applicationInfo != null &&
- !TextUtils.equals(adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
- ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
- if (DEBUG_ABI_SELECTION) {
- Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi
- + " (requirer="
- + (requirer != null ? requirer.pkg : "null")
- + ", scannedPackage="
- + (scannedPackage != null ? scannedPackage : "null")
- + ")");
- }
- if (changedAbiCodePath == null) {
- changedAbiCodePath = new ArrayList<>();
- }
- changedAbiCodePath.add(ps.codePathString);
- }
- }
- }
- }
- return changedAbiCodePath;
- }
-
private void setUpCustomResolverActivity(PackageParser.Package pkg) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mResolverReplaced = true;
// Set up information for custom user intent resolution activity.
mResolveActivity.applicationInfo = pkg.applicationInfo;
@@ -12022,207 +11889,6 @@ public class PackageManagerService extends IPackageManager.Stub
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
}
- private static String calculateBundledApkRoot(final String codePathString) {
- final File codePath = new File(codePathString);
- final File codeRoot;
- if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
- codeRoot = Environment.getRootDirectory();
- } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
- codeRoot = Environment.getOemDirectory();
- } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
- codeRoot = Environment.getVendorDirectory();
- } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
- codeRoot = Environment.getOdmDirectory();
- } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
- codeRoot = Environment.getProductDirectory();
- } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
- codeRoot = Environment.getSystemExtDirectory();
- } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
- codeRoot = Environment.getOdmDirectory();
- } else {
- // Unrecognized code path; take its top real segment as the apk root:
- // e.g. /something/app/blah.apk => /something
- try {
- File f = codePath.getCanonicalFile();
- File parent = f.getParentFile(); // non-null because codePath is a file
- File tmp;
- while ((tmp = parent.getParentFile()) != null) {
- f = parent;
- parent = tmp;
- }
- codeRoot = f;
- Slog.w(TAG, "Unrecognized code path "
- + codePath + " - using " + codeRoot);
- } catch (IOException e) {
- // Can't canonicalize the code path -- shenanigans?
- Slog.w(TAG, "Can't canonicalize code path " + codePath);
- return Environment.getRootDirectory().getPath();
- }
- }
- return codeRoot.getPath();
- }
-
- /**
- * Derive and set the location of native libraries for the given package,
- * which varies depending on where and how the package was installed.
- */
- private static void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir) {
- final ApplicationInfo info = pkg.applicationInfo;
- final String codePath = pkg.codePath;
- final File codeFile = new File(codePath);
- final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
-
- info.nativeLibraryRootDir = null;
- info.nativeLibraryRootRequiresIsa = false;
- info.nativeLibraryDir = null;
- info.secondaryNativeLibraryDir = null;
-
- if (isApkFile(codeFile)) {
- // Monolithic install
- if (bundledApp) {
- // If "/system/lib64/apkname" exists, assume that is the per-package
- // native library directory to use; otherwise use "/system/lib/apkname".
- final String apkRoot = calculateBundledApkRoot(info.sourceDir);
- final boolean is64Bit = VMRuntime.is64BitInstructionSet(
- getPrimaryInstructionSet(info));
-
- // This is a bundled system app so choose the path based on the ABI.
- // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
- // is just the default path.
- final String apkName = deriveCodePathName(codePath);
- final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
- info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
- apkName).getAbsolutePath();
-
- if (info.secondaryCpuAbi != null) {
- final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
- info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
- secondaryLibDir, apkName).getAbsolutePath();
- }
- } else {
- final String apkName = deriveCodePathName(codePath);
- info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
- .getAbsolutePath();
- }
-
- info.nativeLibraryRootRequiresIsa = false;
- info.nativeLibraryDir = info.nativeLibraryRootDir;
- } else {
- // Cluster install
- info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
- info.nativeLibraryRootRequiresIsa = true;
-
- info.nativeLibraryDir = new File(info.nativeLibraryRootDir,
- getPrimaryInstructionSet(info)).getAbsolutePath();
-
- if (info.secondaryCpuAbi != null) {
- info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir,
- VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath();
- }
- }
- }
-
- /**
- * Calculate the abis and roots for a bundled app. These can uniquely
- * be determined from the contents of the system partition, i.e whether
- * it contains 64 or 32 bit shared libraries etc. We do not validate any
- * of this information, and instead assume that the system was built
- * sensibly.
- */
- private static void setBundledAppAbisAndRoots(PackageParser.Package pkg,
- PackageSetting pkgSetting) {
- final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
-
- // If "/system/lib64/apkname" exists, assume that is the per-package
- // native library directory to use; otherwise use "/system/lib/apkname".
- final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
- setBundledAppAbi(pkg, apkRoot, apkName);
- // pkgSetting might be null during rescan following uninstall of updates
- // to a bundled app, so accommodate that possibility. The settings in
- // that case will be established later from the parsed package.
- //
- // If the settings aren't null, sync them up with what we've just derived.
- // note that apkRoot isn't stored in the package settings.
- if (pkgSetting != null) {
- pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
- pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
- }
- }
-
- /**
- * Deduces the ABI of a bundled app and sets the relevant fields on the
- * parsed pkg object.
- *
- * @param apkRoot the root of the installed apk, something like {@code /system} or {@code /oem}
- * under which system libraries are installed.
- * @param apkName the name of the installed package.
- */
- private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
- final File codeFile = new File(pkg.codePath);
-
- final boolean has64BitLibs;
- final boolean has32BitLibs;
- if (isApkFile(codeFile)) {
- // Monolithic install
- has64BitLibs = (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
- has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
- } else {
- // Cluster install
- final File rootDir = new File(codeFile, LIB_DIR_NAME);
- if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
- && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
- final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
- has64BitLibs = (new File(rootDir, isa)).exists();
- } else {
- has64BitLibs = false;
- }
- if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
- && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
- final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
- has32BitLibs = (new File(rootDir, isa)).exists();
- } else {
- has32BitLibs = false;
- }
- }
-
- if (has64BitLibs && !has32BitLibs) {
- // The package has 64 bit libs, but not 32 bit libs. Its primary
- // ABI should be 64 bit. We can safely assume here that the bundled
- // native libraries correspond to the most preferred ABI in the list.
-
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = null;
- } else if (has32BitLibs && !has64BitLibs) {
- // The package has 32 bit libs but not 64 bit libs. Its primary
- // ABI should be 32 bit.
-
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = null;
- } else if (has32BitLibs && has64BitLibs) {
- // The application has both 64 and 32 bit bundled libraries. We check
- // here that the app declares multiArch support, and warn if it doesn't.
- //
- // We will be lenient here and record both ABIs. The primary will be the
- // ABI that's higher on the list, i.e, a device that's configured to prefer
- // 64 bit apps will see a 64 bit primary ABI,
-
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
- Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
- }
-
- if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- } else {
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- }
- } else {
- pkg.applicationInfo.primaryCpuAbi = null;
- pkg.applicationInfo.secondaryCpuAbi = null;
- }
- }
-
private void killApplication(String pkgName, int appId, String reason) {
killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
}
@@ -12271,7 +11937,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.Package removedPackage = mPackages.remove(packageName);
if (removedPackage != null) {
cleanPackageDataStructuresLILPw(removedPackage, chatty);
@@ -12286,7 +11952,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
// Remove the parent package
mPackages.remove(pkg.applicationInfo.packageName);
cleanPackageDataStructuresLILPw(pkg, chatty);
@@ -12303,7 +11969,7 @@ public class PackageManagerService extends IPackageManager.Stub
void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
mComponentResolver.removeAllComponents(pkg, chatty);
-
+ mAppsFilter.removePackage(pkg.packageName);
mPermissionManager.removeAllPermissions(pkg, chatty);
final int instrumentationSize = pkg.instrumentation.size();
@@ -12395,7 +12061,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void notifyPackageAdded(String packageName, int uid) {
final PackageListObserver[] observers;
- synchronized (mPackages) {
+ synchronized (mLock) {
if (mPackageListObservers.size() == 0) {
return;
}
@@ -12411,7 +12077,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void notifyPackageChanged(String packageName, int uid) {
final PackageListObserver[] observers;
- synchronized (mPackages) {
+ synchronized (mLock) {
if (mPackageListObservers.size() == 0) {
return;
}
@@ -12433,7 +12099,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void notifyPackageRemoved(String packageName, int uid) {
final PackageListObserver[] observers;
- synchronized (mPackages) {
+ synchronized (mLock) {
if (mPackageListObservers.size() == 0) {
return;
}
@@ -12682,12 +12348,12 @@ public class PackageManagerService extends IPackageManager.Stub
boolean sendAdded = false;
boolean sendRemoved = false;
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
return false;
}
- if (filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
return false;
}
// Do not allow "android" is being disabled
@@ -12743,7 +12409,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils
.enforceSystemOrPhoneCaller("setSystemAppHiddenUntilInstalled", callingUid);
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null || !pkgSetting.isSystem()) {
return;
@@ -12768,7 +12434,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils
.enforceSystemOrPhoneCaller("setSystemAppInstallState", callingUid);
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
// The target app should always be in system
if (pkgSetting == null || !pkgSetting.isSystem()) {
@@ -12857,12 +12523,12 @@ public class PackageManagerService extends IPackageManager.Stub
long callingId = Binder.clearCallingIdentity();
try {
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
ps = mSettings.mPackages.get(packageName);
if (ps == null) {
return true;
}
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return true;
}
return ps.getHidden(userId);
@@ -12918,7 +12584,7 @@ public class PackageManagerService extends IPackageManager.Stub
(installFlags & PackageManager.INSTALL_FULL_APP) != 0;
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
@@ -12948,7 +12614,8 @@ public class PackageManagerService extends IPackageManager.Stub
// upgrade app from instant to full; we don't allow app downgrade
installed = true;
}
- setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+ setInstantAppForUser(
+ getUserManagerInternal(), pkgSetting, userId, instantApp, fullApp);
}
if (installed) {
@@ -12966,7 +12633,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
sendPackageAddedForUser(packageName, pkgSetting, userId);
- synchronized (mPackages) {
+ synchronized (mLock) {
updateSequenceNumberLP(pkgSetting, new int[]{ userId });
}
// start async restore with no post-install since we finish install here
@@ -12996,8 +12663,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- static void setInstantAppForUser(PackageSetting pkgSetting, int userId,
- boolean instantApp, boolean fullApp) {
+ static void setInstantAppForUser(UserManagerInternal userManager, PackageSetting pkgSetting,
+ int userId, boolean instantApp, boolean fullApp) {
// no state specified; do nothing
if (!instantApp && !fullApp) {
return;
@@ -13009,7 +12676,7 @@ public class PackageManagerService extends IPackageManager.Stub
pkgSetting.setInstantApp(false /*instantApp*/, userId);
}
} else {
- for (int currentUserId : sUserManager.getUserIds()) {
+ for (int currentUserId : userManager.getUserIds()) {
if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
} else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
@@ -13051,9 +12718,10 @@ public class PackageManagerService extends IPackageManager.Stub
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
final PackageSetting pkgSetting;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+ if (pkgSetting == null
+ || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
+ ". Skipping...");
unactionedPackages.add(packageName);
@@ -13064,7 +12732,7 @@ public class PackageManagerService extends IPackageManager.Stub
unactionedPackages.add(packageName);
continue;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
final int oldDistractionFlags = pkgSetting.getDistractionFlags(userId);
if (restrictionFlags != oldDistractionFlags) {
pkgSetting.setDistractionFlags(restrictionFlags, userId);
@@ -13079,7 +12747,7 @@ public class PackageManagerService extends IPackageManager.Stub
new String[changedPackagesList.size()]);
sendDistractingPackagesChanged(changedPackages, changedUids.toArray(), userId,
restrictionFlags);
- synchronized (mPackages) {
+ synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
@@ -13143,9 +12811,10 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
final PackageSetting pkgSetting;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+ if (pkgSetting == null
+ || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
+ ". Skipping suspending/un-suspending.");
unactionedPackages.add(packageName);
@@ -13156,7 +12825,7 @@ public class PackageManagerService extends IPackageManager.Stub
unactionedPackages.add(packageName);
continue;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
launcherExtras, userId);
}
@@ -13170,7 +12839,7 @@ public class PackageManagerService extends IPackageManager.Stub
sendPackagesSuspendedForUser(
changedPackages, changedUids.toArray(), userId, suspended, launcherExtras);
sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, appExtras, userId);
- synchronized (mPackages) {
+ synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
@@ -13184,9 +12853,9 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException("Calling package " + packageName
+ " does not belong to calling uid " + callingUid);
}
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
throw new IllegalArgumentException("Unknown target package: " + packageName);
}
final PackageUserState packageUserState = ps.readUserState(userId);
@@ -13236,9 +12905,9 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */,
"isPackageSuspendedForUser for user " + userId);
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
throw new IllegalArgumentException("Unknown target package: " + packageName);
}
return ps.getSuspended(userId);
@@ -13284,7 +12953,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void unsuspendForSuspendingPackages(Predicate<String> packagePredicate, int userId) {
final List<String> affectedPackages = new ArrayList<>();
final IntArray affectedUids = new IntArray();
- synchronized (mPackages) {
+ synchronized (mLock) {
for (PackageSetting ps : mSettings.mPackages.values()) {
final PackageUserState pus = ps.readUserState(userId);
if (pus.suspended && packagePredicate.test(pus.suspendingPackage)) {
@@ -13379,7 +13048,7 @@ public class PackageManagerService extends IPackageManager.Stub
+ "\": required for permissions management");
continue;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": protected package");
@@ -13537,7 +13206,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private int getUidForVerifier(VerifierInfo verifierInfo) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName);
if (pkg == null) {
return -1;
@@ -13703,10 +13372,11 @@ public class PackageManagerService extends IPackageManager.Stub
if (getInstantAppPackageName(callingUid) != null) {
return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null
- || filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ || shouldFilterApplicationLocked(
+ ps, callingUid, UserHandle.getUserId(callingUid))) {
return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
return mSettings.getIntentFilterVerificationStatusLPr(packageName, userId);
@@ -13719,9 +13389,10 @@ public class PackageManagerService extends IPackageManager.Stub
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
boolean result = false;
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (filterAppAccessLPr(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+ if (shouldFilterApplicationLocked(
+ ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
return false;
}
result = mSettings.updateIntentFilterVerificationStatusLPw(packageName, status, userId);
@@ -13739,9 +13410,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (getInstantAppPackageName(callingUid) != null) {
return ParceledListSlice.emptyList();
}
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ if (shouldFilterApplicationLocked(ps, callingUid, UserHandle.getUserId(callingUid))) {
return ParceledListSlice.emptyList();
}
return new ParceledListSlice<>(mSettings.getIntentFilterVerificationsLPr(packageName));
@@ -13755,7 +13426,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null || pkg.activities == null) {
return ParceledListSlice.emptyList();
@@ -13764,7 +13435,7 @@ public class PackageManagerService extends IPackageManager.Stub
return ParceledListSlice.emptyList();
}
final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return ParceledListSlice.emptyList();
}
final int count = pkg.activities.size();
@@ -13797,10 +13468,10 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting targetPackageSetting = mSettings.mPackages.get(targetPackage);
if (targetPackageSetting == null
- || filterAppAccessLPr(
+ || shouldFilterApplicationLocked(
targetPackageSetting, callingUid, UserHandle.getUserId(callingUid))) {
throw new IllegalArgumentException("Unknown target package: " + targetPackage);
}
@@ -13879,12 +13550,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
callerPackageName);
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null) {
throw new IllegalArgumentException("Unknown target package " + packageName);
}
- if (filterAppAccessLPr(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+ if (shouldFilterApplicationLocked(
+ ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
throw new IllegalArgumentException("Unknown target package " + packageName);
}
if (!Objects.equals(callerPackageName, ps.installerPackageName)) {
@@ -14424,7 +14096,7 @@ public class PackageManagerService extends IPackageManager.Stub
String packageName = pkgLite.packageName;
int installLocation = pkgLite.installLocation;
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
// Currently installed package which the new package is attempting to replace or
// null if no such package is installed.
PackageParser.Package installedPkg = mPackages.get(packageName);
@@ -14763,7 +14435,7 @@ public class PackageManagerService extends IPackageManager.Stub
mPendingEnableRollback.append(enableRollbackToken, this);
final int[] installedUsers;
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
if (ps != null) {
installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
@@ -15201,16 +14873,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
- PackageManagerException {
- if (copyRet < 0) {
- if (copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
- copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
- throw new PackageManagerException(copyRet, message);
- }
- }
- }
-
/**
* Logic to handle movement of existing installed applications.
*/
@@ -15337,26 +14999,6 @@ public class PackageManagerService extends IPackageManager.Stub
return result;
}
- // Utility method that returns the relative package path with respect
- // to the installation directory. Like say for /data/data/com.test-1.apk
- // string com.test-1 is returned.
- static String deriveCodePathName(String codePath) {
- if (codePath == null) {
- return null;
- }
- final File codeFile = new File(codePath);
- final String name = codeFile.getName();
- if (codeFile.isDirectory()) {
- return name;
- } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
- final int lastDot = name.lastIndexOf('.');
- return name.substring(0, lastDot);
- } else {
- Slog.w(TAG, "Odd, " + codePath + " doesn't look like an APK");
- return null;
- }
- }
-
static class PackageInstalledInfo {
String name;
int uid;
@@ -15464,7 +15106,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageSetting childPs = null;
- synchronized (mPackages) {
+ synchronized (mLock) {
childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
}
if (childPs != null) {
@@ -15475,7 +15117,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void enableSystemPackageLPw(PackageParser.Package pkg) {
// Enable the parent package
mSettings.enableSystemPackageLPw(pkg.packageName);
@@ -15487,7 +15129,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private boolean disableSystemPackageLPw(PackageParser.Package oldPkg,
PackageParser.Package newPkg) {
// Disable the parent package (parent always replaced)
@@ -15502,7 +15144,7 @@ public class PackageManagerService extends IPackageManager.Stub
return disabled;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void setInstallerPackageNameLPw(PackageParser.Package pkg,
String installerPackageName) {
// Enable the parent package
@@ -15539,7 +15181,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
- synchronized (mPackages) {
+ synchronized (mLock) {
// NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
mPermissionManager.updatePermissions(pkg.packageName, pkg);
// For system-bundled packages, we assume that installing an upgraded version
@@ -15631,7 +15273,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy({"mInstallLock", "mPackages"})
+ @GuardedBy({"mInstallLock", "mLock"})
private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
@@ -15774,7 +15416,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private static Map<String, ReconciledPackage> reconcilePackagesLocked(
final ReconcileRequest request, KeySetManagerService ksms)
throws ReconcileFailure {
@@ -16085,7 +15727,7 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void commitPackagesLocked(final CommitRequest request) {
// TODO: remove any expected failures from this method; this should only be able to fail due
// to unavoidable errors (I/O, etc.)
@@ -16151,8 +15793,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
} else {
try {
+ // Settings will be written during the call to updateSettingsLI().
executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
- true, request.mAllUsers, true, pkg);
+ true, request.mAllUsers, false, pkg);
} catch (SystemDeleteException e) {
if (Build.IS_ENG) {
throw new RuntimeException("Unexpected failure", e);
@@ -16288,7 +15931,8 @@ public class PackageManagerService extends IPackageManager.Stub
final PrepareResult prepareResult;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
- prepareResult = preparePackageLI(request.args, request.installResult);
+ prepareResult =
+ preparePackageLI(request.args, request.installResult);
} catch (PrepareFailure prepareFailure) {
request.installResult.setError(prepareFailure.error,
prepareFailure.getMessage());
@@ -16342,7 +15986,7 @@ public class PackageManagerService extends IPackageManager.Stub
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
CommitRequest commitRequest = null;
- synchronized (mPackages) {
+ synchronized (mLock) {
Map<String, ReconciledPackage> reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
@@ -16644,7 +16288,7 @@ public class PackageManagerService extends IPackageManager.Stub
// If we are installing a clustered package add results for the children
if (pkg.childPackages != null) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final int childCount = pkg.childPackages.size();
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
@@ -16706,7 +16350,7 @@ public class PackageManagerService extends IPackageManager.Stub
pp = null;
boolean systemApp = false;
boolean replace = false;
- synchronized (mPackages) {
+ synchronized (mLock) {
// Check if installing already existing package
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
String oldName = mSettings.getRenamedPackageLPr(pkgName);
@@ -16807,7 +16451,7 @@ public class PackageManagerService extends IPackageManager.Stub
compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
- synchronized (mPackages) {
+ synchronized (mLock) {
ksms.removeAppKeySetDataLPw(pkg.packageName);
}
}
@@ -16927,7 +16571,7 @@ public class PackageManagerService extends IPackageManager.Stub
scanFlags |= SCAN_NO_DEX;
scanFlags |= SCAN_MOVE;
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps == null) {
res.setError(INSTALL_FAILED_INTERNAL_ERROR,
@@ -16948,7 +16592,11 @@ public class PackageManagerService extends IPackageManager.Stub
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
args.abiOverride : pkg.cpuAbiOverride);
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, abiOverride, extractNativeLibs);
+ final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
+ derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
+ pkg, abiOverride, extractNativeLibs);
+ derivedAbi.first.applyTo(pkg);
+ derivedAbi.second.applyTo(pkg);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -17010,7 +16658,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int[] allUsers;
final int[] installedUsers;
- synchronized (mPackages) {
+ synchronized (mLock) {
oldPackage = mPackages.get(pkgName11);
existingPackage = oldPackage;
if (DEBUG_INSTALL) {
@@ -17145,7 +16793,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
childRemovedRes.isUpdate = false;
childRemovedRes.dataRemoved = true;
- synchronized (mPackages) {
+ synchronized (mLock) {
if (childPs != null) {
childRemovedRes.origUsers = childPs.queryInstalledUsers(
allUsers,
@@ -17217,7 +16865,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
// TODO(patb): MOVE TO RECONCILE
- synchronized (mPackages) {
+ synchronized (mLock) {
renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
if (renamedPackage != null) {
// A package with the same name is already installed, though
@@ -17269,7 +16917,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Collect files we care for fs-verity setup.
ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
if (legacyMode) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
if (ps != null && ps.isPrivileged()) {
fsverityCandidates.put(pkg.baseCodePath, null);
@@ -17396,7 +17044,7 @@ public class PackageManagerService extends IPackageManager.Stub
int count = 0;
final String packageName = pkg.packageName;
- synchronized (mPackages) {
+ synchronized (mLock) {
// If this is a new install and we see that we've already run verification for this
// package, we have nothing to do: it means the state was restored from backup.
if (!replacing) {
@@ -17454,7 +17102,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) {
final ComponentName cn = filter.activity.getComponentName();
final String packageName = cn.getPackageName();
@@ -17477,10 +17125,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private static boolean isMultiArch(ApplicationInfo info) {
- return (info.flags & ApplicationInfo.FLAG_MULTIARCH) != 0;
- }
-
private static boolean isExternal(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
@@ -17489,7 +17133,7 @@ public class PackageManagerService extends IPackageManager.Stub
return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
- private static boolean isSystemApp(PackageParser.Package pkg) {
+ static boolean isSystemApp(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
@@ -17570,7 +17214,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageName = versionedPackage.getPackageName();
final long versionCode = versionedPackage.getLongVersionCode();
final String internalPackageName;
- synchronized (mPackages) {
+ synchronized (mLock) {
// Normalize package name to handle renamed packages and static libs
internalPackageName = resolveInternalPackageNameLPr(packageName, versionCode);
}
@@ -17683,7 +17327,7 @@ public class PackageManagerService extends IPackageManager.Stub
return pkg.packageName;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private String resolveInternalPackageNameLPr(String packageName, long versionCode) {
// Handle renamed packages
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
@@ -17894,7 +17538,7 @@ public class PackageManagerService extends IPackageManager.Stub
int[] allUsers;
/** enabled state of the uninstalled application */
final int origEnabledState;
- synchronized (mPackages) {
+ synchronized (mLock) {
uninstalledPs = mSettings.mPackages.get(packageName);
if (uninstalledPs == null) {
Slog.w(TAG, "Not removing non-existent package " + packageName);
@@ -17960,7 +17604,7 @@ public class PackageManagerService extends IPackageManager.Stub
res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,
deleteFlags | PackageManager.DELETE_CHATTY, info, true, null);
}
- synchronized (mPackages) {
+ synchronized (mLock) {
if (res) {
if (pkg != null) {
mInstantAppRegistry.onPackageUninstalledLPw(pkg, info.removedUsers);
@@ -17988,7 +17632,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageParser.Package stubPkg =
(disabledSystemPs == null) ? null : disabledSystemPs.pkg;
if (stubPkg != null && stubPkg.isStub) {
- synchronized (mPackages) {
+ synchronized (mLock) {
// restore the enabled state of the stub; the state is overwritten when
// the stub is uninstalled
final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
@@ -18197,7 +17841,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (deletedPs != null) {
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
final SparseBooleanArray changedUsers = new SparseBooleanArray();
- synchronized (mPackages) {
+ synchronized (mLock) {
clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
clearDefaultBrowserIfNeeded(packageName);
mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
@@ -18253,7 +17897,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
}
- synchronized (mPackages) {
+ synchronized (mLock) {
// can downgrade to reader
if (writeSettings) {
// Save settings now
@@ -18394,7 +18038,7 @@ public class PackageManagerService extends IPackageManager.Stub
outInfo, writeSettings, disabledPs.pkg);
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
// NOTE: The system package always needs to be enabled; even if it's for
// a compressed stub. If we don't, installing the system package fails
// during scan [scanning checks the disabled packages]. We will reverse
@@ -18474,7 +18118,7 @@ public class PackageManagerService extends IPackageManager.Stub
prepareAppDataAfterInstallLIF(pkg);
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
// Propagate the permissions state as we do not want to drop on the floor
@@ -18523,7 +18167,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean deleteCodeAndResources, int flags, int[] allUserHandles,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if (outInfo != null) {
outInfo.uid = ps.appId;
}
@@ -18550,7 +18194,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageSetting childPs;
- synchronized (mPackages) {
+ synchronized (mLock) {
childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
}
if (childPs != null) {
@@ -18581,7 +18225,7 @@ public class PackageManagerService extends IPackageManager.Stub
int userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
- synchronized (mPackages) {
+ synchronized (mLock) {
// Cannot block uninstall of static shared libs as they are
// considered a part of the using app (emulating static linking).
// Also static libs are installed always on internal storage.
@@ -18599,9 +18243,9 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean getBlockUninstallForUser(String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null || filterAppAccessLPr(ps, Binder.getCallingUid(), userId)) {
+ if (ps == null || shouldFilterApplicationLocked(ps, Binder.getCallingUid(), userId)) {
return false;
}
return mSettings.getBlockUninstallLPr(userId, packageName);
@@ -18611,7 +18255,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) {
enforceSystemOrRoot("setRequiredForSystemUser can only be run by the system or root");
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null) {
Log.w(TAG, "Package doesn't exist: " + packageName);
@@ -18649,7 +18293,7 @@ public class PackageManagerService extends IPackageManager.Stub
* deleted, {@code null} otherwise.
*/
@Nullable
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private static DeletePackageAction mayDeletePackageLocked(
PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs,
@Nullable PackageSetting[] children, int flags, UserHandle user) {
@@ -18697,7 +18341,7 @@ public class PackageManagerService extends IPackageManager.Stub
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
final DeletePackageAction action;
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
PackageSetting[] children = mSettings.getChildSettingsLPr(ps);
@@ -18749,7 +18393,7 @@ public class PackageManagerService extends IPackageManager.Stub
: UserHandle.USER_ALL;
clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags);
- synchronized (mPackages) {
+ synchronized (mLock) {
markPackageUninstalledForUserLPw(ps, user);
scheduleWritePackageRestrictionsLocked(user);
}
@@ -18768,7 +18412,7 @@ public class PackageManagerService extends IPackageManager.Stub
// they have set the special DELETE_SYSTEM_APP which requests different
// semantics than normal for uninstalling system apps.
final boolean clearPackageStateAndReturn;
- synchronized (mPackages) {
+ synchronized (mLock) {
markPackageUninstalledForUserLPw(ps, user);
if (!systemApp) {
// Do not uninstall the APK if an app should be cached
@@ -18798,7 +18442,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (clearPackageStateAndReturn) {
clearPackageStateForUserLIF(ps, userId, outInfo, flags);
- synchronized (mPackages) {
+ synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(user);
}
return;
@@ -18808,7 +18452,7 @@ public class PackageManagerService extends IPackageManager.Stub
// If we are deleting a composite package for all users, keep track
// of result for each child.
if (ps.childPackageNames != null && outInfo != null) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final int childCount = ps.childPackageNames.size();
outInfo.removedChildPackages = new ArrayMap<>(childCount);
for (int i = 0; i < childCount; i++) {
@@ -18841,7 +18485,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (outInfo != null) {
outInfo.removedForAllUsers = mPackages.get(ps.name) == null;
if (outInfo.removedChildPackages != null) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final int childCount = outInfo.removedChildPackages.size();
for (int i = 0; i < childCount; i++) {
PackageRemovedInfo childInfo = outInfo.removedChildPackages.valueAt(i);
@@ -18856,7 +18500,7 @@ public class PackageManagerService extends IPackageManager.Stub
// child packages that appeared as they are declared in the system
// app but were not declared in the update.
if (systemApp) {
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting updatedPs = mSettings.getPackageLPr(ps.name);
final int childCount = (updatedPs.childPackageNames != null)
? updatedPs.childPackageNames.size() : 0;
@@ -18884,7 +18528,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void markPackageUninstalledForUserLPw(PackageSetting ps, UserHandle user) {
final int[] userIds = (user == null || user.getIdentifier() == UserHandle.USER_ALL)
? sUserManager.getUserIds() : new int[] {user.getIdentifier()};
@@ -18918,7 +18562,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void clearPackageStateForUserLIF(PackageSetting ps, int userId,
PackageRemovedInfo outInfo, int flags) {
final PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(ps.name);
}
@@ -18941,7 +18585,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (changedUsers.size() > 0) {
updateDefaultHomeNotLocked(changedUsers);
postPreferredActivityChangedBroadcast(nextUserId);
- synchronized (mPackages) {
+ synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(nextUserId);
}
}
@@ -18971,7 +18615,7 @@ public class PackageManagerService extends IPackageManager.Stub
enforceSystemOrRoot("Only the system can clear all profile data");
final PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(packageName);
}
@@ -18993,7 +18637,8 @@ public class PackageManagerService extends IPackageManager.Stub
true /* requireFullPermission */, false /* checkShell */, "clear application data");
final PackageSetting ps = mSettings.getPackageLPr(packageName);
- final boolean filterApp = (ps != null && filterAppAccessLPr(ps, callingUid, userId));
+ final boolean filterApp =
+ (ps != null && shouldFilterApplicationLocked(ps, callingUid, userId));
if (!filterApp && mProtectedPackages.isPackageDataProtected(userId, packageName)) {
throw new SecurityException("Cannot clear data for a protected package: "
+ packageName);
@@ -19009,7 +18654,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mInstallLock) {
succeeded = clearApplicationUserDataLIF(packageName, userId);
}
- synchronized (mPackages) {
+ synchronized (mLock) {
mInstantAppRegistry.deleteInstantApplicationMetadataLPw(
packageName, userId);
}
@@ -19048,7 +18693,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Try finding details about the requested package
PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -19143,7 +18788,7 @@ public class PackageManagerService extends IPackageManager.Stub
android.Manifest.permission.ACCESS_INSTANT_APPS);
final PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(packageName);
}
@@ -19186,7 +18831,7 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mInstallLock")
private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) {
final PackageSetting ps;
- synchronized (mPackages) {
+ synchronized (mLock) {
ps = mSettings.mPackages.get(packageName);
if (ps == null) {
Slog.w(TAG, "Failed to find settings for " + packageName);
@@ -19218,7 +18863,7 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private int getUidTargetSdkVersionLockedLPr(int uid) {
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingLPr(appId);
@@ -19243,7 +18888,7 @@ public class PackageManagerService extends IPackageManager.Stub
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private int getPackageTargetSdkVersionLockedLPr(String packageName) {
final PackageParser.Package p = mPackages.get(packageName);
if (p != null) {
@@ -19287,7 +18932,7 @@ public class PackageManagerService extends IPackageManager.Stub
+ userId + ":");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- synchronized (mPackages) {
+ synchronized (mLock) {
final PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId);
pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
scheduleWritePackageRestrictionsLocked(userId);
@@ -19339,7 +18984,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if (getUidTargetSdkVersionLockedLPr(callingUid)
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
@@ -19351,7 +18996,7 @@ public class PackageManagerService extends IPackageManager.Stub
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
}
- synchronized (mPackages) {
+ synchronized (mLock) {
final PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
if (pir != null) {
// Get all of the existing entries that exactly match this filter.
@@ -19415,7 +19060,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null || !isCallerSameApp(packageName, callingUid)) {
if (mContext.checkCallingOrSelfPermission(
@@ -19433,7 +19078,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null
- && filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ && shouldFilterApplicationLocked(
+ ps, callingUid, UserHandle.getUserId(callingUid))) {
return;
}
}
@@ -19443,14 +19089,14 @@ public class PackageManagerService extends IPackageManager.Stub
if (changedUsers.size() > 0) {
updateDefaultHomeNotLocked(changedUsers);
postPreferredActivityChangedBroadcast(callingUserId);
- synchronized (mPackages) {
+ synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(callingUserId);
}
}
}
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void clearPackagePreferredActivitiesLPw(String packageName,
@NonNull SparseBooleanArray outUserChanged, int userId) {
ArrayList<PreferredActivity> removed = null;
@@ -19485,7 +19131,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void clearIntentFilterVerificationsLPw(int userId) {
final int packageCount = mPackages.size();
for (int i = 0; i < packageCount; i++) {
@@ -19495,7 +19141,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
void clearIntentFilterVerificationsLPw(String packageName, int userId) {
if (userId == UserHandle.USER_ALL) {
if (mSettings.removeIntentFilterVerificationLPw(packageName,
@@ -19539,7 +19185,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (changedUsers.size() > 0) {
postPreferredActivityChangedBroadcast(userId);
}
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.applyDefaultPreferredAppsLPw(userId);
clearIntentFilterVerificationsLPw(userId);
primeDomainVerificationsLPw(userId);
@@ -19552,7 +19198,7 @@ public class PackageManagerService extends IPackageManager.Stub
// callbacks to the package manager to request a default app reset.
mPermissionManager.setDefaultBrowser(null, true, true, userId);
resetNetworkPolicies(userId);
- synchronized (mPackages) {
+ synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
}
} finally {
@@ -19569,7 +19215,7 @@ public class PackageManagerService extends IPackageManager.Stub
int num = 0;
final int userId = UserHandle.getCallingUserId();
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
if (pir != null) {
final Iterator<PreferredActivity> it = pir.filterIterator();
@@ -19609,7 +19255,7 @@ public class PackageManagerService extends IPackageManager.Stub
+ " for user " + userId + ":");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
new PersistentPreferredActivity(filter, activity));
scheduleWritePackageRestrictionsLocked(userId);
@@ -19627,7 +19273,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
ArrayList<PersistentPreferredActivity> removed = null;
boolean changed = false;
- synchronized (mPackages) {
+ synchronized (mLock) {
for (int i=0; i<mSettings.mPersistentPreferredActivities.size(); i++) {
final int thisUserId = mSettings.mPersistentPreferredActivities.keyAt(i);
PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
@@ -19658,7 +19304,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (changed) {
updateDefaultHomeNotLocked(userId);
postPreferredActivityChangedBroadcast(userId);
- synchronized (mPackages) {
+ synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
@@ -19717,7 +19363,7 @@ public class PackageManagerService extends IPackageManager.Stub
serializer.startDocument(null, true);
serializer.startTag(null, TAG_PREFERRED_BACKUP);
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.writePreferredActivitiesLPr(serializer, userId, true);
}
@@ -19745,7 +19391,7 @@ public class PackageManagerService extends IPackageManager.Stub
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_PREFERRED_BACKUP,
(readParser, readUserId) -> {
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.readPreferredActivitiesLPw(readParser, readUserId);
}
updateDefaultHomeNotLocked(readUserId);
@@ -19775,7 +19421,7 @@ public class PackageManagerService extends IPackageManager.Stub
serializer.startDocument(null, true);
serializer.startTag(null, TAG_DEFAULT_APPS);
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.writeDefaultAppsLPr(serializer, userId);
}
@@ -19804,7 +19450,7 @@ public class PackageManagerService extends IPackageManager.Stub
restoreFromXml(parser, userId, TAG_DEFAULT_APPS,
(parser1, userId1) -> {
final String defaultBrowser;
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.readDefaultAppsLPw(parser1, userId1);
defaultBrowser = mSettings.removeDefaultBrowserPackageNameLPw(userId1);
}
@@ -19833,7 +19479,7 @@ public class PackageManagerService extends IPackageManager.Stub
serializer.startDocument(null, true);
serializer.startTag(null, TAG_INTENT_FILTER_VERIFICATION);
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.writeAllDomainVerificationsLPr(serializer, userId);
}
@@ -19861,7 +19507,7 @@ public class PackageManagerService extends IPackageManager.Stub
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_INTENT_FILTER_VERIFICATION,
(parser1, userId1) -> {
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.readAllDomainVerificationsLPr(parser1, userId1);
mSettings.writeLPr();
}
@@ -19886,7 +19532,7 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
return;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
CrossProfileIntentFilter newFilter = new CrossProfileIntentFilter(intentFilter,
ownerPackage, targetUserId, flags);
CrossProfileIntentResolver resolver =
@@ -19914,7 +19560,7 @@ public class PackageManagerService extends IPackageManager.Stub
enforceOwnerRights(ownerPackage, callingUid);
PackageManagerServiceUtils.enforceShellRestriction(
UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
- synchronized (mPackages) {
+ synchronized (mLock) {
CrossProfileIntentResolver resolver =
mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
ArraySet<CrossProfileIntentFilter> set =
@@ -20066,7 +19712,7 @@ public class PackageManagerService extends IPackageManager.Stub
/** <b>must not hold {@link #mPackages}</b> */
private void updateDefaultHomeNotLocked(SparseBooleanArray userIds) {
- if (Thread.holdsLock(mPackages)) {
+ if (Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mPackages", new Throwable());
}
@@ -20082,7 +19728,7 @@ public class PackageManagerService extends IPackageManager.Stub
* @return Whether the ACTION_PREFERRED_ACTIVITY_CHANGED broadcast has been scheduled.
*/
private boolean updateDefaultHomeNotLocked(int userId) {
- if (Thread.holdsLock(mPackages)) {
+ if (Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mPackages", new Throwable());
}
@@ -20271,7 +19917,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void setUpdateAvailable(String packageName, boolean updateAvailable) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting != null) {
pkgSetting.setUpdateAvailable(updateAvailable);
@@ -20316,7 +19962,7 @@ public class PackageManagerService extends IPackageManager.Stub
ArrayList<String> components;
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
if (!isCallerInstantApp) {
@@ -20342,7 +19988,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!UserHandle.isSameApp(callingUid, pkgSetting.appId)) {
// Don't allow apps that don't have permission to modify other apps
if (!allowedByPermission
- || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+ || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
throw new SecurityException(
"Attempt to change component state; "
+ "pid=" + Binder.getCallingPid()
@@ -20363,7 +20009,7 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException("Cannot disable a system-generated component");
}
- synchronized (mPackages) {
+ synchronized (mLock) {
if (callingUid == Process.SHELL_UID
&& (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
// Shell can only change whole packages between ENABLED and DISABLED_USER states
@@ -20388,7 +20034,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (className == null) {
// We're dealing with an application/package level state change
- synchronized (mPackages) {
+ synchronized (mLock) {
if (pkgSetting.getEnabled(userId) == newState) {
// Nothing to do
return;
@@ -20412,11 +20058,11 @@ public class PackageManagerService extends IPackageManager.Stub
// Don't care about who enables an app.
callingPackage = null;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
pkgSetting.setEnabled(newState, userId, callingPackage);
}
} else {
- synchronized (mPackages) {
+ synchronized (mLock) {
// We're dealing with a component level state change
// First, verify that this is a valid class name.
PackageParser.Package pkg = pkgSetting.pkg;
@@ -20453,7 +20099,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
}
- synchronized (mPackages) {
+ synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
updateSequenceNumberLP(pkgSetting, new int[] { userId });
final long callingId = Binder.clearCallingIdentity();
@@ -20514,7 +20160,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
false /* checkShell */, "flushPackageRestrictions");
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.writePackageRestrictionsLPr(userId);
mDirtyUsers.remove(userId);
if (mDirtyUsers.isEmpty()) {
@@ -20561,9 +20207,9 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */, "stop package");
// writer
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (!filterAppAccessLPr(ps, callingUid, userId)
+ if (!shouldFilterApplicationLocked(ps, callingUid, userId)
&& mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
allowedByPermission, callingUid, userId)) {
scheduleWritePackageRestrictionsLocked(userId);
@@ -20574,9 +20220,10 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String getInstallerPackageName(String packageName) {
final int callingUid = Binder.getCallingUid();
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+ if (shouldFilterApplicationLocked(
+ ps, callingUid, UserHandle.getUserId(callingUid))) {
return null;
}
// InstallerPackageName for Apex is not stored in PackageManager
@@ -20589,7 +20236,7 @@ public class PackageManagerService extends IPackageManager.Stub
public boolean isOrphaned(String packageName) {
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
if (!mPackages.containsKey(packageName)) {
return false;
}
@@ -20604,8 +20251,9 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get enabled");
// reader
- synchronized (mPackages) {
- if (filterAppAccessLPr(mSettings.getPackageLPr(packageName), callingUid, userId)) {
+ synchronized (mLock) {
+ if (shouldFilterApplicationLocked(
+ mSettings.getPackageLPr(packageName), callingUid, userId)) {
return COMPONENT_ENABLED_STATE_DISABLED;
}
return mSettings.getApplicationEnabledSettingLPr(packageName, userId);
@@ -20619,8 +20267,9 @@ public class PackageManagerService extends IPackageManager.Stub
int callingUid = Binder.getCallingUid();
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled");
- synchronized (mPackages) {
- if (filterAppAccessLPr(mSettings.getPackageLPr(component.getPackageName()), callingUid,
+ synchronized (mLock) {
+ if (shouldFilterApplicationLocked(
+ mSettings.getPackageLPr(component.getPackageName()), callingUid,
component, TYPE_UNKNOWN, userId)) {
return COMPONENT_ENABLED_STATE_DISABLED;
}
@@ -20681,7 +20330,7 @@ public class PackageManagerService extends IPackageManager.Stub
Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
}
- synchronized (mPackages) {
+ synchronized (mLock) {
// Verify that all of the preferred activity components actually
// exist. It is possible for applications to be updated and at
// that point remove a previously declared activity component that
@@ -20717,8 +20366,18 @@ public class PackageManagerService extends IPackageManager.Stub
// Now that we've scanned all packages, and granted any default
// permissions, ensure permissions are updated. Beware of dragons if you
// try optimizing this.
- synchronized (mPackages) {
+ synchronized (mLock) {
mPermissionManager.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL, false);
+
+ final PermissionPolicyInternal permissionPolicyInternal =
+ LocalServices.getService(PermissionPolicyInternal.class);
+ permissionPolicyInternal.setOnInitializedCallback(userId -> {
+ // The SDK updated case is already handled when we run during the ctor.
+ synchronized (mPackages) {
+ mPermissionManager.updateAllPermissions(
+ StorageManager.UUID_PRIVATE_INTERNAL, false);
+ }
+ });
}
// Watch for external volumes that come and go over time
@@ -21012,7 +20671,7 @@ public class PackageManagerService extends IPackageManager.Stub
} else if ("service-permissions".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_SERVICE_PERMISSIONS);
} else if ("write".equals(cmd)) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.writeLPr();
pw.println("Settings written.");
return;
@@ -21025,7 +20684,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
if (!checkin) {
if (dumpState.onTitlePrinted())
@@ -21404,7 +21063,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void dumpProto(FileDescriptor fd) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
- synchronized (mPackages) {
+ synchronized (mLock) {
final long requiredVerifierPackageToken =
proto.start(PackageServiceDumpProto.REQUIRED_VERIFIER_PACKAGE);
proto.write(PackageServiceDumpProto.PackageShortProto.NAME, mRequiredVerifierPackage);
@@ -21476,7 +21135,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
@SuppressWarnings("resource")
private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
@@ -21505,7 +21164,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
@SuppressWarnings("resource")
private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
@@ -21655,7 +21314,7 @@ public class PackageManagerService extends IPackageManager.Stub
final VersionInfo ver;
final List<PackageSetting> packages;
- synchronized (mPackages) {
+ synchronized (mLock) {
ver = mSettings.findOrCreateVersion(volumeUuid);
packages = mSettings.getVolumePackagesLPr(volumeUuid);
}
@@ -21705,7 +21364,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- synchronized (mPackages) {
+ synchronized (mLock) {
final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
if (sdkUpdated) {
logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
@@ -21741,7 +21400,7 @@ public class PackageManagerService extends IPackageManager.Stub
final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
synchronized (mInstallLock) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid);
for (PackageSetting ps : packages) {
if (ps.pkg == null) continue;
@@ -21786,7 +21445,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
throws PackageManagerException {
- synchronized (mPackages) {
+ synchronized (mLock) {
// Normalize package name to handle renamed packages
packageName = normalizePackageNameLPr(packageName);
@@ -21805,7 +21464,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private List<String> collectAbsoluteCodePaths() {
- synchronized (mPackages) {
+ synchronized (mLock) {
List<String> codePaths = new ArrayList<>();
final int packageCount = mSettings.mPackages.size();
for (int i = 0; i < packageCount; i++) {
@@ -21956,7 +21615,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Ensure that data directories are ready to roll for all packages
// installed for this volume and user
final List<PackageSetting> packages;
- synchronized (mPackages) {
+ synchronized (mLock) {
packages = mSettings.getVolumePackagesLPr(volumeUuid);
}
int preparedCount = 0;
@@ -21998,7 +21657,7 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
final PackageSetting ps;
- synchronized (mPackages) {
+ synchronized (mLock) {
ps = mSettings.mPackages.get(pkg.packageName);
mSettings.writeKernelMappingLPr(ps);
}
@@ -22060,7 +21719,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final PackageSetting ps;
- synchronized (mPackages) {
+ synchronized (mLock) {
ps = mSettings.mPackages.get(pkg.packageName);
}
final String volumeUuid = pkg.volumeUuid;
@@ -22121,7 +21780,7 @@ public class PackageManagerService extends IPackageManager.Stub
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
// TODO: mark this structure as dirty so we persist it!
- synchronized (mPackages) {
+ synchronized (mLock) {
if (ps != null) {
ps.setCeDataInode(ceDataInode, userId);
}
@@ -22251,7 +21910,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
public PackageFreezer(String packageName, int userId, String killReason) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mPackageName = packageName;
mWeFroze = mFrozenPackages.add(mPackageName);
@@ -22289,7 +21948,7 @@ public class PackageManagerService extends IPackageManager.Stub
public void close() {
mCloseGuard.close();
if (mClosed.compareAndSet(false, true)) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if (mWeFroze) {
mFrozenPackages.remove(mPackageName);
}
@@ -22308,7 +21967,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Verify that given package is currently frozen.
*/
private void checkPackageFrozen(String packageName) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if (!mFrozenPackages.contains(packageName)) {
Slog.wtf(TAG, "Expected " + packageName + " to be frozen!", new Throwable());
}
@@ -22352,12 +22011,12 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean isCurrentLocationExternal;
// reader
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.Package pkg = mPackages.get(packageName);
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (pkg == null
|| ps == null
- || filterAppAccessLPr(ps, callingUid, user.getIdentifier())) {
+ || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
}
if (pkg.applicationInfo.isSystemApp()) {
@@ -22565,7 +22224,7 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) {
final PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(packageName);
}
if (pkg == null) {
@@ -22662,7 +22321,7 @@ public class PackageManagerService extends IPackageManager.Stub
/** Called by UserManagerService */
void cleanUpUser(UserManagerService userManager, int userHandle) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mDirtyUsers.remove(userHandle);
mUserNeedsBadging.delete(userHandle);
mSettings.removeUserLPw(userHandle);
@@ -22677,7 +22336,7 @@ public class PackageManagerService extends IPackageManager.Stub
* that are no longer in use by any other user.
* @param userHandle the user being removed
*/
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void removeUnusedPackagesLPw(UserManagerService userManager, final int userHandle) {
final boolean DEBUG_CLEAN_APKS = false;
int [] users = userManager.getUserIds();
@@ -22728,7 +22387,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mInstallLock) {
mSettings.createNewUserLI(this, mInstaller, userId, disallowedPackages);
}
- synchronized (mPackages) {
+ synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
scheduleWritePackageListLocked(userId);
primeDomainVerificationsLPw(userId);
@@ -22745,7 +22404,7 @@ public class PackageManagerService extends IPackageManager.Stub
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
"Only package verification agents can read the verifier device identity");
- synchronized (mPackages) {
+ synchronized (mLock) {
return mSettings.getVerifierDeviceIdentityLPw();
}
}
@@ -22807,14 +22466,15 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null || alias == null) {
return null;
}
- synchronized(mPackages) {
+ synchronized (mLock) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (filterAppAccessLPr(ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+ if (shouldFilterApplicationLocked(
+ ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -22828,7 +22488,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null) {
return null;
}
- synchronized(mPackages) {
+ synchronized (mLock) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final PackageParser.Package pkg = mPackages.get(packageName);
@@ -22837,7 +22497,7 @@ public class PackageManagerService extends IPackageManager.Stub
throw new IllegalArgumentException("Unknown package: " + packageName);
}
final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
// filter and pretend the package doesn't exist
Slog.w(TAG, "KeySet requested for filtered package: " + packageName
+ ", uid:" + callingUid);
@@ -22861,10 +22521,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null || ks == null) {
return false;
}
- synchronized(mPackages) {
+ synchronized (mLock) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null
- || filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid,
+ || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
UserHandle.getUserId(callingUid))) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -22887,10 +22547,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null || ks == null) {
return false;
}
- synchronized(mPackages) {
+ synchronized (mLock) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null
- || filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid,
+ || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
UserHandle.getUserId(callingUid))) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -22904,7 +22564,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void deletePackageIfUnusedLPr(final String packageName) {
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null) {
@@ -23176,7 +22836,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private SigningDetails getSigningDetails(@NonNull String packageName) {
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Package p = mPackages.get(packageName);
if (p == null) {
return null;
@@ -23186,7 +22846,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private SigningDetails getSigningDetails(int uid) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingLPr(appId);
if (obj != null) {
@@ -23213,27 +22873,28 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean filterAppAccess(PackageParser.Package pkg, int callingUid, int userId) {
- synchronized (mPackages) {
- return PackageManagerService.this
- .filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid, userId);
+ synchronized (mLock) {
+ return PackageManagerService.this.shouldFilterApplicationLocked(
+ (PackageSetting) pkg.mExtras, callingUid, userId);
}
}
@Override
public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
return false;
}
return PackageManagerService.this
- .filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid, userId);
+ .shouldFilterApplicationLocked(
+ (PackageSetting) pkg.mExtras, callingUid, userId);
}
}
@Override
public PackageParser.Package getPackage(String packageName) {
- synchronized (mPackages) {
+ synchronized (mLock) {
packageName = resolveInternalPackageNameLPr(
packageName, PackageManager.VERSION_CODE_HIGHEST);
return mPackages.get(packageName);
@@ -23242,7 +22903,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public PackageParser.Package getPackage(int uid) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final String[] packageNames = getPackagesForUid(uid);
PackageParser.Package pkg = null;
final int numPackages = packageNames == null ? 0 : packageNames.length;
@@ -23255,7 +22916,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public PackageList getPackageList(PackageListObserver observer) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final int N = mPackages.size();
final ArrayList<String> list = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
@@ -23271,14 +22932,14 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void removePackageListObserver(PackageListObserver observer) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mPackageListObservers.remove(observer);
}
}
@Override
public PackageParser.Package getDisabledSystemPackage(String packageName) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
return (ps != null) ? ps.pkg : null;
}
@@ -23331,7 +22992,7 @@ public class PackageManagerService extends IPackageManager.Stub
public void setKeepUninstalledPackages(final List<String> packageList) {
Preconditions.checkNotNull(packageList);
List<String> removedFromList = null;
- synchronized (mPackages) {
+ synchronized (mLock) {
if (mKeepUninstalledPackages != null) {
final int packagesCount = mKeepUninstalledPackages.size();
for (int i = 0; i < packagesCount; i++) {
@@ -23357,7 +23018,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isPermissionsReviewRequired(String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
return false;
@@ -23377,7 +23038,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
PersistableBundle launcherExtras = null;
if (ps != null) {
@@ -23389,7 +23050,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isPackageSuspended(String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
return (ps != null) ? ps.getSuspended(userId) : false;
}
@@ -23397,7 +23058,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String getSuspendingPackage(String suspendedPackage, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
return (ps != null) ? ps.readUserState(userId).suspendingPackage : null;
}
@@ -23405,7 +23066,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
return (ps != null) ? ps.readUserState(userId).dialogInfo : null;
}
@@ -23413,7 +23074,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public int getDistractingPackageRestrictions(String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
return (ps != null) ? ps.getDistractionFlags(userId) : RESTRICTION_NONE;
}
@@ -23500,7 +23161,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isPackageEphemeral(int userId, String packageName) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
return ps != null ? ps.getInstantApp(userId) : false;
}
@@ -23508,21 +23169,21 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean wasPackageEverLaunched(String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
}
}
@Override
public boolean isEnabledAndMatches(ComponentInfo info, int flags, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return mSettings.isEnabledAndMatchLPr(info, flags, userId);
}
}
@Override
public boolean userNeedsBadging(int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return PackageManagerService.this.userNeedsBadging(userId);
}
}
@@ -23544,7 +23205,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void grantEphemeralAccess(int userId, Intent intent,
int targetAppId, int ephemeralAppId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
targetAppId, ephemeralAppId);
}
@@ -23552,7 +23213,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isInstantAppInstallerComponent(ComponentName component) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return mInstantAppInstallerActivity != null
&& mInstantAppInstallerActivity.getComponentName().equals(component);
}
@@ -23576,7 +23237,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isPackagePersistent(String packageName) {
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Package pkg = mPackages.get(packageName);
return pkg != null
? ((pkg.applicationInfo.flags&(ApplicationInfo.FLAG_SYSTEM
@@ -23588,7 +23249,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isLegacySystemApp(PackageParser.Package pkg) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = (PackageSetting) pkg.mExtras;
return mPromoteSystemApps
&& ps.isSystem()
@@ -23599,7 +23260,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public List<PackageInfo> getOverlayPackages(int userId) {
final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>();
- synchronized (mPackages) {
+ synchronized (mLock) {
for (PackageParser.Package p : mPackages.values()) {
if (p.mOverlayTarget != null) {
PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId);
@@ -23615,7 +23276,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public List<String> getTargetPackageNames(int userId) {
List<String> targetPackages = new ArrayList<>();
- synchronized (mPackages) {
+ synchronized (mLock) {
for (PackageParser.Package p : mPackages.values()) {
if (p.mOverlayTarget == null) {
targetPackages.add(p.packageName);
@@ -23628,7 +23289,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
@Nullable List<String> overlayPackageNames) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if (targetPackageName == null || mPackages.get(targetPackageName) == null) {
Slog.e(TAG, "failed to find package " + targetPackageName);
return false;
@@ -23675,28 +23336,28 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void addIsolatedUid(int isolatedUid, int ownerUid) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mIsolatedOwners.put(isolatedUid, ownerUid);
}
}
@Override
public void removeIsolatedUid(int isolatedUid) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mIsolatedOwners.delete(isolatedUid);
}
}
@Override
public int getUidTargetSdkVersion(int uid) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return getUidTargetSdkVersionLockedLPr(uid);
}
}
@Override
public int getPackageTargetSdkVersion(String packageName) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return getPackageTargetSdkVersionLockedLPr(packageName);
}
}
@@ -23708,44 +23369,44 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean canAccessComponent(int callingUid, ComponentName component, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
- return ps != null && !PackageManagerService.this.filterAppAccessLPr(
+ return ps != null && !PackageManagerService.this.shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_UNKNOWN, userId);
}
}
@Override
public boolean hasInstantApplicationMetadata(String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return mInstantAppRegistry.hasInstantApplicationMetadataLPr(packageName, userId);
}
}
@Override
public void notifyPackageUse(String packageName, int reason) {
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageManagerService.this.notifyPackageUseLocked(packageName, reason);
}
}
@Override
public SparseArray<String> getAppsWithSharedUserIds() {
- synchronized (mPackages) {
+ synchronized (mLock) {
return getAppsWithSharedUserIdsLocked();
}
}
@Override
public String getSharedUserIdForPackage(String packageName) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return getSharedUserIdForPackageLocked(packageName);
}
}
@Override
public String[] getPackagesForSharedUserId(String sharedUserId, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return getPackagesForSharedUserIdLocked(sharedUserId, userId);
}
}
@@ -23774,7 +23435,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public ArraySet<String> getEnabledComponents(String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting setting = mSettings.getPackageLPr(packageName);
if (setting == null) {
return new ArraySet<>();
@@ -23785,7 +23446,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public ArraySet<String> getDisabledComponents(String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting setting = mSettings.getPackageLPr(packageName);
if (setting == null) {
return new ArraySet<>();
@@ -23797,7 +23458,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public @PackageManager.EnabledState int getApplicationEnabledState(
String packageName, int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageSetting setting = mSettings.getPackageLPr(packageName);
if (setting == null) {
return COMPONENT_ENABLED_STATE_DEFAULT;
@@ -23817,7 +23478,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean compileLayouts(String packageName) {
PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(packageName);
if (pkg == null) {
return false;
@@ -23834,7 +23495,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Nullable
@Override
public String removeLegacyDefaultBrowserPackageName(int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return mSettings.removeDefaultBrowserPackageNameLPw(userId);
}
}
@@ -23887,7 +23548,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void setRuntimePermissionsFingerPrint(@NonNull String fingerPrint,
@UserIdInt int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.setRuntimePermissionsFingerPrintLPr(fingerPrint, userId);
}
}
@@ -23903,7 +23564,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void writeSettings(boolean async) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if (async) {
scheduleWriteSettingsLocked();
} else {
@@ -23914,7 +23575,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void writePermissionSettings(int[] userIds, boolean async) {
- synchronized (mPackages) {
+ synchronized (mLock) {
for (int userId : userIds) {
mSettings.writeRuntimePermissionsForUserLPr(userId, !async);
}
@@ -23925,7 +23586,7 @@ public class PackageManagerService extends IPackageManager.Stub
public int getTargetSdk(int uid) {
int userId = UserHandle.getUserId(uid);
- synchronized (mPackages) {
+ synchronized (mLock) {
final Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
if (obj instanceof PackageSetting) {
final PackageSetting ps = (PackageSetting) obj;
@@ -23956,7 +23617,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean isCallerInstallerOfRecord(
@NonNull PackageParser.Package pkg, int callingUid) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if (pkg == null) {
return false;
}
@@ -23973,14 +23634,14 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public boolean areDefaultRuntimePermissionsGranted(int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
return mSettings.areDefaultRuntimePermissionsGrantedLPr(userId);
}
}
@Override
public void setReadExternalStorageEnforced(boolean enforced) {
- synchronized (mPackages) {
+ synchronized (mLock) {
if (mSettings.mReadExternalStorageEnforced != null
&& mSettings.mReadExternalStorageEnforced == enforced) {
return;
@@ -23991,10 +23652,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private SparseArray<String> getAppsWithSharedUserIdsLocked() {
final SparseArray<String> sharedUserIds = new SparseArray<>();
- synchronized (mPackages) {
+ synchronized (mLock) {
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
sharedUserIds.put(UserHandle.getAppId(setting.userId), setting.name);
}
@@ -24002,13 +23663,13 @@ public class PackageManagerService extends IPackageManager.Stub
return sharedUserIds;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private String getSharedUserIdForPackageLocked(String packageName) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
return (ps != null && ps.isSharedUser()) ? ps.sharedUser.name : null;
}
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private String[] getPackagesForSharedUserIdLocked(String sharedUserId, int userId) {
try {
final SharedUserSetting sus = mSettings.getSharedUserLPw(
@@ -24040,7 +23701,7 @@ public class PackageManagerService extends IPackageManager.Stub
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
"setRuntimePermissionVersion");
- synchronized (mPackages) {
+ synchronized (mLock) {
return mSettings.getDefaultRuntimePermissionsVersionLPr(userId);
}
}
@@ -24052,13 +23713,13 @@ public class PackageManagerService extends IPackageManager.Stub
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
"setRuntimePermissionVersion");
- synchronized (mPackages) {
+ synchronized (mLock) {
mSettings.setDefaultRuntimePermissionsVersionLPr(version, userId);
}
}
void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
- synchronized (mPackages) {
+ synchronized (mLock) {
int numPackages = mPackages.size();
for (int i = 0; i < numPackages; i++) {
actionLocked.accept(mPackages.valueAt(i));
@@ -24068,7 +23729,7 @@ public class PackageManagerService extends IPackageManager.Stub
void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked,
@UserIdInt int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
int numPackages = mPackages.size();
for (int i = 0; i < numPackages; i++) {
PackageParser.Package pkg = mPackages.valueAt(i);
@@ -24090,7 +23751,7 @@ public class PackageManagerService extends IPackageManager.Stub
* @return A copy of the values of mPackages.
*/
Collection<PackageParser.Package> getPackages() {
- synchronized (mPackages) {
+ synchronized (mLock) {
return new ArrayList<>(mPackages.values());
}
}
@@ -24143,9 +23804,9 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */,
"get install reason");
- synchronized (mPackages) {
+ synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (filterAppAccessLPr(ps, callingUid, userId)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return PackageManager.INSTALL_REASON_UNKNOWN;
}
if (ps != null) {
@@ -24229,13 +23890,13 @@ public class PackageManagerService extends IPackageManager.Stub
if (!isInstantApp(packageName, userId)) {
return null;
}
- synchronized (mPackages) {
+ synchronized (mLock) {
return mInstantAppRegistry.getInstantAppAndroidIdLPw(packageName, userId);
}
}
boolean canHaveOatDir(String packageName) {
- synchronized (mPackages) {
+ synchronized (mLock) {
PackageParser.Package p = mPackages.get(packageName);
if (p == null) {
return false;
@@ -24260,7 +23921,7 @@ public class PackageManagerService extends IPackageManager.Stub
final List<String> codePaths;
final String oatDir;
final PackageParser.Package pkg;
- synchronized (mPackages) {
+ synchronized (mLock) {
pkg = mPackages.get(packageName);
}
instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
@@ -24281,7 +23942,7 @@ public class PackageManagerService extends IPackageManager.Stub
Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
Set<String> unusedPackages = new HashSet<>();
long currentTimeInMillis = System.currentTimeMillis();
- synchronized (mPackages) {
+ synchronized (mLock) {
for (PackageParser.Package pkg : mPackages.values()) {
PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
if (ps == null) {
@@ -24316,7 +23977,7 @@ public class PackageManagerService extends IPackageManager.Stub
+ SET_HARMFUL_APP_WARNINGS + " permission.");
}
- synchronized(mPackages) {
+ synchronized (mLock) {
mSettings.setHarmfulAppWarningLPw(packageName, warning, userId);
scheduleWritePackageRestrictionsLocked(userId);
}
@@ -24337,7 +23998,7 @@ public class PackageManagerService extends IPackageManager.Stub
+ SET_HARMFUL_APP_WARNINGS + " permission.");
}
- synchronized(mPackages) {
+ synchronized (mLock) {
return mSettings.getHarmfulAppWarningLPr(packageName, userId);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 58f262c4c889..029673ffd87b 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -270,7 +270,8 @@ public abstract class PackageSettingBase extends SettingBase {
updateAvailable = orig.updateAvailable;
}
- private PackageUserState modifyUserState(int userId) {
+ @VisibleForTesting
+ PackageUserState modifyUserState(int userId) {
PackageUserState state = mUserState.get(userId);
if (state == null) {
state = new PackageUserState();
@@ -463,6 +464,18 @@ public abstract class PackageSettingBase extends SettingBase {
state.harmfulAppWarning = harmfulAppWarning;
}
+ void setUserState(int userId, PackageUserState otherState) {
+ setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed,
+ otherState.stopped, otherState.notLaunched, otherState.hidden,
+ otherState.distractionFlags, otherState.suspended, otherState.suspendingPackage,
+ otherState.dialogInfo, otherState.suspendedAppExtras,
+ otherState.suspendedLauncherExtras, otherState.instantApp,
+ otherState.virtualPreload, otherState.lastDisableAppCaller,
+ otherState.enabledComponents, otherState.disabledComponents,
+ otherState.domainVerificationStatus, otherState.appLinkGeneration,
+ otherState.installReason, otherState.harmfulAppWarning);
+ }
+
ArraySet<String> getEnabledComponents(int userId) {
return readUserState(userId).enabledComponents;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 3bc2236a8221..c1cb53d4ff0f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4020,7 +4020,7 @@ public final class Settings {
String[] seinfos;
int[] targetSdkVersions;
int packagesCount;
- synchronized (mPackages) {
+ synchronized (mLock) {
Collection<PackageSetting> packages = mPackages.values();
packagesCount = packages.size();
volumeUuids = new String[packagesCount];
@@ -4064,7 +4064,7 @@ public final class Settings {
Slog.w(TAG, "Failed to prepare app data", e);
}
}
- synchronized (mPackages) {
+ synchronized (mLock) {
applyDefaultPreferredAppsLPw(userHandle);
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index bf141a0f139b..bdeaf028bac8 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -180,6 +180,8 @@ public class StagingManager {
checkDowngrade(session, activePackage, pkg);
result.add(pkg);
}
+ Slog.d(TAG, "Session " + session.sessionId + " has following APEX packages: ["
+ + result.stream().map(p -> p.packageName).collect(Collectors.joining(",")) + "]");
return result;
}
@@ -206,7 +208,7 @@ public class StagingManager {
throws PackageManagerException {
final long activeVersion = activePackage.applicationInfo.longVersionCode;
final long newVersionCode = newPackage.applicationInfo.longVersionCode;
- boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
+ final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
session.params.installFlags, activePackage.applicationInfo.flags);
if (activeVersion > newVersionCode && !allowsDowngrade) {
if (!mApexManager.abortActiveSession()) {
@@ -225,6 +227,7 @@ public class StagingManager {
}
private void preRebootVerification(@NonNull PackageInstallerSession session) {
+ Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId);
final boolean hasApex = sessionContainsApex(session);
// APEX checks. For single-package sessions, check if they contain an APEX. For
// multi-package sessions, find all the child sessions that contain an APEX.
@@ -243,6 +246,8 @@ public class StagingManager {
if (sessionContainsApk(session)) {
try {
+ Slog.d(TAG, "Running a pre-reboot verification for APKs in session "
+ + session.sessionId + " by performing a dry-run install");
installApksInSession(session, /* preReboot */ true);
// TODO(b/118865310): abort the session on apexd.
} catch (PackageManagerException e) {
@@ -277,6 +282,7 @@ public class StagingManager {
// On the other hand, if the order of the calls was inverted (first call apexd, then mark
// session as ready), then if a device gets rebooted right after the call to apexd, only
// apex part of the train will be applied, leaving device in an inconsistent state.
+ Slog.d(TAG, "Marking session " + session.sessionId + " as ready");
session.setStagedSessionReady();
if (!hasApex) {
// Session doesn't contain apex, nothing to do.
@@ -315,6 +321,7 @@ public class StagingManager {
}
private void resumeSession(@NonNull PackageInstallerSession session) {
+ Slog.d(TAG, "Resuming session " + session.sessionId);
final boolean hasApex = sessionContainsApex(session);
if (hasApex) {
// Check with apexservice whether the apex packages have been activated.
@@ -348,9 +355,12 @@ public class StagingManager {
+ "retry at next reboot.");
return;
}
+ Slog.i(TAG, "APEX packages in session " + session.sessionId
+ + " were successfully activated. Proceeding with APK packages, if any");
}
// The APEX part of the session is activated, proceed with the installation of APKs.
try {
+ Slog.d(TAG, "Installing APK packages in session " + session.sessionId);
installApksInSession(session, /* preReboot */ false);
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
@@ -370,6 +380,7 @@ public class StagingManager {
return;
}
+ Slog.d(TAG, "Marking session " + session.sessionId + " as applied");
session.setStagedSessionApplied();
if (hasApex) {
mApexManager.markStagedSessionSuccessful(session.sessionId);
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index b829f0b53086..f7b60c25ce4a 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -8,6 +8,20 @@
},
{
"name": "CtsCompilationTestCases"
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pm."
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
],
"postsubmit": [
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 fe0b3a3966f9..3e655edf5db0 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1170,6 +1170,11 @@ public final class DefaultPermissionGrantPolicy {
final int flags = mContext.getPackageManager().getPermissionFlags(
permission, pkg.packageName, user);
+ // If we are trying to grant as system fixed and already system fixed
+ // then the system can change the system fixed grant state.
+ final boolean changingGrantForSystemFixed = systemFixed
+ && (flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0;
+
// Certain flags imply that the permission's current state by the system or
// device/profile owner or the user. In these cases we do not want to clobber the
// current state.
@@ -1177,7 +1182,8 @@ public final class DefaultPermissionGrantPolicy {
// Unless the caller wants to override user choices. The override is
// to make sure we can grant the needed permission to the default
// sms and phone apps after the user chooses this in the UI.
- if (!isFixedOrUserSet(flags) || ignoreSystemPackage) {
+ if (!isFixedOrUserSet(flags) || ignoreSystemPackage
+ || changingGrantForSystemFixed) {
// Never clobber policy fixed permissions.
// We must allow the grant of a system-fixed permission because
// system-fixed is sticky, but the permission itself may be revoked.
@@ -1196,6 +1202,14 @@ public final class DefaultPermissionGrantPolicy {
PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user);
}
+ // If the system tries to change a system fixed permission from one fixed
+ // state to another we need to drop the fixed flag to allow the grant.
+ if (changingGrantForSystemFixed) {
+ mContext.getPackageManager().updatePermissionFlags(permission,
+ pkg.packageName, flags,
+ flags & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, user);
+ }
+
if (pm.checkPermission(permission, pkg.packageName)
!= PackageManager.PERMISSION_GRANTED) {
mContext.getPackageManager()
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 03be8e119e03..210a7afb11a2 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -125,6 +125,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal.Default
import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultHomeProvider;
import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionsState.PermissionState;
+import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
import libcore.util.EmptyArray;
@@ -227,6 +228,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@GuardedBy("mLock")
private boolean mSystemReady;
+ @GuardedBy("mLock")
+ private PermissionPolicyInternal mPermissionPolicyInternal;
+
/**
* For each foreground/background permission the mapping:
* Background permission -> foreground permissions
@@ -1451,7 +1455,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param pkg The package for which to reset.
* @param userId The device user for which to do a reset.
*/
- @GuardedBy("mPackages")
+ @GuardedBy("mLock")
private void resetRuntimePermissionsInternal(final PackageParser.Package pkg,
final int userId) {
final String packageName = pkg.packageName;
@@ -2443,6 +2447,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean softRestricted = bp.isSoftRestricted();
for (int userId : currentUserIds) {
+ // If permission policy is not ready we don't deal with restricted
+ // permissions as the policy may whitelist some permissions. Once
+ // the policy is initialized we would re-evaluate permissions.
+ final boolean permissionPolicyInitialized =
+ mPermissionPolicyInternal != null
+ && mPermissionPolicyInternal.isInitialized(userId);
+
PermissionState permState = origPermissions
.getRuntimePermissionState(perm, userId);
int flags = permState != null ? permState.getFlags() : 0;
@@ -2457,7 +2468,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (appSupportsRuntimePermissions) {
// If hard restricted we don't allow holding it
- if (hardRestricted) {
+ if (permissionPolicyInitialized && hardRestricted) {
if (!restrictionExempt) {
if (permState != null && permState.isGranted()
&& permissionsState.revokeRuntimePermission(
@@ -2470,7 +2481,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
// If soft restricted we allow holding in a restricted form
- } else if (softRestricted) {
+ } else if (permissionPolicyInitialized && softRestricted) {
// Regardless if granted set the restriction flag as it
// may affect app treatment based on this permission.
if (!restrictionExempt && !restrictionApplied) {
@@ -2489,7 +2500,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
wasChanged = true;
// Hard restricted permissions cannot be held.
- } else if (!hardRestricted || restrictionExempt) {
+ } else if (!permissionPolicyInitialized
+ || (!hardRestricted || restrictionExempt)) {
if (permState != null && permState.isGranted()) {
if (permissionsState.grantRuntimePermission(bp, userId)
== PERMISSION_OPERATION_FAILURE) {
@@ -2518,33 +2530,28 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// If legacy app always grant the permission but if restricted
// and not exempt take a note a restriction should be applied.
- if ((hardRestricted || softRestricted)
- && !restrictionExempt && !restrictionApplied) {
+ if (permissionPolicyInitialized
+ && (hardRestricted || softRestricted)
+ && !restrictionExempt && !restrictionApplied) {
flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
wasChanged = true;
}
}
// If unrestricted or restriction exempt, don't apply restriction.
- if (!(hardRestricted || softRestricted) || restrictionExempt) {
- if (restrictionApplied) {
- flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
- // Dropping restriction on a legacy app requires a review.
- if (!appSupportsRuntimePermissions) {
- flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ if (permissionPolicyInitialized) {
+ if (!(hardRestricted || softRestricted) || restrictionExempt) {
+ if (restrictionApplied) {
+ flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
+ // Dropping restriction on a legacy app implies a review
+ if (!appSupportsRuntimePermissions) {
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ }
+ wasChanged = true;
}
- wasChanged = true;
}
}
- if (hardRestricted && !restrictionExempt
- && (flags & FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
- // Applying a hard restriction implies revoking it. This might
- // lead to a system-fixed, revoked permission.
- flags &= ~FLAG_PERMISSION_SYSTEM_FIXED;
- wasChanged = true;
- }
-
if (wasChanged) {
updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
}
@@ -2579,6 +2586,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean softRestricted = bp.isSoftRestricted();
for (int userId : currentUserIds) {
+ // If permission policy is not ready we don't deal with restricted
+ // permissions as the policy may whitelist some permissions. Once
+ // the policy is initialized we would re-evaluate permissions.
+ final boolean permissionPolicyInitialized =
+ mPermissionPolicyInternal != null
+ && mPermissionPolicyInternal.isInitialized(userId);
+
boolean wasChanged = false;
boolean restrictionExempt =
@@ -2589,7 +2603,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (appSupportsRuntimePermissions) {
// If hard restricted we don't allow holding it
- if (hardRestricted) {
+ if (permissionPolicyInitialized && hardRestricted) {
if (!restrictionExempt) {
if (permState != null && permState.isGranted()
&& permissionsState.revokeRuntimePermission(
@@ -2602,7 +2616,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
// If soft restricted we allow holding in a restricted form
- } else if (softRestricted) {
+ } else if (permissionPolicyInitialized && softRestricted) {
// Regardless if granted set the restriction flag as it
// may affect app treatment based on this permission.
if (!restrictionExempt && !restrictionApplied) {
@@ -2621,7 +2635,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
wasChanged = true;
// Hard restricted permissions cannot be held.
- } else if (!hardRestricted || restrictionExempt) {
+ } else if (!permissionPolicyInitialized ||
+ (!hardRestricted || restrictionExempt)) {
if (permissionsState.grantRuntimePermission(bp, userId) !=
PERMISSION_OPERATION_FAILURE) {
wasChanged = true;
@@ -2637,22 +2652,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// If legacy app always grant the permission but if restricted
// and not exempt take a note a restriction should be applied.
- if ((hardRestricted || softRestricted)
- && !restrictionExempt && !restrictionApplied) {
+ if (permissionPolicyInitialized
+ && (hardRestricted || softRestricted)
+ && !restrictionExempt && !restrictionApplied) {
flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
wasChanged = true;
}
}
// If unrestricted or restriction exempt, don't apply restriction.
- if (!(hardRestricted || softRestricted) || restrictionExempt) {
- if (restrictionApplied) {
- flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
- // Dropping restriction on a legacy app requires a review.
- if (!appSupportsRuntimePermissions) {
- flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ if (permissionPolicyInitialized) {
+ if (!(hardRestricted || softRestricted) || restrictionExempt) {
+ if (restrictionApplied) {
+ flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
+ // Dropping restriction on a legacy app implies a review
+ if (!appSupportsRuntimePermissions) {
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ }
+ wasChanged = true;
}
- wasChanged = true;
}
}
@@ -3959,6 +3977,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
+ mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
for (int userId : UserManagerService.getInstance().getUserIds()) {
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
index 7760c1edd9e6..6084c6718577 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
@@ -18,6 +18,7 @@ package com.android.server.policy;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.Intent;
/**
@@ -26,6 +27,19 @@ import android.content.Intent;
public abstract class PermissionPolicyInternal {
/**
+ * Callback for initializing the permission policy service.
+ */
+ public interface OnInitializedCallback {
+
+ /**
+ * Called when initialized for the given user.
+ *
+ * @param userId The initialized user.
+ */
+ void onInitialized(@UserIdInt int userId);
+ }
+
+ /**
* Check whether an activity should be started.
*
* @param intent the {@link Intent} for the activity start
@@ -36,4 +50,17 @@ public abstract class PermissionPolicyInternal {
*/
public abstract boolean checkStartActivity(@NonNull Intent intent, int callingUid,
@Nullable String callingPackage);
+
+ /**
+ * @return Whether the policy is initialized for a user.
+ */
+ public abstract boolean isInitialized(@UserIdInt int userId);
+
+ /**
+ * Set a callback for users being initialized. If the user is already
+ * initialized the callback will not be invoked.
+ *
+ * @param callback The callback to register.
+ */
+ public abstract void setOnInitializedCallback(@NonNull OnInitializedCallback callback);
}
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 8da7f7bb6898..f68a06bb191a 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -66,6 +66,7 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
@@ -86,6 +87,10 @@ public final class PermissionPolicyService extends SystemService {
@GuardedBy("mLock")
private final SparseBooleanArray mIsStarted = new SparseBooleanArray();
+ /** Callbacks for when a user is initialized */
+ @GuardedBy("mLock")
+ private OnInitializedCallback mOnInitializedCallback;
+
/**
* Whether an async {@link #synchronizePackagePermissionsAndAppOpsForUser} is currently
* scheduled for a package/user.
@@ -240,12 +245,20 @@ public final class PermissionPolicyService extends SystemService {
grantOrUpgradeDefaultRuntimePermissionsIfNeeded(userId);
+ final OnInitializedCallback callback;
+
synchronized (mLock) {
mIsStarted.put(userId, true);
+ callback = mOnInitializedCallback;
}
// Force synchronization as permissions might have changed
synchronizePermissionsAndAppOpsForUser(userId);
+
+ // Tell observers we are initialized for this user.
+ if (callback != null) {
+ callback.onInitialized(userId);
+ }
}
@Override
@@ -809,6 +822,18 @@ public final class PermissionPolicyService extends SystemService {
return true;
}
+ @Override
+ public boolean isInitialized(int userId) {
+ return isStarted(userId);
+ }
+
+ @Override
+ public void setOnInitializedCallback(@NonNull OnInitializedCallback callback) {
+ synchronized (mLock) {
+ mOnInitializedCallback = callback;
+ }
+ }
+
/**
* Check if the intent action is removed for the calling package (often based on target SDK
* version). If the action is removed, we'll silently cancel the activity launch.
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index e139ab86775d..4970862070bb 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -188,7 +188,7 @@ public class PinnedSliceState {
b.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
try {
client.call(SliceProvider.METHOD_PIN, null, b);
- } catch (RemoteException e) {
+ } catch (Exception e) {
Log.w(TAG, "Unable to contact " + mUri, e);
}
}
@@ -201,7 +201,7 @@ public class PinnedSliceState {
b.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
try {
client.call(SliceProvider.METHOD_UNPIN, null, b);
- } catch (RemoteException e) {
+ } catch (Exception e) {
Log.w(TAG, "Unable to contact " + mUri, e);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 015464e94ffc..31e8bbdab71c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -30,6 +30,7 @@ import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
+import static android.app.ActivityOptions.ANIM_UNDEFINED;
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.AppOpsManager.MODE_ALLOWED;
@@ -2096,6 +2097,7 @@ final class ActivityRecord extends ConfigurationContainer {
pendingOptions.getRemoteAnimationAdapter());
break;
case ANIM_NONE:
+ case ANIM_UNDEFINED:
break;
default:
Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index beff5fb7a8f9..1c56a107ab9e 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1191,8 +1191,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final PackageInfo packageInfo;
try {
packageInfo = mService.mContext.getPackageManager()
- .getPackageInfoAsUser(callingPackage, PackageManager.GET_PERMISSIONS,
- UserHandle.getUserId(callingUid));
+ .getPackageInfo(callingPackage, PackageManager.GET_PERMISSIONS);
} catch (PackageManager.NameNotFoundException e) {
Slog.i(TAG, "Cannot find package info for " + callingPackage);
return ACTIVITY_RESTRICTION_NONE;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a334ed8ad281..9ed93c46733a 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -187,6 +187,7 @@ class ActivityStarter {
private boolean mNoAnimation;
private boolean mKeepCurTransition;
private boolean mAvoidMoveToFront;
+ private boolean mFrozeTaskList;
// We must track when we deliver the new intent since multiple code paths invoke
// {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -483,6 +484,7 @@ class ActivityStarter {
mNoAnimation = starter.mNoAnimation;
mKeepCurTransition = starter.mKeepCurTransition;
mAvoidMoveToFront = starter.mAvoidMoveToFront;
+ mFrozeTaskList = starter.mFrozeTaskList;
mVoiceSession = starter.mVoiceSession;
mVoiceInteractor = starter.mVoiceInteractor;
@@ -1093,6 +1095,14 @@ class ActivityStarter {
void postStartActivityProcessing(ActivityRecord r, int result,
ActivityStack startedActivityStack) {
+ if (!ActivityManager.isStartResultSuccessful(result)) {
+ if (mFrozeTaskList) {
+ // If we specifically froze the task list as part of starting an activity, then
+ // reset the frozen list state if it failed to start. This is normally otherwise
+ // called when the freeze-timeout has elapsed.
+ mSupervisor.mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
+ }
+ }
if (ActivityManager.isStartResultFatalError(result)) {
return;
}
@@ -1485,6 +1495,14 @@ class ActivityStarter {
mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
: DEFAULT_DISPLAY;
+ // If requested, freeze the task list
+ if (mOptions != null && mOptions.freezeRecentTasksReordering()
+ && mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)
+ && !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {
+ mFrozeTaskList = true;
+ mSupervisor.mRecentTasks.setFreezeTaskListReordering();
+ }
+
// Do not start home activity if it cannot be launched on preferred display. We are not
// doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
// fallback to launch on other displays.
@@ -1776,6 +1794,7 @@ class ActivityStarter {
mNoAnimation = false;
mKeepCurTransition = false;
mAvoidMoveToFront = false;
+ mFrozeTaskList = false;
mVoiceSession = null;
mVoiceInteractor = null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7e741a01868b..b351faf7e9f1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1012,7 +1012,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public final int startActivities(IApplicationThread caller, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
int userId) {
- assertPackageMatchesCallingUid(callingPackage);
final String reason = "startActivities";
enforceNotIsolatedCaller(reason);
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason);
@@ -1032,11 +1031,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
true /*validateIncomingUser*/);
}
- private int startActivityAsUser(IApplicationThread caller, String callingPackage,
+ int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
- assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
@@ -1209,7 +1207,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
final WaitResult res = new WaitResult();
synchronized (mGlobalLock) {
enforceNotIsolatedCaller("startActivityAndWait");
@@ -1237,7 +1234,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public final int startActivityWithConfig(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, Configuration config, Bundle bOptions, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
synchronized (mGlobalLock) {
enforceNotIsolatedCaller("startActivityWithConfig");
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
@@ -1287,7 +1283,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, IBinder permissionToken,
boolean ignoreTargetSecurity, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
// This is very dangerous -- it allows you to perform a start activity (including
// permission grants) as any app that may launch one of your own activities. So we only
// allow this in two cases:
@@ -1417,7 +1412,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Intent intent, String resolvedType, IVoiceInteractionSession session,
IVoiceInteractor interactor, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startVoiceActivity()");
if (session == null || interactor == null) {
throw new NullPointerException("null session or interactor");
@@ -1441,7 +1435,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public int startAssistantActivity(String callingPackage, int callingPid, int callingUid,
Intent intent, String resolvedType, Bundle bOptions, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
userId = handleIncomingUser(callingPid, callingUid, userId, "startAssistantActivity");
@@ -2367,9 +2360,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,
@Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options,
boolean fromRecents) {
+
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
- assertPackageMatchesCallingUid(callingPackage);
+ if (!isSameApp(callingUid, callingPackage)) {
+ String msg = "Permission Denial: moveTaskToFrontLocked() from pid="
+ + Binder.getCallingPid() + " as package " + callingPackage;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
if (!checkAppSwitchAllowedLocked(callingPid, callingUid, -1, -1, "Task to front")) {
SafeActivityOptions.abort(options);
return;
@@ -2421,7 +2420,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/**
* Return true if callingUid is system, or packageName belongs to that callingUid.
*/
- private boolean isSameApp(int callingUid, @Nullable String packageName) {
+ boolean isSameApp(int callingUid, @Nullable String packageName) {
try {
if (callingUid != 0 && callingUid != SYSTEM_UID) {
if (packageName == null) {
@@ -2438,21 +2437,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return true;
}
- /**
- * Checks that the provided package name matches the current calling UID, throws a security
- * exception if it doesn't.
- */
- void assertPackageMatchesCallingUid(@Nullable String packageName) {
- final int callingUid = Binder.getCallingUid();
- if (isSameApp(callingUid, packageName)) {
- return;
- }
- final String msg = "Permission Denial: package=" + packageName
- + " does not belong to uid=" + callingUid;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
-
boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
int callingPid, int callingUid, String name) {
if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
@@ -2986,7 +2970,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public List<IBinder> getAppTasks(String callingPackage) {
int callingUid = Binder.getCallingUid();
- assertPackageMatchesCallingUid(callingPackage);
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -6093,7 +6076,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
SafeActivityOptions options, int userId, boolean validateIncomingUser,
PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart) {
- assertPackageMatchesCallingUid(callingPackage);
synchronized (mGlobalLock) {
return getActivityStartController().startActivitiesInPackage(uid, realCallingPid,
realCallingUid, callingPackage, intents, resolvedTypes, resultTo, options,
@@ -6109,7 +6091,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart) {
- assertPackageMatchesCallingUid(callingPackage);
synchronized (mGlobalLock) {
return getActivityStartController().startActivityInPackage(uid, realCallingPid,
realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho,
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index a8f7768efc87..1eb7455135c7 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -27,6 +27,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
+import android.util.Slog;
/**
* An implementation of IAppTask, that allows an app to manage its own tasks via
@@ -96,7 +97,12 @@ class AppTaskImpl extends IAppTask.Stub {
// Will bring task to front if it already has a root activity.
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
- mService.assertPackageMatchesCallingUid(callingPackage);
+ if (!mService.isSameApp(callingUid, callingPackage)) {
+ String msg = "Permission Denial: moveToFront() from pid="
+ + Binder.getCallingPid() + " as package " + callingPackage;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mService.mGlobalLock) {
@@ -128,7 +134,6 @@ class AppTaskImpl extends IAppTask.Stub {
public int startActivity(IBinder whoThread, String callingPackage,
Intent intent, String resolvedType, Bundle bOptions) {
checkCaller();
- mService.assertPackageMatchesCallingUid(callingPackage);
int callingUser = UserHandle.getCallingUserId();
TaskRecord tr;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 592fa5800425..aefc152cb286 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -2487,7 +2487,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
// transformed the task.
final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
if (controller != null && controller.isAnimatingTask(getTask())
- && controller.shouldCancelWithDeferredScreenshot()) {
+ && controller.shouldDeferCancelUntilNextTransition()) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index a46fa13adf4e..207e8ef728eb 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -30,6 +30,7 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.os.Environment;
+import android.os.FileUtils;
import android.provider.Settings;
import android.util.AtomicFile;
import android.util.Slog;
@@ -64,6 +65,11 @@ import java.util.HashMap;
class DisplayWindowSettings {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayWindowSettings" : TAG_WM;
+ private static final String SYSTEM_DIRECTORY = "system";
+ private static final String DISPLAY_SETTINGS_FILE_NAME = "display_settings.xml";
+ private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/" + DISPLAY_SETTINGS_FILE_NAME;
+ private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
+
private static final int IDENTIFIER_UNIQUE_ID = 0;
private static final int IDENTIFIER_PORT = 1;
@IntDef(prefix = { "IDENTIFIER_" }, value = {
@@ -688,8 +694,26 @@ class DisplayWindowSettings {
private final AtomicFile mAtomicFile;
AtomicFileStorage() {
- final File folder = new File(Environment.getDataDirectory(), "system");
- mAtomicFile = new AtomicFile(new File(folder, "display_settings.xml"), "wm-displays");
+ final File folder = new File(Environment.getDataDirectory(), SYSTEM_DIRECTORY);
+ final File settingsFile = new File(folder, DISPLAY_SETTINGS_FILE_NAME);
+ // If display_settings.xml doesn't exist, try to copy the vendor's one instead
+ // in order to provide the vendor specific initialization.
+ if (!settingsFile.exists()) {
+ copyVendorSettings(settingsFile);
+ }
+ mAtomicFile = new AtomicFile(settingsFile, WM_DISPLAY_COMMIT_TAG);
+ }
+
+ private static void copyVendorSettings(File target) {
+ final File vendorFile = new File(Environment.getVendorDirectory(),
+ VENDOR_DISPLAY_SETTINGS_PATH);
+ if (vendorFile.canRead()) {
+ try {
+ FileUtils.copy(vendorFile, target);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to copy vendor display_settings.xml");
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 422b6e58e0ed..85ba95f7d6de 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -90,24 +90,11 @@ class KeyguardController {
}
/**
- * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
- * on the given display, false otherwise.
+ * @return true if either 1) AOD is showing, or 2) Keyguard is showing, not going away, and not
+ * being occluded on the given display, false otherwise.
*/
boolean isKeyguardOrAodShowing(int displayId) {
- return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
- && !isDisplayOccluded(displayId);
- }
-
- /**
- * @return {@code true} for default display when AOD is showing. Otherwise, same as
- * {@link #isKeyguardOrAodShowing(int)}
- * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic.
- */
- boolean isKeyguardUnoccludedOrAodShowing(int displayId) {
- if (displayId == DEFAULT_DISPLAY && mAodShowing) {
- return true;
- }
- return isKeyguardOrAodShowing(displayId);
+ return mAodShowing || isKeyguardShowing(displayId);
}
/**
@@ -115,7 +102,7 @@ class KeyguardController {
* display, false otherwise
*/
boolean isKeyguardShowing(int displayId) {
- return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
+ return mKeyguardShowing && !mKeyguardGoingAway && !isKeyguardOccluded(displayId);
}
/**
@@ -328,7 +315,7 @@ class KeyguardController {
return;
}
- mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
+ mWindowManager.onKeyguardOccludedChanged(isKeyguardOccluded(DEFAULT_DISPLAY));
if (isKeyguardLocked()) {
mWindowManager.deferSurfaceLayout();
try {
@@ -373,7 +360,7 @@ class KeyguardController {
}
}
- private boolean isDisplayOccluded(int displayId) {
+ private boolean isKeyguardOccluded(int displayId) {
return getDisplay(displayId).mOccluded;
}
@@ -391,13 +378,13 @@ class KeyguardController {
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
&& dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
// TODO(b/113840485): Handle app transition for individual display.
- && isDisplayOccluded(DEFAULT_DISPLAY)) {
+ && isKeyguardOccluded(DEFAULT_DISPLAY)) {
// Reuse old transit in case we are occluding Keyguard again, meaning that we never
// actually occclude/unocclude Keyguard, but just run a normal transition.
return mBeforeUnoccludeTransit;
// TODO(b/113840485): Handle app transition for individual display.
- } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
+ } else if (!isKeyguardOccluded(DEFAULT_DISPLAY)) {
// Save transit in case we dismiss/occlude Keyguard shortly after.
mBeforeUnoccludeTransit = dc.mAppTransition.getAppTransition();
@@ -409,7 +396,7 @@ class KeyguardController {
private void dismissDockedStackIfNeeded() {
// TODO(b/113840485): Handle docked stack for individual display.
- if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {
+ if (mKeyguardShowing && isKeyguardOccluded(DEFAULT_DISPLAY)) {
// The lock screen is currently showing, but is occluded by a window that can
// show on top of the lock screen. In this can we want to dismiss the docked
// stack since it will be complicated/risky to try to put the activity on top
@@ -434,9 +421,9 @@ class KeyguardController {
private void updateKeyguardSleepToken(int displayId) {
final KeyguardDisplayState state = getDisplay(displayId);
- if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
+ if (isKeyguardOrAodShowing(displayId) && state.mSleepToken == null) {
state.acquiredSleepToken();
- } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
+ } else if (!isKeyguardOrAodShowing(displayId) && state.mSleepToken != null) {
state.releaseSleepToken();
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index bf627ec5680c..0a3e7a4860d5 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -355,7 +355,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// launch-behind state is restored. That also prevents the next transition
// type being disturbed if the visibility is updated after setting the next
// transition (the target activity will be one of closing apps).
- if (!controller.shouldCancelWithDeferredScreenshot()
+ if (!controller.shouldDeferCancelWithScreenshot()
&& !targetStack.isFocusedStackOnDisplay()) {
targetStack.ensureActivitiesVisibleLocked(null /* starting */,
0 /* starting */, false /* preserveWindows */);
@@ -415,16 +415,18 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
final DisplayContent dc =
mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
dc.mBoundsAnimationController.setAnimationType(
- controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS);
+ controller.shouldDeferCancelUntilNextTransition() ? FADE_IN : BOUNDS);
- // Cancel running recents animation and screenshot previous task when the next
- // transition starts in below cases:
- // 1) The next launching task is not in recents animation task.
+ // We defer canceling the recents animation until the next app transition in the following
+ // cases:
+ // 1) The next launching task is not being animated by the recents animation
// 2) The next task is home activity. (i.e. pressing home key to back home in recents).
if ((!controller.isAnimatingTask(stack.getTaskStack().getTopChild())
|| controller.isTargetApp(stack.getTopActivity().mAppWindowToken))
- && controller.shouldCancelWithDeferredScreenshot()) {
- controller.cancelOnNextTransitionStart();
+ && controller.shouldDeferCancelUntilNextTransition()) {
+ // Always prepare an app transition since we rely on the transition callbacks to cleanup
+ mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ controller.setCancelOnNextTransitionStart();
} else {
// Just cancel directly to unleash from launcher when the next launching task is the
// current top task.
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 163be1ebd0ed..6ea4d580ea98 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -97,10 +97,9 @@ public class RecentsAnimationController implements DeathRecipient {
private final Runnable mFailsafeRunnable = () ->
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
- final Object mLock = new Object();
-
// The recents component app token that is shown behind the visibile tasks
private AppWindowToken mTargetAppToken;
+ private DisplayContent mDisplayContent;
private int mTargetActivityType;
private Rect mMinimizedHomeBounds = new Rect();
@@ -124,25 +123,47 @@ public class RecentsAnimationController implements DeathRecipient {
private boolean mLinkedToDeathOfRunner;
- private boolean mCancelWithDeferredScreenshot;
-
+ // Whether to try to defer canceling from a stack order change until the next transition
+ private boolean mRequestDeferCancelUntilNextTransition;
+ // Whether to actually defer canceling until the next transition
private boolean mCancelOnNextTransitionStart;
+ // Whether to take a screenshot when handling a deferred cancel
+ private boolean mCancelDeferredWithScreenshot;
/**
* Animates the screenshot of task that used to be controlled by RecentsAnimation.
- * @see {@link #cancelOnNextTransitionStart}
+ * @see {@link #setCancelOnNextTransitionStart}
*/
SurfaceAnimator mRecentScreenshotAnimator;
+ /**
+ * An app transition listener to cancel the recents animation only after the app transition
+ * starts or is canceled.
+ */
final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
@Override
public int onAppTransitionStartingLocked(int transit, long duration,
long statusBarAnimationStartTime, long statusBarAnimationDuration) {
- onTransitionStart();
- mService.mRoot.getDisplayContent(mDisplayId).mAppTransition
- .unregisterListener(this);
+ continueDeferredCancel();
return 0;
}
+
+ @Override
+ public void onAppTransitionCancelledLocked(int transit) {
+ continueDeferredCancel();
+ }
+
+ private void continueDeferredCancel() {
+ mDisplayContent.mAppTransition.unregisterListener(this);
+ if (mCanceled) {
+ return;
+ }
+
+ if (mCancelOnNextTransitionStart) {
+ mCancelOnNextTransitionStart = false;
+ cancelAnimationWithScreenshot(mCancelDeferredWithScreenshot);
+ }
+ }
};
public interface RecentsAnimationCallbacks {
@@ -202,8 +223,7 @@ public class RecentsAnimationController implements DeathRecipient {
? REORDER_MOVE_TO_TOP
: REORDER_MOVE_TO_ORIGINAL_POSITION,
true /* runSynchronously */, sendUserLeaveHint);
- final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
- dc.mBoundsAnimationController.setAnimationType(FADE_IN);
+ mDisplayContent.mBoundsAnimationController.setAnimationType(FADE_IN);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -240,8 +260,7 @@ public class RecentsAnimationController implements DeathRecipient {
}
mInputConsumerEnabled = enabled;
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.updateInputWindowsLw(true /*force*/);
mService.scheduleAnimationLocked();
}
@@ -282,15 +301,23 @@ public class RecentsAnimationController implements DeathRecipient {
}
@Override
+ @Deprecated
public void setCancelWithDeferredScreenshot(boolean screenshot) {
- synchronized (mLock) {
- setCancelWithDeferredScreenshotLocked(screenshot);
+ synchronized (mService.mGlobalLock) {
+ setDeferredCancel(true /* deferred */, screenshot);
+ }
+ }
+
+ @Override
+ public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+ synchronized (mService.mGlobalLock) {
+ setDeferredCancel(defer, screenshot);
}
}
@Override
public void cleanupScreenshot() {
- synchronized (mLock) {
+ synchronized (mService.mGlobalLock) {
if (mRecentScreenshotAnimator != null) {
mRecentScreenshotAnimator.cancelAnimation();
mRecentScreenshotAnimator = null;
@@ -312,10 +339,7 @@ public class RecentsAnimationController implements DeathRecipient {
mCallbacks = callbacks;
mDisplayId = displayId;
mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
- }
-
- public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
- initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds);
+ mDisplayContent = service.mRoot.getDisplayContent(displayId);
}
/**
@@ -323,15 +347,15 @@ public class RecentsAnimationController implements DeathRecipient {
* because it may call cancelAnimation() which needs to properly clean up the controller
* in the window manager.
*/
- @VisibleForTesting
- void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
+ public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
mTargetActivityType = targetActivityType;
- dc.mAppTransition.registerListenerLocked(mAppTransitionListener);
+ mDisplayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
// Make leashes for each of the visible/target tasks and add it to the recents animation to
// be started
- final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
- final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
+ final ArrayList<Task> visibleTasks = mDisplayContent.getVisibleTasks();
+ final TaskStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
+ targetActivityType);
if (targetStack != null) {
for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
final Task t = targetStack.getChildAt(i);
@@ -365,29 +389,31 @@ public class RecentsAnimationController implements DeathRecipient {
}
// Adjust the wallpaper visibility for the showing target activity
- final AppWindowToken recentsComponentAppToken = dc.getStack(WINDOWING_MODE_UNDEFINED,
- targetActivityType).getTopChild().getTopFullscreenAppToken();
+ final AppWindowToken recentsComponentAppToken =
+ targetStack.getTopChild().getTopFullscreenAppToken();
if (recentsComponentAppToken != null) {
if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
+ recentsComponentAppToken.getName() + ")");
mTargetAppToken = recentsComponentAppToken;
if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
- dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- dc.setLayoutNeeded();
+ mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ mDisplayContent.setLayoutNeeded();
}
}
// Save the minimized home height
- final TaskStack dockedStack = dc.getSplitScreenPrimaryStackIgnoringVisibility();
- dc.getDockedDividerController().getHomeStackBoundsInDockedMode(
- dc.getConfiguration(),
+ final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+ mDisplayContent.getDockedDividerController().getHomeStackBoundsInDockedMode(
+ mDisplayContent.getConfiguration(),
dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(),
mMinimizedHomeBounds);
mService.mWindowPlacerLocked.performSurfacePlacement();
// Notify that the animation has started
- mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+ if (mStatusBar != null) {
+ mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+ }
}
@VisibleForTesting
@@ -441,8 +467,7 @@ public class RecentsAnimationController implements DeathRecipient {
// Perform layout if it was scheduled before to make sure that we get correct content
// insets for the target app window after a rotation
- final DisplayContent displayContent = mService.mRoot.getDisplayContent(mDisplayId);
- displayContent.performLayout(false /* initial */, false /* updateInputWindows */);
+ mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
final Rect minimizedHomeBounds = mTargetAppToken != null
&& mTargetAppToken.inSplitScreenSecondaryWindowingMode()
@@ -480,9 +505,8 @@ public class RecentsAnimationController implements DeathRecipient {
cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason);
}
- void cancelAnimationWithScreenShot() {
- cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, true /* screenshot */,
- "stackOrderChanged");
+ void cancelAnimationWithScreenshot(boolean screenshot) {
+ cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, screenshot, "stackOrderChanged");
}
private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
@@ -496,21 +520,29 @@ public class RecentsAnimationController implements DeathRecipient {
}
mService.mH.removeCallbacks(mFailsafeRunnable);
mCanceled = true;
- try {
- if (screenshot) {
- // Screen shot previous task when next task starts transition.
- final Task task = mPendingAnimations.get(0).mTask;
- screenshotRecentTask(task, reorderMode, runSynchronously);
+
+ if (screenshot) {
+ // Screen shot previous task when next task starts transition and notify the runner.
+ // We will actually finish the animation once the runner calls cleanUpScreenshot().
+ final Task task = mPendingAnimations.get(0).mTask;
+ screenshotRecentTask(task, reorderMode, runSynchronously);
+ try {
mRunner.onAnimationCanceled(true /* deferredWithScreenshot */);
- return;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation", e);
+ }
+ } else {
+ // Otherwise, notify the runner and clean up the animation immediately
+ // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
+ // to the runner if we this actually triggers cancel twice on the caller
+ try {
+ mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation", e);
}
- mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to cancel recents animation", e);
+ mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+ false /* sendUserLeaveHint */);
}
- // Clean up and return to the previous app
- mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
- false /* sendUserLeaveHint */);
}
}
@@ -523,27 +555,36 @@ public class RecentsAnimationController implements DeathRecipient {
* screenshot, so that Launcher can still control the leash lifecycle & make the next app
* transition animate smoothly without flickering.
*/
- void cancelOnNextTransitionStart() {
+ void setCancelOnNextTransitionStart() {
mCancelOnNextTransitionStart = true;
}
- void setCancelWithDeferredScreenshotLocked(boolean screenshot) {
- mCancelWithDeferredScreenshot = screenshot;
+ /**
+ * Requests that we attempt to defer the cancel until the next app transition if we are
+ * canceling from a stack order change. If {@param screenshot} is specified, then the system
+ * will replace the contents of the leash with a screenshot, which must be cleaned up when the
+ * runner calls cleanUpScreenshot().
+ */
+ void setDeferredCancel(boolean defer, boolean screenshot) {
+ mRequestDeferCancelUntilNextTransition = defer;
+ mCancelDeferredWithScreenshot = screenshot;
}
- boolean shouldCancelWithDeferredScreenshot() {
- return mCancelWithDeferredScreenshot;
+ /**
+ * @return Whether we should defer the cancel from a stack order change until the next app
+ * transition.
+ */
+ boolean shouldDeferCancelUntilNextTransition() {
+ return mRequestDeferCancelUntilNextTransition;
}
- void onTransitionStart() {
- if (mCanceled) {
- return;
- }
-
- if (mCancelOnNextTransitionStart) {
- mCancelOnNextTransitionStart = false;
- cancelAnimationWithScreenShot();
- }
+ /**
+ * @return Whether we should both defer the cancel from a stack order change until the next
+ * app transition, and also that the deferred cancel should replace the contents of the leash
+ * with a screenshot.
+ */
+ boolean shouldDeferCancelWithScreenshot() {
+ return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
}
void screenshotRecentTask(Task task, @ReorderMode int reorderMode, boolean runSynchronously) {
@@ -576,6 +617,7 @@ public class RecentsAnimationController implements DeathRecipient {
// Clear any pending failsafe runnables
mService.mH.removeCallbacks(mFailsafeRunnable);
+ mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener);
// Clear references to the runner
unlinkToDeathOfRunner();
@@ -589,21 +631,22 @@ public class RecentsAnimationController implements DeathRecipient {
}
// Update the input windows after the animation is complete
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.updateInputWindowsLw(true /*force*/);
// We have deferred all notifications to the target app as a part of the recents animation,
// so if we are actually transitioning there, notify again here
if (mTargetAppToken != null) {
if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
- mService.mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.notifyAppTransitionFinishedLocked(mTargetAppToken.token);
+ mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
+ mTargetAppToken.token);
}
}
// Notify that the animation has ended
- mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+ if (mStatusBar != null) {
+ mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+ }
}
void scheduleFailsafe() {
@@ -630,8 +673,7 @@ public class RecentsAnimationController implements DeathRecipient {
synchronized (mService.getWindowManagerLock()) {
// Clear associated input consumers on runner death
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
}
}
@@ -827,5 +869,11 @@ public class RecentsAnimationController implements DeathRecipient {
pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
+ pw.print(innerPrefix); pw.println("mRequestDeferCancelUntilNextTransition="
+ + mRequestDeferCancelUntilNextTransition);
+ pw.print(innerPrefix); pw.println("mCancelOnNextTransitionStart="
+ + mCancelOnNextTransitionStart);
+ pw.print(innerPrefix); pw.println("mCancelDeferredWithScreenshot="
+ + mCancelDeferredWithScreenshot);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 0d18b30c1b0b..f51d4c4aa3f7 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -294,6 +294,10 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
private int getPreferredLaunchDisplay(@Nullable TaskRecord task,
@Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams) {
+ if (!mSupervisor.mService.mSupportsMultiDisplay) {
+ return DEFAULT_DISPLAY;
+ }
+
int displayId = INVALID_DISPLAY;
final int optionLaunchId = options != null ? options.getLaunchDisplayId() : INVALID_DISPLAY;
if (optionLaunchId != INVALID_DISPLAY) {
@@ -321,6 +325,12 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
displayId = sourceDisplayId;
}
+ if (displayId == INVALID_DISPLAY && options != null) {
+ final int callerDisplayId = options.getCallerDisplayId();
+ if (DEBUG) appendLog("display-from-caller=" + callerDisplayId);
+ displayId = callerDisplayId;
+ }
+
if (displayId != INVALID_DISPLAY
&& mSupervisor.mRootActivityContainer.getActivityDisplay(displayId) == null) {
displayId = currentParams.mPreferredDisplayId;
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index 1a571683de34..143543e8c74b 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -28,7 +28,7 @@ import android.view.SurfaceSession;
* Class used by {@link RecentsAnimationController} to create a surface control with taking
* screenshot of task when canceling recents animation.
*
- * @see {@link RecentsAnimationController#cancelOnNextTransitionStart}
+ * @see {@link RecentsAnimationController#setCancelOnNextTransitionStart}
*/
class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
private static final String TAG = "TaskScreenshotAnim";
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 636f4e6d09d0..05cfbd4e39d9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -511,4 +511,9 @@ public abstract class WindowManagerInternal {
*/
public abstract void removeNonHighRefreshRatePackage(@NonNull String packageName);
+ /**
+ * Checks if this display is touchable.
+ */
+ public abstract boolean isTouchableDisplay(int displayId);
+
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 70e446c51c43..fbdc54a2435b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7455,6 +7455,17 @@ public class WindowManagerService extends IWindowManager.Stub
.removeNonHighRefreshRatePackage(packageName));
}
}
+
+ @Override
+ public boolean isTouchableDisplay(int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ final Configuration configuration =
+ displayContent != null ? displayContent.getConfiguration() : null;
+ return configuration != null
+ && configuration.touchscreen == Configuration.TOUCHSCREEN_FINGER;
+ }
+ }
}
void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index f74e2c01699d..4a91dac27d7e 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -566,7 +566,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
* activities are allowed to be resumed per process.
* @return {@code true} if the activity is allowed to be resumed by compatibility
* restrictions, which the activity was the topmost visible activity in process or the app is
- * targeting after Q.
+ * targeting after Q. Note that non-focusable activity, in picture-in-picture mode for instance,
+ * does not count as a topmost activity.
*/
boolean updateTopResumingActivityInProcessIfNeeded(@NonNull ActivityRecord activity) {
if (mInfo.targetSdkVersion >= Q || mPreQTopResumedActivity == activity) {
@@ -582,9 +583,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
boolean canUpdate = false;
final ActivityDisplay topDisplay =
mPreQTopResumedActivity != null ? mPreQTopResumedActivity.getDisplay() : null;
- // Update the topmost activity if current top activity was not on any display or no
- // longer visible.
- if (topDisplay == null || !mPreQTopResumedActivity.visible) {
+ // Update the topmost activity if current top activity is
+ // - not on any display OR
+ // - no longer visible OR
+ // - not focusable (in PiP mode for instance)
+ if (topDisplay == null
+ || !mPreQTopResumedActivity.visible
+ || !mPreQTopResumedActivity.isFocusable()) {
canUpdate = true;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 41840a4c531c..d90e66e10e73 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -370,6 +370,13 @@ class WindowStateAnimator {
// of the proper size. The preserved surface will still be removed when client
// finishes drawing to the new surface.
mSurfaceDestroyDeferred = false;
+
+ // Make sure to reparent any children of the new surface back to the preserved
+ // surface before destroying it.
+ if (mSurfaceController != null && mPendingDestroySurface != null) {
+ mPostDrawTransaction.reparentChildren(mSurfaceController.mSurfaceControl,
+ mPendingDestroySurface.mSurfaceControl).apply();
+ }
destroySurfaceLocked();
mSurfaceDestroyDeferred = true;
return;
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index 98e4343e6e57..8b2cbbde2db8 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -4,3 +4,11 @@ xsd_config {
api_dir: "schema",
package_name: "com.android.server.pm.permission.configfile",
}
+
+
+xsd_config {
+ name: "platform-compat-config",
+ srcs: ["platform-compat-config.xsd"],
+ api_dir: "platform-compat-schema",
+ package_name: "com.android.server.compat.config",
+}
diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat-config.xsd
new file mode 100644
index 000000000000..ee39e507aff1
--- /dev/null
+++ b/services/core/xsd/platform-compat-config.xsd
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2019 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.
+ -->
+
+<!-- This defines the format of the XML file generated by
+ ~ com.android.compat.annotation.ChangeIdProcessor annotation processor (from
+ ~ tools/platform-compat), and is parsed in com/android/server/compat/CompatConfig.java.
+-->
+<xs:schema version="2.0" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ <xs:complexType name="change">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute type="xs:long" name="id" use="required"/>
+ <xs:attribute type="xs:string" name="name" use="required"/>
+ <xs:attribute type="xs:boolean" name="disabled"/>
+ <xs:attribute type="xs:int" name="enableAfterTargetSdk"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:element name="config">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="compat-change" type="change" maxOccurs="unbounded"
+ minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:unique name="UniqueId">
+ <xs:selector xpath="compat-change" />
+ <xs:field xpath="@id" />
+ </xs:unique>
+ </xs:element>
+</xs:schema>
+
+
+
+
diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat-schema/current.txt
new file mode 100644
index 000000000000..84567851da2c
--- /dev/null
+++ b/services/core/xsd/platform-compat-schema/current.txt
@@ -0,0 +1,31 @@
+// Signature format: 2.0
+package com.android.server.compat.config {
+
+ public class Change {
+ ctor public Change();
+ method public boolean getDisabled();
+ method public int getEnableAfterTargetSdk();
+ method public long getId();
+ method public String getName();
+ method public String getValue();
+ method public void setDisabled(boolean);
+ method public void setEnableAfterTargetSdk(int);
+ method public void setId(long);
+ method public void setName(String);
+ method public void setValue(String);
+ }
+
+ public class Config {
+ ctor public Config();
+ method public java.util.List<com.android.server.compat.config.Change> getCompatChange();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static com.android.server.compat.config.Config read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/services/core/xsd/platform-compat-schema/last_current.txt b/services/core/xsd/platform-compat-schema/last_current.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/services/core/xsd/platform-compat-schema/last_current.txt
diff --git a/services/core/xsd/platform-compat-schema/last_removed.txt b/services/core/xsd/platform-compat-schema/last_removed.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/services/core/xsd/platform-compat-schema/last_removed.txt
diff --git a/services/core/xsd/platform-compat-schema/removed.txt b/services/core/xsd/platform-compat-schema/removed.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/services/core/xsd/platform-compat-schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a04875f1a283..16007d775283 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -87,6 +87,7 @@ import com.android.server.biometrics.iris.IrisService;
import com.android.server.broadcastradio.BroadcastRadioService;
import com.android.server.camera.CameraServiceProxy;
import com.android.server.clipboard.ClipboardService;
+import com.android.server.compat.PlatformCompat;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.coverage.CoverageService;
@@ -101,7 +102,6 @@ import com.android.server.incident.IncidentCompanionService;
import com.android.server.input.InputManagerService;
import com.android.server.inputmethod.InputMethodManagerService;
import com.android.server.inputmethod.MultiClientInputMethodManagerService;
-import com.android.server.job.JobSchedulerService;
import com.android.server.lights.LightsService;
import com.android.server.media.MediaResourceMonitorService;
import com.android.server.media.MediaRouterService;
@@ -1098,6 +1098,11 @@ public final class SystemServer {
t.traceBegin("SignedConfigService");
SignedConfigService.registerUpdateReceiver(mSystemContext);
t.traceEnd();
+
+ t.traceBegin("PlatformCompat");
+ ServiceManager.addService("platform_compat", new PlatformCompat(context));
+ t.traceEnd();
+
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
@@ -1569,8 +1574,9 @@ public final class SystemServer {
mSystemServiceManager.startService(ColorDisplayService.class);
t.traceEnd();
+ // TODO(aml-jobscheduler): Think about how to do it properly.
t.traceBegin("StartJobScheduler");
- mSystemServiceManager.startService(JobSchedulerService.class);
+ mSystemServiceManager.startService(JOB_SCHEDULER_SERVICE_CLASS);
t.traceEnd();
t.traceBegin("StartSoundTrigger");
@@ -1974,6 +1980,11 @@ public final class SystemServer {
}
t.traceEnd();
+ // Permission policy service
+ t.traceBegin("StartPermissionPolicyService");
+ mSystemServiceManager.startService(PermissionPolicyService.class);
+ t.traceEnd();
+
t.traceBegin("MakePackageManagerServiceReady");
mPackageManagerService.systemReady();
t.traceEnd();
@@ -2008,11 +2019,6 @@ public final class SystemServer {
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
- // Permission policy service
- t.traceBegin("StartPermissionPolicyService");
- mSystemServiceManager.startService(PermissionPolicyService.class);
- t.traceEnd();
-
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp
new file mode 100644
index 000000000000..3ce514a56b60
--- /dev/null
+++ b/services/robotests/Android.bp
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 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.
+
+//##################################################################
+// FrameworksServicesLib app just for Robolectric test target #
+//##################################################################
+
+android_app {
+ name: "FrameworksServicesLib",
+ platform_apis: true,
+
+ privileged: true,
+
+ static_libs: [
+ "services.core",
+ "services.net",
+ ],
+}
+
+//##################################################################
+// FrameworksServicesLib Robolectric test target. #
+//##################################################################
+android_robolectric_test {
+ name: "FrameworksServicesRoboTests",
+
+ srcs: ["src/**/*.java"],
+
+ java_resource_dirs: ["config"],
+
+ // Include the testing libraries
+ libs: [
+ "platform-test-annotations",
+ "testng",
+ ],
+
+ instrumentation_for: "FrameworksServicesLib",
+}
+
+filegroup {
+ name: "FrameworksServicesRoboShadows",
+ srcs: ["src/com/android/server/testing/shadows/**/*.java"],
+}
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
deleted file mode 100644
index 0cf0d3402dea..000000000000
--- a/services/robotests/Android.mk
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (C) 2016 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.
-
-###################################################################
-# FrameworksServicesLib app just for Robolectric test target #
-###################################################################
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := FrameworksServicesLib
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- services.core \
- services.net
-
-include $(BUILD_PACKAGE)
-
-###################################################################
-# FrameworksServicesLib Robolectric test target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := FrameworksServicesRoboTests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res
-
-LOCAL_JAVA_RESOURCE_DIRS := config
-
-# Include the testing libraries
-LOCAL_JAVA_LIBRARIES := \
- platform-test-annotations \
- robolectric_android-all-stub \
- Robolectric_all-target \
- mockito-robolectric-prebuilt \
- truth-prebuilt \
- testng
-
-LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-###################################################################
-# FrameworksServicesLib runner target to run the previous target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := RunFrameworksServicesRoboTests
-
-LOCAL_JAVA_LIBRARIES := \
- FrameworksServicesRoboTests \
- platform-test-annotations \
- robolectric_android-all-stub \
- Robolectric_all-target \
- mockito-robolectric-prebuilt \
- truth-prebuilt \
- testng
-
-LOCAL_TEST_PACKAGE := FrameworksServicesLib
-
-LOCAL_ROBOTEST_FILES := $(call find-files-in-subdirs,$(LOCAL_PATH)/src,*Test.java,.)
-
-include external/robolectric-shadows/run_robotests.mk
-
-###################################################################
-# include subdir Android.mk files
-###################################################################
-include $(CLEAR_VARS)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/robotests/AndroidManifest.xml b/services/robotests/AndroidManifest.xml
new file mode 100644
index 000000000000..828c8fade6fc
--- /dev/null
+++ b/services/robotests/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ coreApp="true"
+ package="com.android.server.robotests">
+
+ <application/>
+
+</manifest>
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
new file mode 100644
index 000000000000..9d384e90d253
--- /dev/null
+++ b/services/robotests/backup/Android.bp
@@ -0,0 +1,53 @@
+// Copyright (C) 2018 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.
+
+//##################################################################
+// BackupFrameworksServicesLib app just for Robolectric test target #
+//##################################################################
+android_app {
+ name: "BackupFrameworksServicesLib",
+ platform_apis: true,
+
+ privileged: true,
+
+ static_libs: [
+ "bmgr",
+ "bu",
+ "services.backup",
+ "services.core",
+ "services.net",
+ ],
+}
+
+//##################################################################
+// BackupFrameworksServicesLib Robolectric test target. #
+//##################################################################
+android_robolectric_test {
+ name: "BackupFrameworksServicesRoboTests",
+ srcs: [
+ "src/**/*.java",
+ ":FrameworksServicesRoboShadows",
+ ],
+
+ java_resource_dirs: ["config"],
+
+ // Include the testing libraries
+ libs: [
+ "platform-test-annotations",
+ "testng",
+ ],
+
+ instrumentation_for: "BackupFrameworksServicesLib",
+
+}
diff --git a/services/robotests/backup/Android.mk b/services/robotests/backup/Android.mk
deleted file mode 100644
index bd4ebbd393fa..000000000000
--- a/services/robotests/backup/Android.mk
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright (C) 2018 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.
-
-LOCAL_PATH := $(call my-dir)
-
-###################################################################
-# BackupFrameworksServicesLib app just for Robolectric test target #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := BackupFrameworksServicesLib
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- bmgr \
- bu \
- services.backup \
- services.core \
- services.net
-
-include $(BUILD_PACKAGE)
-
-###################################################################
-# BackupFrameworksServicesLib Robolectric test target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := BackupFrameworksServicesRoboTests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- $(call all-java-files-under, ../src/com/android/server/testing/shadows)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_JAVA_RESOURCE_DIRS := config
-
-# Include the testing libraries
-LOCAL_JAVA_LIBRARIES := \
- platform-test-annotations \
- robolectric_android-all-stub \
- Robolectric_all-target \
- mockito-robolectric-prebuilt \
- truth-prebuilt \
- testng
-
-LOCAL_INSTRUMENTATION_FOR := BackupFrameworksServicesLib
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-###################################################################
-# BackupFrameworksServicesLib runner target to run the previous target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := RunBackupFrameworksServicesRoboTests
-
-LOCAL_JAVA_LIBRARIES := \
- BackupFrameworksServicesRoboTests \
- platform-test-annotations \
- robolectric_android-all-stub \
- Robolectric_all-target \
- mockito-robolectric-prebuilt \
- truth-prebuilt \
- testng
-
-LOCAL_TEST_PACKAGE := BackupFrameworksServicesLib
-
-include external/robolectric-shadows/run_robotests.mk
diff --git a/services/robotests/backup/AndroidManifest.xml b/services/robotests/backup/AndroidManifest.xml
new file mode 100644
index 000000000000..09323782a228
--- /dev/null
+++ b/services/robotests/backup/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ coreApp="true"
+ package="com.android.server.backup.robotests">
+
+ <application/>
+
+</manifest>
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 2baa4d81515a..ad94e6159b87 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -20,6 +20,7 @@ android_test {
static_libs: [
"services.core",
"services.net",
+ "jobscheduler-service",
"androidx.test.runner",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 06c83a26cca6..6feac520e538 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -53,6 +53,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.longThat;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@@ -129,9 +130,12 @@ public class DeviceIdleControllerTest {
ConnectivityService connectivityService;
LocationManager locationManager;
ConstraintController constraintController;
+ // Freeze time for testing.
+ long nowElapsed;
InjectorForTest(Context ctx) {
super(ctx);
+ nowElapsed = SystemClock.elapsedRealtime();
}
@Override
@@ -156,6 +160,11 @@ public class DeviceIdleControllerTest {
}
@Override
+ long getElapsedRealtime() {
+ return nowElapsed;
+ }
+
+ @Override
LocationManager getLocationManager() {
return locationManager;
}
@@ -494,11 +503,44 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.becomeActiveLocked("testing", 0);
verifyStateConditions(STATE_ACTIVE);
+ setAlarmSoon(false);
+ setChargingOn(false);
+ setScreenOn(false);
+
+ mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+ verifyStateConditions(STATE_INACTIVE);
+ verify(mDeviceIdleController)
+ .scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false));
+ }
+
+ @Test
+ public void testStateActiveToStateInactive_UpcomingAlarm() {
+ final long timeUntilAlarm = mConstants.MIN_TIME_TO_ALARM / 2;
+ // Set an upcoming alarm that will prevent full idle.
+ doReturn(mInjector.getElapsedRealtime() + timeUntilAlarm)
+ .when(mAlarmManager).getNextWakeFromIdleTime();
+
+ InOrder inOrder = inOrder(mDeviceIdleController);
+
+ enterDeepState(STATE_ACTIVE);
+ setQuickDozeEnabled(false);
setChargingOn(false);
setScreenOn(false);
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_INACTIVE);
+ inOrder.verify(mDeviceIdleController)
+ .scheduleAlarmLocked(eq(timeUntilAlarm + mConstants.INACTIVE_TIMEOUT), eq(false));
+
+ enterDeepState(STATE_ACTIVE);
+ setQuickDozeEnabled(true);
+ setChargingOn(false);
+ setScreenOn(false);
+
+ mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+ verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+ inOrder.verify(mDeviceIdleController).scheduleAlarmLocked(
+ eq(timeUntilAlarm + mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
}
@Test
@@ -515,42 +557,68 @@ public class DeviceIdleControllerTest {
@Test
public void testTransitionFromAnyStateToStateQuickDozeDelay() {
+ setAlarmSoon(false);
+ InOrder inOrder = inOrder(mDeviceIdleController);
+
enterDeepState(STATE_ACTIVE);
setQuickDozeEnabled(true);
setChargingOn(false);
setScreenOn(false);
verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+ inOrder.verify(mDeviceIdleController)
+ .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
enterDeepState(STATE_INACTIVE);
setQuickDozeEnabled(true);
verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+ inOrder.verify(mDeviceIdleController)
+ .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
enterDeepState(STATE_IDLE_PENDING);
setQuickDozeEnabled(true);
verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+ inOrder.verify(mDeviceIdleController)
+ .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
enterDeepState(STATE_SENSING);
setQuickDozeEnabled(true);
verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+ inOrder.verify(mDeviceIdleController)
+ .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
enterDeepState(STATE_LOCATING);
setQuickDozeEnabled(true);
verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+ inOrder.verify(mDeviceIdleController)
+ .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
// IDLE should stay as IDLE.
enterDeepState(STATE_IDLE);
+ // Clear out any alarm setting from the order before checking for this section.
+ inOrder.verify(mDeviceIdleController, atLeastOnce())
+ .scheduleAlarmLocked(anyLong(), anyBoolean());
setQuickDozeEnabled(true);
verifyStateConditions(STATE_IDLE);
+ inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean());
// IDLE_MAINTENANCE should stay as IDLE_MAINTENANCE.
enterDeepState(STATE_IDLE_MAINTENANCE);
+ // Clear out any alarm setting from the order before checking for this section.
+ inOrder.verify(mDeviceIdleController, atLeastOnce())
+ .scheduleAlarmLocked(anyLong(), anyBoolean());
setQuickDozeEnabled(true);
verifyStateConditions(STATE_IDLE_MAINTENANCE);
+ inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean());
+ // State is already QUICK_DOZE_DELAY. No work should be done.
enterDeepState(STATE_QUICK_DOZE_DELAY);
+ // Clear out any alarm setting from the order before checking for this section.
+ inOrder.verify(mDeviceIdleController, atLeastOnce())
+ .scheduleAlarmLocked(anyLong(), anyBoolean());
setQuickDozeEnabled(true);
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+ inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean());
}
@Test
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 869913dec646..b37e4602ed97 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -39,6 +39,8 @@ android_test {
"platformprotosnano",
"hamcrest-library",
"servicestests-utils",
+ "xml-writer-device-lib",
+ "jobscheduler-service",
],
aidl: {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
index aad7230bbc89..cdcc338b3928 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
@@ -16,6 +16,7 @@
package com.android.server.accessibility;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@@ -174,6 +175,7 @@ public class AccessibilityGestureDetectorTest {
}
// Check that correct gesture was recognized.
- verify(mResultListener).onGestureCompleted(gestureId);
+ verify(mResultListener).onGestureCompleted(
+ argThat(gestureInfo -> gestureInfo.getGestureId() == gestureId));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index ba2959f7f965..2f9f9bbecbdf 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -23,21 +23,25 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.GestureDescription;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.view.Display;
import com.android.server.wm.WindowManagerInternal;
@@ -50,6 +54,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
/**
@@ -73,6 +78,9 @@ public class AccessibilityServiceConnectionTest {
@Mock GlobalActionPerformer mMockGlobalActionPerformer;
@Mock KeyEventDispatcher mMockKeyEventDispatcher;
@Mock MagnificationController mMockMagnificationController;
+ @Mock IBinder mMockIBinder;
+ @Mock IAccessibilityServiceClient mMockServiceClient;
+ @Mock MotionEventInjector mMockMotionEventInjector;
MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
@@ -82,15 +90,22 @@ public class AccessibilityServiceConnectionTest {
when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mMockKeyEventDispatcher);
when(mMockSystemSupport.getMagnificationController())
.thenReturn(mMockMagnificationController);
+ when(mMockSystemSupport.getMotionEventInjectorForDisplayLocked(
+ Display.DEFAULT_DISPLAY)).thenReturn(mMockMotionEventInjector);
when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
mMockResolveInfo.serviceInfo = mock(ServiceInfo.class);
mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
+ when(mMockIBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
+ when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
+ true);
+
mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
mMockSecurityPolicy, mMockSystemSupport, mMockWindowManagerInternal,
mMockGlobalActionPerformer, mMockA11yWindowManager);
+ when(mMockSecurityPolicy.canPerformGestures(mConnection)).thenReturn(true);
}
@After
@@ -115,25 +130,23 @@ public class AccessibilityServiceConnectionTest {
@Test
public void bindConnectUnbind_linksAndUnlinksToServiceDeath() throws RemoteException {
- IBinder mockBinder = mock(IBinder.class);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
- verify(mockBinder).linkToDeath(eq(mConnection), anyInt());
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+ verify(mMockIBinder).linkToDeath(eq(mConnection), anyInt());
mConnection.unbindLocked();
- verify(mockBinder).unlinkToDeath(eq(mConnection), anyInt());
+ verify(mMockIBinder).unlinkToDeath(eq(mConnection), anyInt());
}
@Test
public void connectedServiceCrashedAndRestarted_crashReportedInServiceInfo() {
- IBinder mockBinder = mock(IBinder.class);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
assertFalse(mConnection.getServiceInfo().crashed);
mConnection.binderDied();
assertTrue(mConnection.getServiceInfo().crashed);
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
mHandler.sendAllMessages();
assertFalse(mConnection.getServiceInfo().crashed);
}
@@ -145,10 +158,9 @@ public class AccessibilityServiceConnectionTest {
@Test
public void binderDied_keysGetFlushed() {
- IBinder mockBinder = mock(IBinder.class);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
mConnection.binderDied();
assertTrue(mConnection.getServiceInfo().crashed);
verify(mMockKeyEventDispatcher).flush(mConnection);
@@ -157,17 +169,63 @@ public class AccessibilityServiceConnectionTest {
@Test
public void connectedService_notInEnabledServiceList_doNotInitClient()
throws RemoteException {
- IBinder mockBinder = mock(IBinder.class);
- IAccessibilityServiceClient mockClient = mock(IAccessibilityServiceClient.class);
- when(mockBinder.queryLocalInterface(any())).thenReturn(mockClient);
when(mMockUserState.getEnabledServicesLocked())
.thenReturn(Collections.emptySet());
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
mHandler.sendAllMessages();
verify(mMockSystemSupport, times(2)).onClientChangeLocked(false);
- verify(mockClient, times(0)).init(any(), anyInt(), any());
+ verify(mMockServiceClient, times(0)).init(any(), anyInt(), any());
+ }
+
+ @Test
+ public void sendGesture_touchableDisplay_injectEvents()
+ throws RemoteException {
+ setServiceBinding(COMPONENT_NAME);
+ mConnection.bindLocked();
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+ ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+ List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+ when(parceledListSlice.getList()).thenReturn(gestureSteps);
+ mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
+
+ verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0);
+ }
+
+ @Test
+ public void sendGesture_untouchableDisplay_performGestureResultFailed()
+ throws RemoteException {
+ when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
+ false);
+ setServiceBinding(COMPONENT_NAME);
+ mConnection.bindLocked();
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+ ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+ List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+ when(parceledListSlice.getList()).thenReturn(gestureSteps);
+ mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
+
+ verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0);
+ verify(mMockServiceClient).onPerformGestureResult(0, false);
}
+
+ @Test
+ public void sendGesture_invalidDisplay_performGestureResultFailed()
+ throws RemoteException {
+ setServiceBinding(COMPONENT_NAME);
+ mConnection.bindLocked();
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+ ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+ List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+ when(parceledListSlice.getList()).thenReturn(gestureSteps);
+ mConnection.dispatchGesture(0, parceledListSlice, Display.INVALID_DISPLAY);
+
+ verify(mMockServiceClient).onPerformGestureResult(0, false);
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index d008ca66b762..f3c5e99f5f90 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -22,9 +22,17 @@ import android.content.pm.ApplicationInfo;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compat.annotation.Change;
+import com.android.compat.annotation.XmlWriter;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.UUID;
+
@RunWith(AndroidJUnit4.class)
public class CompatConfigTest {
@@ -35,6 +43,27 @@ public class CompatConfigTest {
return ai;
}
+ private File createTempDir() {
+ String base = System.getProperty("java.io.tmpdir");
+ File dir = new File(base, UUID.randomUUID().toString());
+ assertThat(dir.mkdirs()).isTrue();
+ return dir;
+ }
+
+ private void writeChangesToFile(Change[] changes, File f) {
+ XmlWriter writer = new XmlWriter();
+ for (Change change: changes) {
+ writer.addChange(change);
+ }
+ try {
+ f.createNewFile();
+ writer.write(new FileOutputStream(f));
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Encountered an error while writing compat config file", e);
+ }
+ }
+
@Test
public void testUnknownChangeEnabled() {
CompatConfig pc = new CompatConfig();
@@ -170,4 +199,45 @@ public class CompatConfigTest {
sysApp.flags |= ApplicationInfo.FLAG_SYSTEM;
assertThat(pc.isChangeEnabled(1234L, sysApp)).isTrue();
}
+
+ @Test
+ public void testReadConfig() {
+ Change[] changes = {new Change(1234L, "MY_CHANGE1", false, 2), new Change(1235L,
+ "MY_CHANGE2", true, null), new Change(1236L, "MY_CHANGE3", false, null)};
+
+ File dir = createTempDir();
+ writeChangesToFile(changes, new File(dir.getPath() + "/platform_compat_config.xml"));
+
+ CompatConfig pc = new CompatConfig();
+ pc.initConfigFromLib(dir);
+
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
+ assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
+ assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
+ }
+
+ @Test
+ public void testReadConfigMultipleFiles() {
+ Change[] changes1 = {new Change(1234L, "MY_CHANGE1", false, 2)};
+ Change[] changes2 = {new Change(1235L, "MY_CHANGE2", true, null), new Change(1236L,
+ "MY_CHANGE3", false, null)};
+
+ File dir = createTempDir();
+ writeChangesToFile(changes1,
+ new File(dir.getPath() + "/libcore_platform_compat_config.xml"));
+ writeChangesToFile(changes2,
+ new File(dir.getPath() + "/frameworks_platform_compat_config.xml"));
+
+
+ CompatConfig pc = new CompatConfig();
+ pc.initConfigFromLib(dir);
+
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
+ assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
+ assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
+ }
}
+
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
new file mode 100644
index 000000000000..65f9e321e084
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2019 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 org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Build;
+import android.os.Process;
+import android.permission.IPermissionManager;
+import android.util.ArrayMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class AppsFilterTest {
+
+ private static final int DUMMY_CALLING_UID = 10345;
+
+ @Mock
+ IPermissionManager mPermissionManagerMock;
+
+ @Mock
+ AppsFilter.ConfigProvider mConfigProviderMock;
+
+ @Mock
+ AppOpsManager mAppOpsManager;
+
+ private Map<String, PackageParser.Package> mExisting = new ArrayMap<>();
+
+ private static PackageBuilder pkg(String packageName) {
+ return new PackageBuilder(packageName)
+ .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.R);
+ }
+
+ private static PackageBuilder pkg(String packageName, Intent... queries) {
+ return pkg(packageName).setQueriesIntents(queries);
+ }
+
+ private static PackageBuilder pkg(String packageName, String... queriesPackages) {
+ return pkg(packageName).setQueriesPackages(queriesPackages);
+ }
+
+ private static PackageBuilder pkg(String packageName, IntentFilter... filters) {
+ final PackageBuilder packageBuilder = pkg(packageName).addActivity(
+ pkg -> new PackageParser.ParseComponentArgs(pkg, new String[1], 0, 0, 0, 0, 0, 0,
+ new String[]{packageName}, 0, 0, 0), new ActivityInfo());
+ for (IntentFilter filter : filters) {
+ packageBuilder.addActivityIntentInfo(0 /* index */, activity -> {
+ final PackageParser.ActivityIntentInfo info =
+ new PackageParser.ActivityIntentInfo(activity);
+ if (filter.countActions() > 0) {
+ filter.actionsIterator().forEachRemaining(info::addAction);
+ }
+ if (filter.countCategories() > 0) {
+ filter.actionsIterator().forEachRemaining(info::addAction);
+ }
+ if (filter.countDataAuthorities() > 0) {
+ filter.authoritiesIterator().forEachRemaining(info::addDataAuthority);
+ }
+ if (filter.countDataSchemes() > 0) {
+ filter.schemesIterator().forEachRemaining(info::addDataScheme);
+ }
+ return info;
+ });
+ }
+ return packageBuilder;
+ }
+
+ @Before
+ public void setup() throws Exception {
+ mExisting = new ArrayMap<>();
+
+ MockitoAnnotations.initMocks(this);
+ when(mPermissionManagerMock
+ .checkPermission(anyString(), anyString(), anyInt()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mConfigProviderMock.isEnabled()).thenReturn(true);
+ when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
+ DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_DEFAULT);
+ }
+
+ @Test
+ public void testQueriesAction_FilterMatches() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter,
+ pkg("com.some.package", new IntentFilter("TEST_ACTION"))).build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package", new Intent("TEST_ACTION"))).build();
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testQueriesAction_NoMatchingAction_Filters() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter,
+ pkg("com.some.package")).build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package", new Intent("TEST_ACTION"))).build();
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+ PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package",
+ new Intent("TEST_ACTION")).setApplicationInfoTargetSdkVersion(
+ Build.VERSION_CODES.P)).build();
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testNoQueries_Filters() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package")).build();
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testForceQueryable_DoesntFilter() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target =
+ simulateAddPackage(appsFilter, pkg("com.some.package").setForceQueryable(true))
+ .build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package")).build();
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testForceQueryableByDevice_SystemCaller_DoesntFilter() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{"com.some.package"}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"))
+ .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ .build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package")).build();
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testForceQueryableByDevice_NonSystemCaller_Filters() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{"com.some.package"}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package")).build();
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+
+ @Test
+ public void testSystemQueryable_DoesntFilter() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, true /* system force queryable */);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"))
+ .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ .build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package")).build();
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testQueriesPackage_DoesntFilter() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package", "com.some.package")).build();
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testNoQueries_AppOpModeDeny_Filters() {
+ when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
+ DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_ERRORED);
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package")).build();
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testNoQueries_AppOpModeAllow_DoesntFilter() {
+ when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
+ DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_ALLOWED);
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package")).build();
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testNoQueries_AppOpModeIgnore_Filters() {
+ when(mAppOpsManager.checkOpNoThrow(eq(AppOpsManager.OP_QUERY_ALL_PACKAGES), eq(
+ DUMMY_CALLING_UID), anyString())).thenReturn(AppOpsManager.MODE_IGNORED);
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package")).build();
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testNoQueries_FeatureOff_DoesntFilter() {
+ when(mConfigProviderMock.isEnabled()).thenReturn(false);
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package")).build();
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+ }
+
+ @Test
+ public void testSystemUid_DoesntFilter() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+
+ assertFalse(appsFilter.shouldFilterApplication(0, null, target, 0));
+ assertFalse(appsFilter.shouldFilterApplication(
+ Process.FIRST_APPLICATION_UID - 1, null, target, 0));
+ }
+
+ @Test
+ public void testNonSystemUid_NoCallingSetting_Filters() {
+ final AppsFilter appsFilter =
+ new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager,
+ new String[]{}, false);
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build();
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, null, target, 0));
+ }
+
+ private PackageSettingBuilder simulateAddPackage(AppsFilter filter,
+ PackageBuilder newPkgBuilder) {
+ PackageParser.Package newPkg = newPkgBuilder.build();
+ filter.addPackage(newPkg, mExisting);
+ mExisting.put(newPkg.packageName, newPkg);
+ return new PackageSettingBuilder()
+ .setPackage(newPkg)
+ .setName(newPkg.packageName)
+ .setCodePath("/")
+ .setResourcePath("/")
+ .setPVersionCode(1L);
+ }
+
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
new file mode 100644
index 000000000000..c38672cfc93c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 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 android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageParser;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+class PackageBuilder {
+ final PackageParser.Package mPkg;
+
+ PackageBuilder(String packageName) {
+ mPkg = new PackageParser.Package(packageName);
+ }
+
+ PackageBuilder setApplicationInfoCodePath(String codePath) {
+ mPkg.applicationInfo.setCodePath(codePath);
+ return this;
+ }
+
+ PackageBuilder setApplicationInfoResourcePath(String resourcePath) {
+ mPkg.applicationInfo.setResourcePath(resourcePath);
+ return this;
+ }
+
+ PackageBuilder setCodePath(String codePath) {
+ mPkg.codePath = codePath;
+ return this;
+ }
+
+ PackageBuilder setBaseCodePath(String baseCodePath) {
+ mPkg.baseCodePath = baseCodePath;
+ return this;
+ }
+
+ PackageBuilder addUsesStaticLibrary(String name, long version) {
+ mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name);
+ mPkg.usesStaticLibrariesVersions =
+ ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version);
+ return this;
+ }
+
+ PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) {
+ mPkg.applicationInfo.nativeLibraryRootDir = dir;
+ return this;
+ }
+
+ PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) {
+ mPkg.staticSharedLibVersion = staticSharedLibVersion;
+ mPkg.staticSharedLibName = staticSharedLibName;
+ return this;
+ }
+
+ PackageBuilder setManifestPackageName(String manifestPackageName) {
+ mPkg.manifestPackageName = manifestPackageName;
+ return this;
+ }
+
+ PackageBuilder setVersionCodeMajor(int versionCodeMajor) {
+ mPkg.mVersionCodeMajor = versionCodeMajor;
+ return this;
+ }
+
+ PackageBuilder setVersionCode(int versionCode) {
+ mPkg.mVersionCode = versionCode;
+ return this;
+ }
+
+ PackageBuilder addSplitCodePath(String splitCodePath) {
+ mPkg.splitCodePaths =
+ ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath);
+ return this;
+ }
+
+ PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) {
+ mPkg.applicationInfo.volumeUuid = volumeUuid;
+ return this;
+ }
+
+ PackageBuilder addLibraryName(String libraryName) {
+ mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName);
+ return this;
+ }
+
+ PackageBuilder setRealPackageName(String realPackageName) {
+ mPkg.mRealPackage = realPackageName;
+ return this;
+ }
+
+ PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) {
+ mPkg.cpuAbiOverride = cpuAbiOverride;
+ return this;
+ }
+
+ PackageBuilder addPermissionRequest(String permissionName) {
+ mPkg.requestedPermissions.add(permissionName);
+ return this;
+ }
+
+ PackageParser.Package build() {
+ return mPkg;
+ }
+
+ public PackageBuilder addApplicationInfoFlag(int flag) {
+ mPkg.applicationInfo.flags |= flag;
+ return this;
+ }
+
+ public PackageBuilder setApplicationInfoTargetSdkVersion(int versionCode) {
+ mPkg.applicationInfo.targetSdkVersion = versionCode;
+ return this;
+ }
+
+ public PackageBuilder setQueriesIntents(Collection<Intent> queriesIntents) {
+ mPkg.mQueriesIntents = new ArrayList<>(queriesIntents);
+ return this;
+ }
+
+ public PackageBuilder setQueriesIntents(Intent... intents) {
+ return setQueriesIntents(Arrays.asList(intents));
+ }
+
+ public PackageBuilder setQueriesPackages(Collection<String> queriesPackages) {
+ mPkg.mQueriesPackages = new ArrayList<>(queriesPackages);
+ return this;
+ }
+
+ public PackageBuilder setQueriesPackages(String... queriesPackages) {
+ return setQueriesPackages(Arrays.asList(queriesPackages));
+ }
+
+ public PackageBuilder setForceQueryable(boolean forceQueryable) {
+ mPkg.mForceQueryable = forceQueryable;
+ return this;
+ }
+
+ public interface ParseComponentArgsCreator {
+ PackageParser.ParseComponentArgs create(PackageParser.Package pkg);
+ }
+
+ public PackageBuilder addActivity(ParseComponentArgsCreator argsCreator, ActivityInfo info) {
+ mPkg.activities.add(new PackageParser.Activity(argsCreator.create(mPkg), info));
+ return this;
+ }
+
+ public interface ActivityIntentInfoCreator {
+ PackageParser.ActivityIntentInfo create(PackageParser.Activity activity);
+ }
+
+ public PackageBuilder addActivityIntentInfo(
+ int activityIndex, ActivityIntentInfoCreator creator) {
+ final PackageParser.Activity activity = mPkg.activities.get(activityIndex);
+ activity.intents.add(creator.create(activity));
+ return this;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 13a8eb1d7fad..e33d8ca66ed0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
@@ -557,6 +558,9 @@ public class PackageParserTest {
pkg.mRequiredForAllUsers = true;
pkg.visibleToInstantApps = true;
pkg.use32bitAbi = true;
+ pkg.mForceQueryable = true;
+ pkg.mQueriesPackages = new ArrayList<>(Arrays.asList("foo27"));
+ pkg.mQueriesIntents = new ArrayList<>(Arrays.asList(new Intent("foo28")));
}
private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
new file mode 100644
index 000000000000..06c6314ab907
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2019 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 android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.util.List;
+
+class PackageSettingBuilder {
+ private String mName;
+ private String mRealName;
+ private String mCodePath;
+ private String mResourcePath;
+ private String mLegacyNativeLibraryPathString;
+ private String mPrimaryCpuAbiString;
+ private String mSecondaryCpuAbiString;
+ private String mCpuAbiOverrideString;
+ private long mPVersionCode;
+ private int mPkgFlags;
+ private int mPrivateFlags;
+ private String mParentPackageName;
+ private List<String> mChildPackageNames;
+ private int mSharedUserId;
+ private String[] mUsesStaticLibraries;
+ private long[] mUsesStaticLibrariesVersions;
+ private String mVolumeUuid;
+ private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
+ private PackageParser.Package mPkg;
+
+ public PackageSettingBuilder setPackage(PackageParser.Package pkg) {
+ this.mPkg = pkg;
+ return this;
+ }
+
+ public PackageSettingBuilder setName(String name) {
+ this.mName = name;
+ return this;
+ }
+
+ public PackageSettingBuilder setRealName(String realName) {
+ this.mRealName = realName;
+ return this;
+ }
+
+ public PackageSettingBuilder setCodePath(String codePath) {
+ this.mCodePath = codePath;
+ return this;
+ }
+
+ public PackageSettingBuilder setResourcePath(String resourcePath) {
+ this.mResourcePath = resourcePath;
+ return this;
+ }
+
+ public PackageSettingBuilder setLegacyNativeLibraryPathString(
+ String legacyNativeLibraryPathString) {
+ this.mLegacyNativeLibraryPathString = legacyNativeLibraryPathString;
+ return this;
+ }
+
+ public PackageSettingBuilder setPrimaryCpuAbiString(String primaryCpuAbiString) {
+ this.mPrimaryCpuAbiString = primaryCpuAbiString;
+ return this;
+ }
+
+ public PackageSettingBuilder setSecondaryCpuAbiString(String secondaryCpuAbiString) {
+ this.mSecondaryCpuAbiString = secondaryCpuAbiString;
+ return this;
+ }
+
+ public PackageSettingBuilder setCpuAbiOverrideString(String cpuAbiOverrideString) {
+ this.mCpuAbiOverrideString = cpuAbiOverrideString;
+ return this;
+ }
+
+ public PackageSettingBuilder setPVersionCode(long pVersionCode) {
+ this.mPVersionCode = pVersionCode;
+ return this;
+ }
+
+ public PackageSettingBuilder setPkgFlags(int pkgFlags) {
+ this.mPkgFlags = pkgFlags;
+ return this;
+ }
+
+ public PackageSettingBuilder setPrivateFlags(int privateFlags) {
+ this.mPrivateFlags = privateFlags;
+ return this;
+ }
+
+ public PackageSettingBuilder setParentPackageName(String parentPackageName) {
+ this.mParentPackageName = parentPackageName;
+ return this;
+ }
+
+ public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) {
+ this.mChildPackageNames = childPackageNames;
+ return this;
+ }
+
+ public PackageSettingBuilder setSharedUserId(int sharedUserId) {
+ this.mSharedUserId = sharedUserId;
+ return this;
+ }
+
+ public PackageSettingBuilder setUsesStaticLibraries(String[] usesStaticLibraries) {
+ this.mUsesStaticLibraries = usesStaticLibraries;
+ return this;
+ }
+
+ public PackageSettingBuilder setUsesStaticLibrariesVersions(
+ long[] usesStaticLibrariesVersions) {
+ this.mUsesStaticLibrariesVersions = usesStaticLibrariesVersions;
+ return this;
+ }
+
+ public PackageSettingBuilder setVolumeUuid(String volumeUuid) {
+ this.mVolumeUuid = volumeUuid;
+ return this;
+ }
+
+ public PackageSettingBuilder setInstantAppUserState(int userId, boolean isInstant) {
+ if (mUserStates.indexOfKey(userId) < 0) {
+ mUserStates.put(userId, new PackageUserState());
+ }
+ mUserStates.get(userId).instantApp = isInstant;
+ return this;
+ }
+
+ public PackageSetting build() {
+ final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
+ new File(mCodePath), new File(mResourcePath),
+ mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
+ mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
+ mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
+ mUsesStaticLibrariesVersions);
+ packageSetting.pkg = mPkg;
+ packageSetting.volumeUuid = this.mVolumeUuid;
+ for (int i = 0; i < mUserStates.size(); i++) {
+ packageSetting.setUserState(mUserStates.keyAt(i), mUserStates.valueAt(i));
+ }
+ return packageSetting;
+
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
new file mode 100644
index 000000000000..34a3f860496a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 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 android.content.pm.PackageParser;
+import android.os.UserHandle;
+
+class ScanRequestBuilder {
+ private final PackageParser.Package mPkg;
+ private PackageParser.Package mOldPkg;
+ private SharedUserSetting mSharedUserSetting;
+ private PackageSetting mPkgSetting;
+ private PackageSetting mDisabledPkgSetting;
+ private PackageSetting mOriginalPkgSetting;
+ private String mRealPkgName;
+ private int mParseFlags;
+ private int mScanFlags;
+ private UserHandle mUser;
+ private boolean mIsPlatformPackage;
+
+ ScanRequestBuilder(PackageParser.Package pkg) {
+ this.mPkg = pkg;
+ }
+
+ public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) {
+ this.mOldPkg = oldPkg;
+ return this;
+ }
+
+ public ScanRequestBuilder setSharedUserSetting(SharedUserSetting sharedUserSetting) {
+ this.mSharedUserSetting = sharedUserSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setPkgSetting(PackageSetting pkgSetting) {
+ this.mPkgSetting = pkgSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setDisabledPkgSetting(PackageSetting disabledPkgSetting) {
+ this.mDisabledPkgSetting = disabledPkgSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setOriginalPkgSetting(PackageSetting originalPkgSetting) {
+ this.mOriginalPkgSetting = originalPkgSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setRealPkgName(String realPkgName) {
+ this.mRealPkgName = realPkgName;
+ return this;
+ }
+
+ public ScanRequestBuilder setParseFlags(int parseFlags) {
+ this.mParseFlags = parseFlags;
+ return this;
+ }
+
+ public ScanRequestBuilder addParseFlag(int parseFlag) {
+ this.mParseFlags |= parseFlag;
+ return this;
+ }
+
+ public ScanRequestBuilder setScanFlags(int scanFlags) {
+ this.mScanFlags = scanFlags;
+ return this;
+ }
+
+ public ScanRequestBuilder addScanFlag(int scanFlag) {
+ this.mScanFlags |= scanFlag;
+ return this;
+ }
+
+ public ScanRequestBuilder setUser(UserHandle user) {
+ this.mUser = user;
+ return this;
+ }
+
+ public ScanRequestBuilder setIsPlatformPackage(boolean isPlatformPackage) {
+ this.mIsPlatformPackage = isPlatformPackage;
+ return this;
+ }
+
+ PackageManagerService.ScanRequest build() {
+ return new PackageManagerService.ScanRequest(
+ mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
+ mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
+ mUser);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
new file mode 100644
index 000000000000..dd3d8b929793
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2019 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.SharedLibraryInfo.TYPE_DYNAMIC;
+import static android.content.pm.SharedLibraryInfo.TYPE_STATIC;
+import static android.content.pm.SharedLibraryInfo.VERSION_UNDEFINED;
+
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
+import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.collection.IsArrayContainingInOrder.arrayContaining;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertNotSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
+import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.File;
+
+@RunWith(MockitoJUnitRunner.class)
+@Presubmit
+// TODO: shared user tests
+public class ScanTests {
+
+ private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
+
+ @Mock
+ PackageAbiHelper mMockPackageAbiHelper;
+ @Mock
+ UserManagerInternal mMockUserManager;
+
+ @Before
+ public void setupDefaultUser() {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+ }
+
+ @Before
+ public void setupDefaultAbiBehavior() throws Exception {
+ when(mMockPackageAbiHelper.derivePackageAbi(
+ any(PackageParser.Package.class), nullable(String.class), anyBoolean()))
+ .thenReturn(new Pair<>(
+ new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
+ new PackageAbiHelper.NativeLibraryPaths(
+ "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
+ when(mMockPackageAbiHelper.getNativeLibraryPaths(
+ any(PackageParser.Package.class), any(File.class)))
+ .thenReturn(new PackageAbiHelper.NativeLibraryPaths(
+ "getRootDir", true, "getNativeDir", "getNativeDir2"
+ ));
+ when(mMockPackageAbiHelper.getBundledAppAbis(
+ any(PackageParser.Package.class)))
+ .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
+ }
+
+ @Test
+ public void newInstallSimpleAllNominal() throws Exception {
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+ .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+ assertThat(scanResult.existingSettingCopied, is(false));
+ assertPathsNotDerived(scanResult);
+ }
+
+ @Test
+ public void newInstallForAllUsers() throws Exception {
+ final int[] userIds = {0, 10, 11};
+ when(mMockUserManager.getUserIds()).thenReturn(userIds);
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setRealPkgName(null)
+ .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+ .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+ .build();
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ for (int uid : userIds) {
+ assertThat(scanResult.pkgSetting.readUserState(uid).installed, is(true));
+ }
+ }
+
+ @Test
+ public void installRealPackageName() throws Exception {
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setRealPkgName("com.package.real")
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.pkgSetting.realName, is("com.package.real"));
+
+ final PackageManagerService.ScanRequest scanRequestNoRealPkg =
+ createBasicScanRequestBuilder(
+ createBasicPackage(DUMMY_PACKAGE_NAME)
+ .setRealPackageName("com.package.real").build())
+ .build();
+
+ final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
+ assertThat(scanResultNoReal.pkgSetting.realName, nullValue());
+ }
+
+ @Test
+ public void updateSimpleNominal() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting pkgSetting = createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setPrimaryCpuAbiString("primaryCpuAbi")
+ .setSecondaryCpuAbiString("secondaryCpuAbi")
+ .build();
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+ .setPkgSetting(pkgSetting)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.existingSettingCopied, is(true));
+
+ // ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
+ assertNotSame(pkgSetting, scanResult.pkgSetting);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+
+ assertThat(scanResult.pkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
+ assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
+ assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());
+
+ assertPathsNotDerived(scanResult);
+ }
+
+ @Test
+ public void updateInstantSimpleNominal() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setInstantAppUserState(0, true)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+ }
+
+ @Test
+ public void installStaticSharedLibrary() throws Exception {
+ final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123")
+ .setStaticSharedLib("static.lib", 123L)
+ .setManifestPackageName("static.lib.pkg")
+ .setVersionCodeMajor(1)
+ .setVersionCode(234)
+ .setBaseCodePath("/some/path.apk")
+ .addSplitCodePath("/some/other/path.apk")
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(
+ pkg).setUser(UserHandle.of(0)).build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.staticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
+ assertThat(scanResult.staticSharedLibraryInfo.getName(), is("static.lib"));
+ assertThat(scanResult.staticSharedLibraryInfo.getLongVersion(), is(123L));
+ assertThat(scanResult.staticSharedLibraryInfo.getType(), is(TYPE_STATIC));
+ assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
+ is("static.lib.pkg"));
+ assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
+ is(pkg.getLongVersionCode()));
+ assertThat(scanResult.staticSharedLibraryInfo.getAllCodePaths(),
+ hasItems("/some/path.apk", "/some/other/path.apk"));
+ assertThat(scanResult.staticSharedLibraryInfo.getDependencies(), nullValue());
+ assertThat(scanResult.staticSharedLibraryInfo.getDependentPackages(), empty());
+ }
+
+ @Test
+ public void installDynamicLibraries() throws Exception {
+ final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg")
+ .setManifestPackageName("dynamic.lib.pkg")
+ .addLibraryName("liba")
+ .addLibraryName("libb")
+ .setVersionCodeMajor(1)
+ .setVersionCode(234)
+ .setBaseCodePath("/some/path.apk")
+ .addSplitCodePath("/some/other/path.apk")
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ final SharedLibraryInfo dynamicLib0 = scanResult.dynamicSharedLibraryInfos.get(0);
+ assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib0.getName(), is("liba"));
+ assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
+ assertThat(dynamicLib0.getType(), is(TYPE_DYNAMIC));
+ assertThat(dynamicLib0.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib0.getDeclaringPackage().getLongVersionCode(),
+ is(pkg.getLongVersionCode()));
+ assertThat(dynamicLib0.getAllCodePaths(),
+ hasItems("/some/path.apk", "/some/other/path.apk"));
+ assertThat(dynamicLib0.getDependencies(), nullValue());
+ assertThat(dynamicLib0.getDependentPackages(), empty());
+
+ final SharedLibraryInfo dynamicLib1 = scanResult.dynamicSharedLibraryInfos.get(1);
+ assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib1.getName(), is("libb"));
+ assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
+ assertThat(dynamicLib1.getType(), is(TYPE_DYNAMIC));
+ assertThat(dynamicLib1.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib1.getDeclaringPackage().getLongVersionCode(),
+ is(pkg.getLongVersionCode()));
+ assertThat(dynamicLib1.getAllCodePaths(),
+ hasItems("/some/path.apk", "/some/other/path.apk"));
+ assertThat(dynamicLib1.getDependencies(), nullValue());
+ assertThat(dynamicLib1.getDependentPackages(), empty());
+ }
+
+ @Test
+ public void volumeUuidChangesOnUpdate() throws Exception {
+ final PackageSetting pkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setVolumeUuid("someUuid")
+ .build();
+
+ final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .setApplicationInfoVolumeUuid("someNewUuid")
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(
+ new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
+
+ assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid"));
+ }
+
+ @Test
+ public void scanFirstBoot_derivesAbis() throws Exception {
+ final PackageSetting pkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
+
+ final PackageParser.Package basicPackage =
+ createBasicPackage(DUMMY_PACKAGE_NAME)
+ .setCpuAbiOVerride("testOverride")
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
+ basicPackage)
+ .setPkgSetting(pkgSetting)
+ .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
+ .build());
+
+ assertAbiAndPathssDerived(scanResult);
+ }
+
+ @Test
+ public void scanWithOriginalPkgSetting_packageNameChanges() throws Exception {
+ final PackageSetting originalPkgSetting =
+ createBasicPackageSettingBuilder("original.package").build();
+
+ final PackageParser.Package basicPackage =
+ createBasicPackage(DUMMY_PACKAGE_NAME)
+ .build();
+
+
+ final PackageManagerService.ScanResult result =
+ executeScan(new ScanRequestBuilder(basicPackage)
+ .setOriginalPkgSetting(originalPkgSetting)
+ .build());
+
+ assertThat(result.request.pkg.packageName, is("original.package"));
+ }
+
+ @Test
+ public void updateInstant_changeToFull() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setInstantAppUserState(0, true)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .addScanFlag(SCAN_AS_FULL_APP)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+ }
+
+ @Test
+ public void updateFull_changeToInstant() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setInstantAppUserState(0, false)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .addScanFlag(SCAN_AS_INSTANT_APP)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+ }
+
+ @Test
+ public void updateSystemApp_applicationInfoFlagSet() throws Exception {
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .setDisabledPkgSetting(existingPkgSetting)
+ .addScanFlag(SCAN_NEW_INSTALL)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.request.pkg.applicationInfo.flags,
+ hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
+ }
+
+ @Test
+ public void factoryTestFlagSet() throws Exception {
+ final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .addPermissionRequest(Manifest.permission.FACTORY_TEST)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
+ createBasicScanRequestBuilder(basicPackage).build(),
+ new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+ true /*isUnderFactoryTest*/,
+ System.currentTimeMillis());
+
+ assertThat(scanResult.request.pkg.applicationInfo.flags,
+ hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
+ }
+
+ @Test
+ public void scanSystemApp_isOrphanedTrue() throws Exception {
+ final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(pkg)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.pkgSetting.isOrphaned, is(true));
+ }
+
+ private static Matcher<Integer> hasFlag(final int flag) {
+ return new BaseMatcher<Integer>() {
+ @Override public void describeTo(Description description) {
+ description.appendText("flags ");
+ }
+
+ @Override public boolean matches(Object item) {
+ return ((int) item & flag) != 0;
+ }
+
+ @Override
+ public void describeMismatch(Object item, Description mismatchDescription) {
+ mismatchDescription
+ .appendValue(item)
+ .appendText(" does not contain flag ")
+ .appendValue(flag);
+ }
+ };
+ }
+
+ private PackageManagerService.ScanResult executeScan(
+ PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
+ return PackageManagerService.scanPackageOnlyLI(
+ scanRequest,
+ new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+ false /*isUnderFactoryTest*/,
+ System.currentTimeMillis());
+ }
+
+ private static String createResourcePath(String packageName) {
+ return "/data/app/" + packageName + "-randompath/base.apk";
+ }
+
+ private static String createCodePath(String packageName) {
+ return "/data/app/" + packageName + "-randompath";
+ }
+
+ private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) {
+ return new PackageSettingBuilder()
+ .setName(packageName)
+ .setCodePath(createCodePath(packageName))
+ .setResourcePath(createResourcePath(packageName));
+ }
+
+ private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) {
+ return new ScanRequestBuilder(pkg)
+ .setUser(UserHandle.of(0));
+ }
+
+
+ private static PackageBuilder createBasicPackage(String packageName) {
+ return new PackageBuilder(packageName)
+ .setCodePath("/data/tmp/randompath")
+ .setApplicationInfoCodePath(createCodePath(packageName))
+ .setApplicationInfoResourcePath(createResourcePath(packageName))
+ .setApplicationInfoVolumeUuid("volumeUuid")
+ .setBaseCodePath("/data/tmp/randompath/base.apk")
+ .addUsesStaticLibrary("some.static.library", 234L)
+ .addUsesStaticLibrary("some.other.static.library", 456L)
+ .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
+ .setVersionCodeMajor(1)
+ .setVersionCode(2345);
+ }
+
+ private static void assertBasicPackageScanResult(
+ PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant) {
+ assertThat(scanResult.success, is(true));
+
+ final PackageSetting pkgSetting = scanResult.pkgSetting;
+ assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
+
+ final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
+ assertBasicApplicationInfo(scanResult, applicationInfo);
+
+ }
+
+ private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
+ String packageName, boolean isInstant, PackageSetting pkgSetting) {
+ assertThat(pkgSetting.pkg.packageName, is(packageName));
+ assertThat(pkgSetting.getInstantApp(0), is(isInstant));
+ assertThat(pkgSetting.usesStaticLibraries,
+ arrayContaining("some.static.library", "some.other.static.library"));
+ assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
+ assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
+ assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
+ assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
+ assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
+ assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
+ }
+
+ private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
+ ApplicationInfo applicationInfo) {
+ assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
+
+ final int uid = applicationInfo.uid;
+ assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
+
+ final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
+ applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
+ scanResult.request.pkg.packageName).getAbsolutePath();
+ assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
+ assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
+ }
+
+ private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
+ final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+ assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
+ assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
+
+ assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir"));
+ assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
+ assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
+ assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir"));
+ assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
+ }
+
+ private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
+ final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+ assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
+ assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
+ assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
+ assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir"));
+ assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2"));
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index f5002ace6690..3b336eb7aec9 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -7,10 +7,12 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -159,4 +161,25 @@ public class PinnedSliceStateTest extends UiServiceTestCase {
verify(mSliceService).removePinnedSlice(eq(TEST_URI));
assertFalse(mPinnedSliceManager.hasPinOrListener());
}
+
+ @Test
+ public void testPinFailed() throws Exception {
+ // Throw exception when trying to pin
+ doAnswer(invocation -> {
+ throw new Exception("Pin failed");
+ }).when(mIContentProvider).call(
+ anyString(), anyString(), anyString(), eq(null), any());
+
+ TestableLooper.get(this).processAllMessages();
+
+ // When pinned for the first time, a pinned message should be sent.
+ mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
+ TestableLooper.get(this).processAllMessages();
+
+ verify(mIContentProvider).call(anyString(), anyString(), eq(SliceProvider.METHOD_PIN),
+ eq(null), argThat(b -> {
+ assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
+ return true;
+ }));
+ }
}
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 a08923bafe28..3d944671ef25 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -842,4 +842,51 @@ public class ActivityStarterTests extends ActivityTestsBase {
// Ensure the activity is moved to secondary display.
assertEquals(secondaryDisplay, topActivity.getDisplay());
}
+
+ /**
+ * This test ensures that starting an activity with the freeze-task-list activity option will
+ * actually freeze the task list
+ */
+ @Test
+ public void testFreezeTaskListActivityOption() {
+ RecentTasks recentTasks = mock(RecentTasks.class);
+ mService.mStackSupervisor.setRecentTasks(recentTasks);
+ doReturn(true).when(recentTasks).isCallerRecents(anyInt());
+
+ final ActivityStarter starter = prepareStarter(0 /* flags */);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setFreezeRecentTasksReordering();
+
+ starter.setReason("testFreezeTaskListActivityOption")
+ .setActivityOptions(new SafeActivityOptions(options))
+ .execute();
+
+ verify(recentTasks, times(1)).setFreezeTaskListReordering();
+ verify(recentTasks, times(0)).resetFreezeTaskListReorderingOnTimeout();
+ }
+
+ /**
+ * This test ensures that if we froze the task list as a part of starting an activity that fails
+ * to start, that we also reset the task list.
+ */
+ @Test
+ public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
+ RecentTasks recentTasks = mock(RecentTasks.class);
+ mService.mStackSupervisor.setRecentTasks(recentTasks);
+ doReturn(true).when(recentTasks).isCallerRecents(anyInt());
+
+ final ActivityStarter starter = prepareStarter(0 /* flags */);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setFreezeRecentTasksReordering();
+
+ starter.setReason("testFreezeTaskListActivityOptionFailedStart")
+ .setActivityOptions(new SafeActivityOptions(options))
+ .execute();
+
+ // Simulate a failed start
+ starter.postStartActivityProcessing(null, START_ABORTED, null);
+
+ verify(recentTasks, times(1)).setFreezeTaskListReordering();
+ verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 26cd63c62cc1..cd292b2494ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -25,6 +25,7 @@ import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
@@ -35,10 +36,12 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_O
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
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 android.os.Binder;
@@ -79,6 +82,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Hold the lock to protect the stubbing from being accessed by other threads.
spyOn(mWm.mRoot);
doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+ doReturn(mDisplayContent).when(mWm.mRoot).getDisplayContent(anyInt());
}
when(mMockRunner.asBinder()).thenReturn(new Binder());
mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
@@ -135,7 +139,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
hiddenAppWindow.setHidden(true);
mDisplayContent.getConfiguration().windowConfiguration.setRotation(
mDisplayContent.getRotation());
- mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
// Ensure that we are animating the target activity as well
assertTrue(mController.isAnimatingTask(homeAppWindow.getTask()));
@@ -144,7 +148,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
}
@Test
- public void testCancelAnimationWithScreenShot() throws Exception {
+ public void testDeferCancelAnimation() throws Exception {
mWm.setRecentsAnimationController(mController);
final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -156,8 +160,31 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
assertTrue(mController.isAnimatingTask(appWindow.getTask()));
- mController.setCancelWithDeferredScreenshotLocked(true);
- mController.cancelAnimationWithScreenShot();
+ mController.setDeferredCancel(true /* deferred */, false /* screenshot */);
+ mController.cancelAnimationWithScreenshot(false /* screenshot */);
+ verify(mMockRunner).onAnimationCanceled(false /* deferredWithScreenshot */);
+ assertNull(mController.mRecentScreenshotAnimator);
+
+ // Simulate the app transition finishing
+ mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0, 0, 0);
+ verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
+ }
+
+ @Test
+ public void testDeferCancelAnimationWithScreenShot() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+ appWindow.addWindow(win1);
+ assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow);
+ assertEquals(appWindow.findMainWindow(), win1);
+
+ mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
+ assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+
+ mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
+ mController.cancelAnimationWithScreenshot(true /* screenshot */);
verify(mMockRunner).onAnimationCanceled(true /* deferredWithScreenshot */);
assertNotNull(mController.mRecentScreenshotAnimator);
assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
@@ -185,7 +212,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Assume appWindow transition should animate when no
// IRecentsAnimationController#setCancelWithDeferredScreenshot called.
- assertFalse(mController.shouldCancelWithDeferredScreenshot());
+ assertFalse(mController.shouldDeferCancelWithScreenshot());
assertTrue(appWindow.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 9630b7d46e3c..0e119e3cc375 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -274,12 +274,13 @@ public class RecentsAnimationTest extends ActivityTestsBase {
// Assume recents animation already started, set a state that cancel recents animation
// with screenshot.
- doReturn(true).when(mRecentsAnimationController).shouldCancelWithDeferredScreenshot();
+ doReturn(true).when(mRecentsAnimationController).shouldDeferCancelUntilNextTransition();
+ doReturn(true).when(mRecentsAnimationController).shouldDeferCancelWithScreenshot();
// Start another fullscreen activity.
fullscreenStack2.moveToFront("Activity start");
- // Ensure that the recents animation was canceled by cancelOnNextTransitionStart().
- verify(mRecentsAnimationController, times(1)).cancelOnNextTransitionStart();
+ // Ensure that the recents animation was canceled by setCancelOnNextTransitionStart().
+ verify(mRecentsAnimationController, times(1)).setCancelOnNextTransitionStart();
}
@Test
@@ -315,7 +316,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
// Ensure that the recents animation was NOT canceled
verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously(
eq(REORDER_KEEP_IN_PLACE), any());
- verify(mRecentsAnimationController, times(0)).cancelOnNextTransitionStart();
+ verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart();
}
@Test
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 29398b6b6e75..2cebebfc292e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1251,6 +1251,22 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
assertEquals(startingBounds, adjustedBounds);
}
+ @Test
+ public void testNoMultiDisplaySupports() {
+ final boolean orgValue = mService.mSupportsMultiDisplay;
+ final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+ mCurrent.mPreferredDisplayId = display.mDisplayId;
+
+ try {
+ mService.mSupportsMultiDisplay = false;
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+ assertEquals(DEFAULT_DISPLAY, mResult.mPreferredDisplayId);
+ } finally {
+ mService.mSupportsMultiDisplay = orgValue;
+ }
+ }
+
private TestActivityDisplay createNewActivityDisplay(int windowingMode) {
final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
display.setWindowingMode(windowingMode);
diff --git a/startop/apps/test/Android.bp b/startop/apps/test/Android.bp
index 7a1678ac9a5a..a4906d7b4cd3 100644
--- a/startop/apps/test/Android.bp
+++ b/startop/apps/test/Android.bp
@@ -23,4 +23,5 @@ android_app {
"src/FrameLayoutInflationActivity.java",
"src/TextViewInflationActivity.java",
],
+ platform_apis: true,
}
diff --git a/startop/scripts/iorap/compiler.py b/startop/scripts/iorap/compiler.py
index a335b30da8a5..9527e28c94fe 100755
--- a/startop/scripts/iorap/compiler.py
+++ b/startop/scripts/iorap/compiler.py
@@ -305,7 +305,7 @@ def main(argv):
transform_perfetto_trace_to_systrace(options.perfetto_trace_file,
trace_file.name)
return run(sql_db_path,
- options.trace_file,
+ trace_file.name,
options.trace_duration,
options.output_file,
inode_table,
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 6047e8c74e38..09f9c04d9e2c 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -102,6 +102,12 @@ std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
case Instruction::Op::kCheckCast:
out << "kCheckCast";
return out;
+ case Instruction::Op::kGetStaticField:
+ out << "kGetStaticField";
+ return out;
+ case Instruction::Op::kSetStaticField:
+ out << "kSetStaticField";
+ return out;
}
}
@@ -229,6 +235,22 @@ ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) {
return type;
}
+ir::FieldDecl* DexBuilder::GetOrAddField(TypeDescriptor parent, const std::string& name,
+ TypeDescriptor type) {
+ const auto key = std::make_tuple(parent, name);
+ if (field_decls_by_key_.find(key) != field_decls_by_key_.end()) {
+ return field_decls_by_key_[key];
+ }
+
+ ir::FieldDecl* field = Alloc<ir::FieldDecl>();
+ field->parent = GetOrAddType(parent);
+ field->name = GetOrAddString(name);
+ field->type = GetOrAddType(type);
+ dex_file_->fields_map[field->orig_index] = field;
+ field_decls_by_key_[key] = field;
+ return field;
+}
+
ir::Proto* Prototype::Encode(DexBuilder* dex) const {
auto* proto = dex->Alloc<ir::Proto>();
proto->shorty = dex->GetOrAddString(Shorty());
@@ -360,6 +382,9 @@ void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
return EncodeNew(instruction);
case Instruction::Op::kCheckCast:
return EncodeCast(instruction);
+ case Instruction::Op::kGetStaticField:
+ case Instruction::Op::kSetStaticField:
+ return EncodeStaticFieldOp(instruction);
}
}
@@ -428,7 +453,7 @@ void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruct
// first move all the arguments into contiguous temporary registers.
std::array<Value, kMaxArgs> scratch = GetScratchRegisters<kMaxArgs>();
- const auto& prototype = dex_->GetPrototypeByMethodId(instruction.method_id());
+ const auto& prototype = dex_->GetPrototypeByMethodId(instruction.index_argument());
CHECK(prototype.has_value());
for (size_t i = 0; i < instruction.args().size(); ++i) {
@@ -452,12 +477,12 @@ void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruct
Encode3rc(InvokeToInvokeRange(opcode),
instruction.args().size(),
- instruction.method_id(),
+ instruction.index_argument(),
RegisterValue(scratch[0]));
} else {
Encode35c(opcode,
instruction.args().size(),
- instruction.method_id(),
+ instruction.index_argument(),
arguments[0],
arguments[1],
arguments[2],
@@ -514,6 +539,35 @@ void MethodBuilder::EncodeCast(const Instruction& instruction) {
Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
}
+void MethodBuilder::EncodeStaticFieldOp(const Instruction& instruction) {
+ switch (instruction.opcode()) {
+ case Instruction::Op::kGetStaticField: {
+ CHECK(instruction.dest().has_value());
+ CHECK(instruction.dest()->is_variable());
+ CHECK_EQ(0, instruction.args().size());
+
+ Encode21c(::art::Instruction::SGET,
+ RegisterValue(*instruction.dest()),
+ instruction.index_argument());
+ break;
+ }
+ case Instruction::Op::kSetStaticField: {
+ CHECK(!instruction.dest().has_value());
+ const auto& args = instruction.args();
+ CHECK_EQ(1, args.size());
+ CHECK(args[0].is_variable());
+
+ Encode21c(::art::Instruction::SPUT,
+ RegisterValue(args[0]),
+ instruction.index_argument());
+ break;
+ }
+ default: {
+ LOG(FATAL) << "Unsupported static field operation";
+ }
+ }
+}
+
size_t MethodBuilder::RegisterValue(const Value& value) const {
if (value.is_register()) {
return value.value();
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index 541d80077bd3..3f9ac43ae532 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -153,6 +153,7 @@ class Instruction {
kBranchEqz,
kBranchNEqz,
kCheckCast,
+ kGetStaticField,
kInvokeDirect,
kInvokeInterface,
kInvokeStatic,
@@ -162,6 +163,7 @@ class Instruction {
kNew,
kReturn,
kReturnObject,
+ kSetStaticField
};
////////////////////////
@@ -170,12 +172,12 @@ class Instruction {
// For instructions with no return value and no arguments.
static inline Instruction OpNoArgs(Op opcode) {
- return Instruction{opcode, /*method_id*/ 0, /*dest*/ {}};
+ return Instruction{opcode, /*index_argument*/ 0, /*dest*/ {}};
}
// For most instructions, which take some number of arguments and have an optional return value.
template <typename... T>
static inline Instruction OpWithArgs(Op opcode, std::optional<const Value> dest, T... args) {
- return Instruction{opcode, /*method_id=*/0, /*result_is_object=*/false, dest, args...};
+ return Instruction{opcode, /*index_argument=*/0, /*result_is_object=*/false, dest, args...};
}
// A cast instruction. Basically, `(type)val`
@@ -186,77 +188,87 @@ class Instruction {
// For method calls.
template <typename... T>
- static inline Instruction InvokeVirtual(size_t method_id, std::optional<const Value> dest,
+ static inline Instruction InvokeVirtual(size_t index_argument, std::optional<const Value> dest,
Value this_arg, T... args) {
return Instruction{
- Op::kInvokeVirtual, method_id, /*result_is_object=*/false, dest, this_arg, args...};
+ Op::kInvokeVirtual, index_argument, /*result_is_object=*/false, dest, this_arg, args...};
}
// Returns an object
template <typename... T>
- static inline Instruction InvokeVirtualObject(size_t method_id, std::optional<const Value> dest,
+ static inline Instruction InvokeVirtualObject(size_t index_argument, std::optional<const Value> dest,
Value this_arg, T... args) {
return Instruction{
- Op::kInvokeVirtual, method_id, /*result_is_object=*/true, dest, this_arg, args...};
+ Op::kInvokeVirtual, index_argument, /*result_is_object=*/true, dest, this_arg, args...};
}
// For direct calls (basically, constructors).
template <typename... T>
- static inline Instruction InvokeDirect(size_t method_id, std::optional<const Value> dest,
+ static inline Instruction InvokeDirect(size_t index_argument, std::optional<const Value> dest,
Value this_arg, T... args) {
return Instruction{
- Op::kInvokeDirect, method_id, /*result_is_object=*/false, dest, this_arg, args...};
+ Op::kInvokeDirect, index_argument, /*result_is_object=*/false, dest, this_arg, args...};
}
// Returns an object
template <typename... T>
- static inline Instruction InvokeDirectObject(size_t method_id, std::optional<const Value> dest,
+ static inline Instruction InvokeDirectObject(size_t index_argument, std::optional<const Value> dest,
Value this_arg, T... args) {
return Instruction{
- Op::kInvokeDirect, method_id, /*result_is_object=*/true, dest, this_arg, args...};
+ Op::kInvokeDirect, index_argument, /*result_is_object=*/true, dest, this_arg, args...};
}
// For static calls.
template <typename... T>
- static inline Instruction InvokeStatic(size_t method_id, std::optional<const Value> dest,
+ static inline Instruction InvokeStatic(size_t index_argument, std::optional<const Value> dest,
T... args) {
- return Instruction{Op::kInvokeStatic, method_id, /*result_is_object=*/false, dest, args...};
+ return Instruction{Op::kInvokeStatic, index_argument, /*result_is_object=*/false, dest, args...};
}
// Returns an object
template <typename... T>
- static inline Instruction InvokeStaticObject(size_t method_id, std::optional<const Value> dest,
+ static inline Instruction InvokeStaticObject(size_t index_argument, std::optional<const Value> dest,
T... args) {
- return Instruction{Op::kInvokeStatic, method_id, /*result_is_object=*/true, dest, args...};
+ return Instruction{Op::kInvokeStatic, index_argument, /*result_is_object=*/true, dest, args...};
}
// For static calls.
template <typename... T>
- static inline Instruction InvokeInterface(size_t method_id, std::optional<const Value> dest,
+ static inline Instruction InvokeInterface(size_t index_argument, std::optional<const Value> dest,
T... args) {
- return Instruction{Op::kInvokeInterface, method_id, /*result_is_object=*/false, dest, args...};
+ return Instruction{Op::kInvokeInterface, index_argument, /*result_is_object=*/false, dest, args...};
+
+ }
+
+ static inline Instruction GetStaticField(size_t field_id, Value dest) {
+ return Instruction{Op::kGetStaticField, field_id, dest};
+ }
+
+ static inline Instruction SetStaticField(size_t field_id, Value value) {
+ return Instruction{Op::kSetStaticField, field_id, /*result_is_object=*/false, /*dest=*/{}, value};
}
+
///////////////
// Accessors //
///////////////
Op opcode() const { return opcode_; }
- size_t method_id() const { return method_id_; }
+ size_t index_argument() const { return index_argument_; }
bool result_is_object() const { return result_is_object_; }
const std::optional<const Value>& dest() const { return dest_; }
const std::vector<const Value>& args() const { return args_; }
private:
- inline Instruction(Op opcode, size_t method_id, std::optional<const Value> dest)
- : opcode_{opcode}, method_id_{method_id}, result_is_object_{false}, dest_{dest}, args_{} {}
+ inline Instruction(Op opcode, size_t index_argument, std::optional<const Value> dest)
+ : opcode_{opcode}, index_argument_{index_argument}, result_is_object_{false}, dest_{dest}, args_{} {}
template <typename... T>
- inline constexpr Instruction(Op opcode, size_t method_id, bool result_is_object,
+ inline constexpr Instruction(Op opcode, size_t index_argument, bool result_is_object,
std::optional<const Value> dest, T... args)
: opcode_{opcode},
- method_id_{method_id},
+ index_argument_{index_argument},
result_is_object_{result_is_object},
dest_{dest},
args_{args...} {}
const Op opcode_;
// The index of the method to invoke, for kInvokeVirtual and similar opcodes.
- const size_t method_id_{0};
+ const size_t index_argument_{0};
const bool result_is_object_;
const std::optional<const Value> dest_;
const std::vector<const Value> args_;
@@ -319,6 +331,7 @@ class MethodBuilder {
void EncodeBranch(art::Instruction::Code op, const Instruction& instruction);
void EncodeNew(const Instruction& instruction);
void EncodeCast(const Instruction& instruction);
+ void EncodeStaticFieldOp(const Instruction& instruction);
// Low-level instruction format encoding. See
// https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of
@@ -481,6 +494,11 @@ class DexBuilder {
// See the TypeDescriptor class for help generating these. GetOrAddType can be used to declare
// imported classes.
ir::Type* GetOrAddType(const std::string& descriptor);
+ inline ir::Type* GetOrAddType(TypeDescriptor descriptor) {
+ return GetOrAddType(descriptor.descriptor());
+ }
+
+ ir::FieldDecl* GetOrAddField(TypeDescriptor parent, const std::string& name, TypeDescriptor type);
// Returns the method id for the method, creating it if it has not been created yet.
const MethodDeclData& GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
@@ -526,6 +544,9 @@ class DexBuilder {
// Keep track of already-encoded protos.
std::map<Prototype, ir::Proto*> proto_map_;
+
+ // Keep track of fields that have been declared
+ std::map<std::tuple<TypeDescriptor, std::string>, ir::FieldDecl*> field_decls_by_key_;
};
template <typename... T>
diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp
index 22a3cfafbc44..1214538e8f0d 100644
--- a/startop/view_compiler/dex_builder_test/Android.bp
+++ b/startop/view_compiler/dex_builder_test/Android.bp
@@ -39,6 +39,7 @@ android_test {
srcs: [
"src/android/startop/test/DexBuilderTest.java",
"src/android/startop/test/LayoutCompilerTest.java",
+ "src/android/startop/test/TestClass.java",
],
sdk_version: "current",
data: [":generate_dex_testcases", ":generate_compiled_layout1", ":generate_compiled_layout2"],
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
index f7b1674894f5..6c0b8bbe8b83 100644
--- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
@@ -24,10 +24,10 @@ import java.lang.reflect.Method;
// Adding tests here requires changes in several other places. See README.md in
// the view_compiler directory for more information.
-public class DexBuilderTest {
+public final class DexBuilderTest {
static ClassLoader loadDexFile(String filename) throws Exception {
return new PathClassLoader("/data/local/tmp/dex-builder-test/" + filename,
- ClassLoader.getSystemClassLoader());
+ DexBuilderTest.class.getClassLoader());
}
public void hello() {}
@@ -167,4 +167,23 @@ public class DexBuilderTest {
}
Assert.assertTrue(castFailed);
}
+
+ @Test
+ public void readStaticField() throws Exception {
+ ClassLoader loader = loadDexFile("simple.dex");
+ Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+ Method method = clazz.getMethod("readStaticField");
+ TestClass.staticInteger = 5;
+ Assert.assertEquals(5, method.invoke(null));
+ }
+
+ @Test
+ public void setStaticField() throws Exception {
+ ClassLoader loader = loadDexFile("simple.dex");
+ Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+ Method method = clazz.getMethod("setStaticField");
+ TestClass.staticInteger = 5;
+ method.invoke(null);
+ Assert.assertEquals(7, TestClass.staticInteger);
+ }
}
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/TestClass.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/TestClass.java
new file mode 100644
index 000000000000..dd7792306030
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/TestClass.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 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 android.startop.test;
+
+ /**
+ * A simple class to help test DexBuilder.
+ */
+public final class TestClass {
+ public static int staticInteger;
+
+ public int instanceField;
+}
diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc
index f62ec5dde85e..fee5e722bc55 100644
--- a/startop/view_compiler/dex_testcase_generator.cc
+++ b/startop/view_compiler/dex_testcase_generator.cc
@@ -282,6 +282,37 @@ void GenerateSimpleTestCases(const string& outdir) {
method.Encode();
}(castObjectToString);
+ // Read a static field
+ // integer readStaticField() { return TestClass.staticInteger; }
+ MethodBuilder readStaticField{
+ cbuilder.CreateMethod("readStaticField", Prototype{TypeDescriptor::Int()})};
+ [&](MethodBuilder& method) {
+ const ir::FieldDecl* field =
+ dex_file.GetOrAddField(TypeDescriptor::FromClassname("android.startop.test.TestClass"),
+ "staticInteger",
+ TypeDescriptor::Int());
+ Value result{method.MakeRegister()};
+ method.AddInstruction(Instruction::GetStaticField(field->orig_index, result));
+ method.BuildReturn(result, /*is_object=*/false);
+ method.Encode();
+ }(readStaticField);
+
+ // Set a static field
+ // void setStaticField() { TestClass.staticInteger = 7; }
+ MethodBuilder setStaticField{
+ cbuilder.CreateMethod("setStaticField", Prototype{TypeDescriptor::Void()})};
+ [&](MethodBuilder& method) {
+ const ir::FieldDecl* field =
+ dex_file.GetOrAddField(TypeDescriptor::FromClassname("android.startop.test.TestClass"),
+ "staticInteger",
+ TypeDescriptor::Int());
+ Value number{method.MakeRegister()};
+ method.BuildConst4(number, 7);
+ method.AddInstruction(Instruction::SetStaticField(field->orig_index, number));
+ method.BuildReturn();
+ method.Encode();
+ }(setStaticField);
+
slicer::MemView image{dex_file.CreateImage()};
std::ofstream out_file(outdir + "/simple.dex");
out_file.write(image.ptr<const char>(), image.size());
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 91bea5ff479b..cd79f37bb2ce 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2151,6 +2151,15 @@ public class CarrierConfigManager {
"data_warning_notification_bool";
/**
+ * Controls if the device should automatically warn the user that sim voice & data function
+ * might be limited due to dual sim scenario. When set to {@true} display the notification,
+ * {@code false} otherwise.
+ * @hide
+ */
+ public static final String KEY_LIMITED_SIM_FUNCTION_NOTIFICATION_FOR_DSDS_BOOL =
+ "limited_sim_function_notification_for_dsds_bool";
+
+ /**
* Controls the cellular data limit.
* <p>
* If the user uses more than this amount of data in their billing cycle, as defined by
@@ -3029,6 +3038,23 @@ public class CarrierConfigManager {
"is_opportunistic_subscription_bool";
/**
+ * Configs used by the IMS stack.
+ */
+ public static final class Ims {
+ /** Prefix of all Ims.KEY_* constants. */
+ public static final String KEY_PREFIX = "ims.";
+
+ //TODO: Add configs related to IMS.
+
+ private Ims() {}
+
+ private static PersistableBundle getDefaults() {
+ PersistableBundle defaults = new PersistableBundle();
+ return defaults;
+ }
+ }
+
+ /**
* A list of 4 GSM RSSI thresholds above which a signal level is considered POOR,
* MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
*
@@ -3326,6 +3352,7 @@ public class CarrierConfigManager {
sDefaults.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, DATA_CYCLE_USE_PLATFORM_DEFAULT);
sDefaults.putLong(KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, DATA_CYCLE_USE_PLATFORM_DEFAULT);
sDefaults.putBoolean(KEY_DATA_WARNING_NOTIFICATION_BOOL, true);
+ sDefaults.putBoolean(KEY_LIMITED_SIM_FUNCTION_NOTIFICATION_FOR_DSDS_BOOL, false);
sDefaults.putLong(KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, DATA_CYCLE_USE_PLATFORM_DEFAULT);
sDefaults.putBoolean(KEY_DATA_LIMIT_NOTIFICATION_BOOL, true);
sDefaults.putBoolean(KEY_DATA_RAPID_NOTIFICATION_BOOL, true);
@@ -3463,6 +3490,7 @@ public class CarrierConfigManager {
-89, /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
+ sDefaults.putAll(Ims.getDefaults());
}
/**
@@ -3659,4 +3687,75 @@ public class CarrierConfigManager {
return ICarrierConfigLoader.Stub
.asInterface(ServiceManager.getService(Context.CARRIER_CONFIG_SERVICE));
}
+
+ /**
+ * Gets the configuration values for a component using its prefix.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param prefix prefix of the component.
+ * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
+ *
+ * @see #getConfigForSubId
+ */
+ @Nullable
+ public PersistableBundle getConfigByComponentForSubId(String prefix, int subId) {
+ PersistableBundle configs = getConfigForSubId(subId);
+
+ if (configs == null) {
+ return null;
+ }
+
+ PersistableBundle ret = new PersistableBundle();
+ for (String configKey : configs.keySet()) {
+ if (configKey.startsWith(prefix)) {
+ addConfig(configKey, configs.get(configKey), ret);
+ }
+ }
+
+ return ret;
+ }
+
+ private void addConfig(String key, Object value, PersistableBundle configs) {
+ if (value instanceof String) {
+ configs.putString(key, (String) value);
+ }
+
+ if (value instanceof String[]) {
+ configs.putStringArray(key, (String[]) value);
+ }
+
+ if (value instanceof Integer) {
+ configs.putInt(key, (Integer) value);
+ }
+
+ if (value instanceof Long) {
+ configs.putLong(key, (Long) value);
+ }
+
+ if (value instanceof Double) {
+ configs.putDouble(key, (Double) value);
+ }
+
+ if (value instanceof Boolean) {
+ configs.putBoolean(key, (Boolean) value);
+ }
+
+ if (value instanceof int[]) {
+ configs.putIntArray(key, (int[]) value);
+ }
+
+ if (value instanceof double[]) {
+ configs.putDoubleArray(key, (double[]) value);
+ }
+
+ if (value instanceof boolean[]) {
+ configs.putBooleanArray(key, (boolean[]) value);
+ }
+
+ if (value instanceof long[]) {
+ configs.putLongArray(key, (long[]) value);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 9d732baf7514..fb16d540fbb4 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -143,7 +143,7 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P
}
/**
- * Get the signal strength as dBm
+ * Get the signal strength as dBm.
*/
@Override
public int getDbm() {
@@ -163,18 +163,17 @@ public final class CellSignalStrengthGsm extends CellSignalStrength implements P
}
/**
- * Return the Received Signal Strength Indicator
+ * Return the Received Signal Strength Indicator.
*
* @return the RSSI in dBm (-113, -51) or
* {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE}.
- * @hide
*/
public int getRssi() {
return mRssi;
}
/**
- * Return the Bit Error Rate
+ * Return the Bit Error Rate.
*
* @return the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
* {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE}.
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index 8c686f704967..8e1324b3be0b 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.pm.PackageManager;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import java.lang.annotation.Retention;
@@ -55,12 +56,23 @@ public final class ImsException extends Exception {
*/
public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2;
+ /**
+ * The subscription ID associated with this operation is invalid or not active.
+ * <p>
+ * This is a configuration error and there should be no retry. The subscription used for this
+ * operation is either invalid or has become inactive. The active subscriptions can be queried
+ * with {@link SubscriptionManager#getActiveSubscriptionInfoList()}.
+ * @hide
+ */
+ public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3;
+
/**@hide*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "CODE_ERROR_", value = {
CODE_ERROR_UNSPECIFIED,
CODE_ERROR_SERVICE_UNAVAILABLE,
- CODE_ERROR_UNSUPPORTED_OPERATION
+ CODE_ERROR_UNSUPPORTED_OPERATION,
+ CODE_ERROR_INVALID_SUBSCRIPTION
})
public @interface ImsErrorCode {}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index be5872387d7b..a1a7fcc5dd51 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -31,6 +31,7 @@ import android.net.Uri;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.telephony.AccessNetworkConstants;
import android.telephony.SubscriptionManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -375,6 +376,13 @@ public class ImsMmTelManager {
c.setExecutor(executor);
try {
getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException | IllegalStateException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -390,8 +398,6 @@ public class ImsMmTelManager {
* @param c The {@link RegistrationCallback} to be removed.
* @see SubscriptionManager.OnSubscriptionsChangedListener
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
- * @throws IllegalArgumentException if the subscription ID associated with this callback is
- * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
@@ -445,6 +451,13 @@ public class ImsMmTelManager {
c.setExecutor(executor);
try {
getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} catch (IllegalStateException e) {
@@ -460,8 +473,6 @@ public class ImsMmTelManager {
* inactive subscription, it will result in a no-op.
* @param c The MmTel {@link CapabilityCallback} to be removed.
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
- * @throws IllegalArgumentException if the subscription ID associated with this callback is
- * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
@@ -482,12 +493,9 @@ public class ImsMmTelManager {
* be enabled as long as the carrier has provisioned these services for the specified
* subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
* carrier requirements.
- *
- * Modifying this value may also trigger an IMS registration or deregistration, depending on
- * whether or not the new value is enabled or disabled.
- *
+ * <p>
* Note: If the carrier configuration for advanced calling is not editable or hidden, this
- * method will do nothing and will instead always use the default value.
+ * method will always return the default value.
*
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
* @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
@@ -495,12 +503,21 @@ public class ImsMmTelManager {
* @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
* @see #setAdvancedCallingSettingEnabled(boolean)
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user's setting for advanced calling is enabled, false otherwise.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isAdvancedCallingSettingEnabled() {
try {
return getITelephony().isAdvancedCallingSettingEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -526,12 +543,20 @@ public class ImsMmTelManager {
* @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
* @see #isAdvancedCallingSettingEnabled()
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
try {
getITelephony().setAdvancedCallingSettingEnabled(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -597,6 +622,9 @@ public class ImsMmTelManager {
/**
* The user's setting for whether or not they have enabled the "Video Calling" setting.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user’s “Video Calling” setting is currently enabled.
* @see #setVtSettingEnabled(boolean)
*/
@@ -604,6 +632,13 @@ public class ImsMmTelManager {
public boolean isVtSettingEnabled() {
try {
return getITelephony().isVtSettingEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -611,13 +646,22 @@ public class ImsMmTelManager {
/**
* Change the user's setting for Video Telephony and enable the Video Telephony capability.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #isVtSettingEnabled()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVtSettingEnabled(boolean isEnabled) {
try {
getITelephony().setVtSettingEnabled(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -625,12 +669,22 @@ public class ImsMmTelManager {
/**
* @return true if the user's setting for Voice over WiFi is enabled and false if it is not.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #setVoWiFiSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isVoWiFiSettingEnabled() {
try {
return getITelephony().isVoWiFiSettingEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -638,6 +692,9 @@ public class ImsMmTelManager {
/**
* Sets the user's setting for whether or not Voice over WiFi is enabled.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
* @see #isVoWiFiSettingEnabled()
*/
@@ -645,13 +702,23 @@ public class ImsMmTelManager {
public void setVoWiFiSettingEnabled(boolean isEnabled) {
try {
getITelephony().setVoWiFiSettingEnabled(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
+ * Returns the user's voice over WiFi roaming setting associated with the current subscription.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user's setting for Voice over WiFi while roaming is enabled, false
* if disabled.
* @see #setVoWiFiRoamingSettingEnabled(boolean)
@@ -660,6 +727,13 @@ public class ImsMmTelManager {
public boolean isVoWiFiRoamingSettingEnabled() {
try {
return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -667,15 +741,24 @@ public class ImsMmTelManager {
/**
* Change the user's setting for Voice over WiFi while roaming.
+ *
* @param isEnabled true if the user's setting for Voice over WiFi while roaming is enabled,
* false otherwise.
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #isVoWiFiRoamingSettingEnabled()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
try {
getITelephony().setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -691,19 +774,31 @@ public class ImsMmTelManager {
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #setVoWiFiSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
try {
getITelephony().setVoWiFiNonPersistent(mSubId, isCapable, mode);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
+ * Returns the user's voice over WiFi Roaming mode setting associated with the device.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @return The Voice over WiFi Mode preference set by the user, which can be one of the
* following:
* - {@link #WIFI_MODE_WIFI_ONLY}
@@ -715,6 +810,13 @@ public class ImsMmTelManager {
public @WiFiCallingMode int getVoWiFiModeSetting() {
try {
return getITelephony().getVoWiFiModeSetting(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -727,13 +829,21 @@ public class ImsMmTelManager {
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #getVoWiFiModeSetting()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
try {
getITelephony().setVoWiFiModeSetting(mSubId, mode);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -748,12 +858,21 @@ public class ImsMmTelManager {
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #setVoWiFiRoamingSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
try {
return getITelephony().getVoWiFiRoamingModeSetting(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -768,13 +887,21 @@ public class ImsMmTelManager {
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #getVoWiFiRoamingModeSetting()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
try {
getITelephony().setVoWiFiRoamingModeSetting(mSubId, mode);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -787,13 +914,21 @@ public class ImsMmTelManager {
* {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting
* for RTT. That value is enabled/disabled separately by the user through the Accessibility
* settings.
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @param isEnabled if true RTT should be enabled during calls made on this subscription.
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setRttCapabilitySetting(boolean isEnabled) {
try {
getITelephony().setRttCapabilitySetting(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -801,6 +936,9 @@ public class ImsMmTelManager {
/**
* @return true if TTY over VoLTE is supported
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see android.telecom.TelecomManager#getCurrentTtyMode
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
*/
@@ -808,6 +946,13 @@ public class ImsMmTelManager {
boolean isTtyOverVolteEnabled() {
try {
return getITelephony().isTtyOverVolteEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
new file mode 100644
index 000000000000..3c343dd19a86
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.ims;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.os.Binder;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.RcsFeature;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Manager for interfacing with the framework RCS services, including the User Capability Exchange
+ * (UCE) service, as well as managing user settings.
+ *
+ * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this manager.
+ * @hide
+ */
+public class ImsRcsManager {
+
+ /**
+ * Receives RCS availability status updates from the ImsService.
+ *
+ * @see #isAvailable(int)
+ * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
+ * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+ */
+ public static class AvailabilityCallback {
+
+ private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
+
+ private final AvailabilityCallback mLocalCallback;
+ private Executor mExecutor;
+
+ CapabilityBinder(AvailabilityCallback c) {
+ mLocalCallback = c;
+ }
+
+ @Override
+ public void onCapabilitiesStatusChanged(int config) {
+ if (mLocalCallback == null) return;
+
+ Binder.withCleanCallingIdentity(() ->
+ mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(
+ new RcsFeature.RcsImsCapabilities(config))));
+ }
+
+ @Override
+ public void onQueryCapabilityConfiguration(int capability, int radioTech,
+ boolean isEnabled) {
+ // This is not used for public interfaces.
+ }
+
+ @Override
+ public void onChangeCapabilityConfigurationError(int capability, int radioTech,
+ @ImsFeature.ImsCapabilityError int reason) {
+ // This is not used for public interfaces
+ }
+
+ private void setExecutor(Executor executor) {
+ mExecutor = executor;
+ }
+ }
+
+ private final CapabilityBinder mBinder = new CapabilityBinder(this);
+
+ /**
+ * The availability of the feature's capabilities has changed to either available or
+ * unavailable.
+ * <p>
+ * If unavailable, the feature does not support the capability at the current time. This may
+ * be due to network or subscription provisioning changes, such as the IMS registration
+ * being lost, network type changing, or OMA-DM provisioning updates.
+ *
+ * @param capabilities The new availability of the capabilities.
+ */
+ public void onAvailabilityChanged(RcsFeature.RcsImsCapabilities capabilities) {
+ }
+
+ /**@hide*/
+ public final IImsCapabilityCallback getBinder() {
+ return mBinder;
+ }
+
+ private void setExecutor(Executor executor) {
+ mBinder.setExecutor(executor);
+ }
+ }
+
+ private final int mSubId;
+ private final Context mContext;
+
+
+ /**
+ * Create an instance of ImsRcsManager for the subscription id specified.
+ *
+ * @param context The context to create this ImsRcsManager instance within.
+ * @param subscriptionId The ID of the subscription that this ImsRcsManager will use.
+ * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
+ * @throws IllegalArgumentException if the subscription is invalid.
+ * @hide
+ */
+ public static ImsRcsManager createForSubscriptionId(Context context, int subscriptionId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) {
+ throw new IllegalArgumentException("Invalid subscription ID");
+ }
+
+ return new ImsRcsManager(context, subscriptionId);
+ }
+
+ /**
+ * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this class.
+ */
+ private ImsRcsManager(Context context, int subId) {
+ mContext = context;
+ mSubId = subId;
+ }
+
+ /**
+ * Registers an {@link AvailabilityCallback} with the system, which will provide RCS
+ * availability updates for the subscription specified.
+ *
+ * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
+ * subscription changed events and call
+ * {@link #unregisterRcsAvailabilityCallback(AvailabilityCallback)} to clean up after a
+ * subscription is removed.
+ * <p>
+ * When the callback is registered, it will initiate the callback c to be called with the
+ * current capabilities.
+ *
+ * @param executor The executor the callback events should be run on.
+ * @param c The RCS {@link AvailabilityCallback} to be registered.
+ * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+ * @throws ImsException if the subscription associated with this instance of
+ * {@link ImsRcsManager} is valid, but the ImsService associated with the subscription is not
+ * available. This can happen if the ImsService has crashed, for example, or if the subscription
+ * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void registerRcsAvailabilityCallback(@CallbackExecutor Executor executor,
+ @NonNull AvailabilityCallback c) throws ImsException {
+ if (c == null) {
+ throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException("Must include a non-null Executor.");
+ }
+ c.setExecutor(executor);
+ throw new UnsupportedOperationException("registerRcsAvailabilityCallback is not"
+ + "supported.");
+ }
+
+ /**
+ * Removes an existing RCS {@link AvailabilityCallback}.
+ * <p>
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be unregistered. If this method is called for an
+ * inactive subscription, it will result in a no-op.
+ * @param c The RCS {@link AvailabilityCallback} to be removed.
+ * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void unregisterRcsAvailabilityCallback(@NonNull AvailabilityCallback c) {
+ if (c == null) {
+ throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+ }
+ throw new UnsupportedOperationException("unregisterRcsAvailabilityCallback is not"
+ + "supported.");
+ }
+
+ /**
+ * Query for the capability of an IMS RCS service provided by the framework.
+ * <p>
+ * This only reports the status of RCS capabilities provided by the framework, not necessarily
+ * RCS capabilities provided over-the-top by applications.
+ *
+ * @param capability The RCS capability to query.
+ * @return true if the RCS capability is capable for this subscription, false otherwise. This
+ * does not necessarily mean that we are registered for IMS and the capability is available, but
+ * rather the subscription is capable of this service over IMS.
+ * @see #isAvailable(int)
+ * @see android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isCapable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+ throw new UnsupportedOperationException("isCapable is not supported.");
+ }
+
+ /**
+ * Query the availability of an IMS RCS capability.
+ * <p>
+ * This only reports the status of RCS capabilities provided by the framework, not necessarily
+ * RCS capabilities provided by over-the-top by applications.
+ *
+ * @param capability the RCS capability to query.
+ * @return true if the RCS capability is currently available for the associated subscription,
+ * false otherwise. If the capability is available, IMS is registered and the service is
+ * currently available over IMS.
+ * @see #isCapable(int)
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isAvailable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+ throw new UnsupportedOperationException("isAvailable is not supported.");
+ }
+
+ /**
+ * @return A new {@link RcsUceAdapter} used for User Capability Exchange (UCE) operations for
+ * this subscription.
+ */
+ @NonNull
+ public RcsUceAdapter getUceAdapter() {
+ return new RcsUceAdapter(mSubId);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index cc037e3ea814..effdf48067c3 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -387,6 +387,24 @@ public class ProvisioningManager {
}
}
+ /**
+ * Notify the framework that an RCS autoconfiguration XML file has been received for
+ * provisioning.
+ * @param config The XML file to be read. ASCII/UTF8 encoded text if not compressed.
+ * @param isCompressed The XML file is compressed in gzip format and must be decompressed
+ * before being read.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void notifyRcsAutoConfigurationReceived(@NonNull byte[] config, boolean isCompressed) {
+ if (config == null) {
+ throw new IllegalArgumentException("Must include a non-null config XML file.");
+ }
+ // TODO: Connect to ImsConfigImplBase.
+ throw new UnsupportedOperationException("notifyRcsAutoConfigurationReceived is not"
+ + "supported");
+ }
+
private static boolean isImsAvailableOnDevice() {
IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
if (pm == null) {
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.aidl
index f04360fc1942..bef6a4037fea 100644
--- a/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (c) 2018 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.
@@ -14,16 +14,7 @@
* limitations under the License.
*/
-package com.android.preload.classdataretrieval;
-import com.android.ddmlib.Client;
+package android.telephony.ims;
-import java.util.Map;
-
-/**
- * Retrieve a class-to-classloader map for loaded classes from the client.
- */
-public interface ClassDataRetriever {
-
- public Map<String, String> getClassData(Client client);
-}
+parcelable RcsContactUceCapability;
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
new file mode 100644
index 000000000000..492170b1069a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.ims;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Contains the User Capability Exchange capabilities corresponding to a contact's URI.
+ * @hide
+ */
+public final class RcsContactUceCapability implements Parcelable {
+
+ /** Supports 1-to-1 chat */
+ public static final int CAPABILITY_CHAT_STANDALONE = (1 << 0);
+ /** Supports group chat */
+ public static final int CAPABILITY_CHAT_SESSION = (1 << 1);
+ /** Supports full store and forward group chat information. */
+ public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = (1 << 2);
+ /**
+ * Supports file transfer via Message Session Relay Protocol (MSRP) without Store and Forward.
+ */
+ public static final int CAPABILITY_FILE_TRANSFER = (1 << 3);
+ /** Supports File Transfer Thumbnail */
+ public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = (1 << 4);
+ /** Supports File Transfer with Store and Forward */
+ public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = (1 << 5);
+ /** Supports File Transfer via HTTP */
+ public static final int CAPABILITY_FILE_TRANSFER_HTTP = (1 << 6);
+ /** Supports file transfer via SMS */
+ public static final int CAPABILITY_FILE_TRANSFER_SMS = (1 << 7);
+ /** Supports image sharing */
+ public static final int CAPABILITY_IMAGE_SHARE = (1 << 8);
+ /** Supports video sharing during a circuit-switch call (IR.74)*/
+ public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = (1 << 9);
+ /** Supports video share outside of voice call (IR.84) */
+ public static final int CAPABILITY_VIDEO_SHARE = (1 << 10);
+ /** Supports social presence information */
+ public static final int CAPABILITY_SOCIAL_PRESENCE = (1 << 11);
+ /** Supports capability discovery via presence */
+ public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = (1 << 12);
+ /** Supports IP Voice calling over LTE or IWLAN (IR.92/IR.51) */
+ public static final int CAPABILITY_IP_VOICE_CALL = (1 << 13);
+ /** Supports IP video calling (IR.94) */
+ public static final int CAPABILITY_IP_VIDEO_CALL = (1 << 14);
+ /** Supports Geolocation PUSH during 1-to-1 or multiparty chat */
+ public static final int CAPABILITY_GEOLOCATION_PUSH = (1 << 15);
+ /** Supports Geolocation PUSH via SMS for fallback. */
+ public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = (1 << 16);
+ /** Supports Geolocation pull. */
+ public static final int CAPABILITY_GEOLOCATION_PULL = (1 << 17);
+ /** Supports Geolocation pull using file transfer support. */
+ public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = (1 << 18);
+ /** Supports RCS voice calling */
+ public static final int CAPABILITY_RCS_VOICE_CALL = (1 << 19);
+ /** Supports RCS video calling */
+ public static final int CAPABILITY_RCS_VIDEO_CALL = (1 << 20);
+ /** Supports RCS video calling, where video media can not be dropped */
+ public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = (1 << 21);
+
+ /** @hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "CAPABILITY_", flag = true, value = {
+ CAPABILITY_CHAT_STANDALONE,
+ CAPABILITY_CHAT_SESSION,
+ CAPABILITY_CHAT_SESSION_STORE_FORWARD,
+ CAPABILITY_FILE_TRANSFER,
+ CAPABILITY_FILE_TRANSFER_THUMBNAIL,
+ CAPABILITY_FILE_TRANSFER_STORE_FORWARD,
+ CAPABILITY_FILE_TRANSFER_HTTP,
+ CAPABILITY_FILE_TRANSFER_SMS,
+ CAPABILITY_IMAGE_SHARE,
+ CAPABILITY_VIDEO_SHARE_DURING_CS_CALL,
+ CAPABILITY_VIDEO_SHARE,
+ CAPABILITY_SOCIAL_PRESENCE,
+ CAPABILITY_DISCOVERY_VIA_PRESENCE,
+ CAPABILITY_IP_VOICE_CALL,
+ CAPABILITY_IP_VIDEO_CALL,
+ CAPABILITY_GEOLOCATION_PUSH,
+ CAPABILITY_GEOLOCATION_PUSH_SMS,
+ CAPABILITY_GEOLOCATION_PULL,
+ CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER,
+ CAPABILITY_RCS_VOICE_CALL,
+ CAPABILITY_RCS_VIDEO_CALL,
+ CAPABILITY_RCS_VIDEO_ONLY_CALL
+ })
+ public @interface CapabilityFlag {}
+
+ /**
+ * Builder to help construct {@link RcsContactUceCapability} instances.
+ */
+ public static class Builder {
+
+ private final RcsContactUceCapability mCapabilities;
+
+ /**
+ * Create the Builder, which can be used to set UCE capabilities as well as custom
+ * capability extensions.
+ * @param contact The contact URI that the capabilities are attached to.
+ */
+ public Builder(@NonNull Uri contact) {
+ mCapabilities = new RcsContactUceCapability(contact);
+ }
+
+ /**
+ * Add a UCE capability bit-field as well as the associated URI that the framework should
+ * use for those services. This is mainly used for capabilities that may use a URI separate
+ * from the contact's URI, for example the URI to use for VT calls.
+ * @param type The capability to map to a service URI that is different from the contact's
+ * URI.
+ */
+ public Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) {
+ mCapabilities.mCapabilities |= type;
+ // Put each of these capabilities into the map separately.
+ for (int shift = 0; shift < Integer.SIZE; shift++) {
+ int cap = type & (1 << shift);
+ if (cap != 0) {
+ mCapabilities.mServiceMap.put(cap, serviceUri);
+ // remove that capability from the field.
+ type &= ~cap;
+ }
+ if (type == 0) {
+ // no need to keep going, end early.
+ break;
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Add a UCE capability flag that this contact supports.
+ * @param type the capability that the contact supports.
+ */
+ public Builder add(@CapabilityFlag int type) {
+ mCapabilities.mCapabilities |= type;
+ return this;
+ }
+
+ /**
+ * Add a carrier specific service tag.
+ * @param extension A string containing a carrier specific service tag that is an extension
+ * of the {@link CapabilityFlag}s that are defined here.
+ */
+ public Builder add(@NonNull String extension) {
+ mCapabilities.mExtensionTags.add(extension);
+ return this;
+ }
+
+ /**
+ * @return the constructed instance.
+ */
+ public RcsContactUceCapability build() {
+ return mCapabilities;
+ }
+ }
+
+ private final Uri mContactUri;
+ private int mCapabilities;
+ private List<String> mExtensionTags = new ArrayList<>();
+ private Map<Integer, Uri> mServiceMap = new HashMap<>();
+
+ /**
+ * Use {@link Builder} to build an instance of this interface.
+ * @param contact The URI associated with this capability information.
+ * @hide
+ */
+ RcsContactUceCapability(@NonNull Uri contact) {
+ mContactUri = contact;
+ }
+
+ private RcsContactUceCapability(Parcel in) {
+ mContactUri = in.readParcelable(Uri.class.getClassLoader());
+ mCapabilities = in.readInt();
+ in.readStringList(mExtensionTags);
+ // read mServiceMap as key,value pair
+ int mapSize = in.readInt();
+ for (int i = 0; i < mapSize; i++) {
+ mServiceMap.put(in.readInt(), in.readParcelable(Uri.class.getClassLoader()));
+ }
+ }
+
+ public static final Creator<RcsContactUceCapability> CREATOR =
+ new Creator<RcsContactUceCapability>() {
+ @Override
+ public RcsContactUceCapability createFromParcel(Parcel in) {
+ return new RcsContactUceCapability(in);
+ }
+
+ @Override
+ public RcsContactUceCapability[] newArray(int size) {
+ return new RcsContactUceCapability[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(mContactUri, 0);
+ out.writeInt(mCapabilities);
+ out.writeStringList(mExtensionTags);
+ // write mServiceMap as key,value pairs
+ int mapSize = mServiceMap.keySet().size();
+ out.writeInt(mapSize);
+ for (int key : mServiceMap.keySet()) {
+ out.writeInt(key);
+ out.writeParcelable(mServiceMap.get(key), 0);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Query for a capability
+ * @param type The capability flag to query.
+ * @return true if the capability flag specified is set, false otherwise.
+ */
+ public boolean isCapable(@CapabilityFlag int type) {
+ return (mCapabilities & type) > 0;
+ }
+
+ /**
+ * @return true if the extension service tag is set, false otherwise.
+ */
+ public boolean isCapable(@NonNull String extensionTag) {
+ return mExtensionTags.contains(extensionTag);
+ }
+
+ /**
+ * @return An immutable list containing all of the extension tags that have been set as capable.
+ * @throws UnsupportedOperationException if this list is modified.
+ */
+ public @NonNull List<String> getCapableExtensionTags() {
+ return Collections.unmodifiableList(mExtensionTags);
+ }
+
+ /**
+ * Retrieves the {@link Uri} associated with the capability being queried.
+ * <p>
+ * This will typically be the contact {@link Uri} available via {@link #getContactUri()} unless
+ * a different service {@link Uri} was associated with this capability using
+ * {@link Builder#add(int, Uri)}.
+ *
+ * @return a String containing the {@link Uri} associated with the service tag or
+ * {@code null} if this capability is not set as capable.
+ * @see #isCapable(int)
+ */
+ public @Nullable Uri getServiceUri(@CapabilityFlag int type) {
+ Uri result = mServiceMap.getOrDefault(type, null);
+ // If the capability is capable, but does not have a service URI associated, use the default
+ // contact URI.
+ if (result == null) {
+ return isCapable(type) ? getContactUri() : null;
+ }
+ return result;
+ }
+
+ /**
+ * @return the URI representing the contact associated with the capabilities.
+ */
+ public @NonNull Uri getContactUri() {
+ return mContactUri;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
new file mode 100644
index 000000000000..a6a7a84c2c65
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.ims;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.net.Uri;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Manages RCS User Capability Exchange for the subscription specified.
+ *
+ * @see ImsRcsManager#getUceAdapter() for information on creating an instance of this class.
+ * @hide
+ */
+public class RcsUceAdapter {
+
+ /**
+ * An unknown error has caused the request to fail.
+ */
+ public static final int ERROR_GENERIC_FAILURE = 1;
+ /**
+ * The carrier network does not have UCE support enabled for this subscriber.
+ */
+ public static final int ERROR_NOT_ENABLED = 2;
+ /**
+ * The data network that the device is connected to does not support UCE currently (e.g. it is
+ * 1x only currently).
+ */
+ public static final int ERROR_NOT_AVAILABLE = 3;
+ /**
+ * The network has responded with SIP 403 error and a reason "User not registered."
+ */
+ public static final int ERROR_NOT_REGISTERED = 4;
+ /**
+ * The network has responded to this request with a SIP 403 error and reason "not authorized for
+ * presence" for this subscriber.
+ */
+ public static final int ERROR_NOT_AUTHORIZED = 5;
+ /**
+ * The network has responded to this request with a SIP 403 error and no reason.
+ */
+ public static final int ERROR_FORBIDDEN = 6;
+ /**
+ * The contact URI requested is not provisioned for VoLTE or it is not known as an IMS
+ * subscriber to the carrier network.
+ */
+ public static final int ERROR_NOT_FOUND = 7;
+ /**
+ * The capabilities request contained too many URIs for the carrier network to handle. Retry
+ * with a lower number of contact numbers. The number varies per carrier.
+ */
+ // TODO: Try to integrate this into the API so that the service will split based on carrier.
+ public static final int ERROR_REQUEST_TOO_LARGE = 8;
+ /**
+ * The network did not respond to the capabilities request before the request timed out.
+ */
+ public static final int ERROR_REQUEST_TIMEOUT = 10;
+ /**
+ * The request failed due to the service having insufficient memory.
+ */
+ public static final int ERROR_INSUFFICIENT_MEMORY = 11;
+ /**
+ * The network was lost while trying to complete the request.
+ */
+ public static final int ERROR_LOST_NETWORK = 12;
+ /**
+ * The request has failed because the same request has already been added to the queue.
+ */
+ public static final int ERROR_ALREADY_IN_QUEUE = 13;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "ERROR_", value = {
+ ERROR_GENERIC_FAILURE,
+ ERROR_NOT_ENABLED,
+ ERROR_NOT_AVAILABLE,
+ ERROR_NOT_REGISTERED,
+ ERROR_NOT_AUTHORIZED,
+ ERROR_FORBIDDEN,
+ ERROR_NOT_FOUND,
+ ERROR_REQUEST_TOO_LARGE,
+ ERROR_REQUEST_TIMEOUT,
+ ERROR_INSUFFICIENT_MEMORY,
+ ERROR_LOST_NETWORK,
+ ERROR_ALREADY_IN_QUEUE
+ })
+ public @interface ErrorCode {}
+
+ /**
+ * The last publish has resulted in a "200 OK" response or the device is using SIP OPTIONS for
+ * UCE.
+ */
+ public static final int PUBLISH_STATE_200_OK = 1;
+
+ /**
+ * The hasn't published its capabilities since boot or hasn't gotten any publish response yet.
+ */
+ public static final int PUBLISH_STATE_NOT_PUBLISHED = 2;
+
+ /**
+ * The device has tried to publish its capabilities, which has resulted in an error. This error
+ * is related to the fact that the device is not VoLTE provisioned.
+ */
+ public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3;
+
+ /**
+ * The device has tried to publish its capabilities, which has resulted in an error. This error
+ * is related to the fact that the device is not RCS or UCE provisioned.
+ */
+ public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4;
+
+ /**
+ * The last publish resulted in a "408 Request Timeout" response.
+ */
+ public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5;
+
+ /**
+ * The last publish resulted in another unknown error, such as SIP 503 - "Service Unavailable"
+ * or SIP 423 - "Interval too short".
+ * <p>
+ * Device shall retry with exponential back-off.
+ */
+ public static final int PUBLISH_STATE_OTHER_ERROR = 6;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "PUBLISH_STATE_", value = {
+ PUBLISH_STATE_200_OK,
+ PUBLISH_STATE_NOT_PUBLISHED,
+ PUBLISH_STATE_VOLTE_PROVISION_ERROR,
+ PUBLISH_STATE_RCS_PROVISION_ERROR,
+ PUBLISH_STATE_REQUEST_TIMEOUT,
+ PUBLISH_STATE_OTHER_ERROR
+ })
+ public @interface PublishState {}
+
+
+ /**
+ * Provides a one-time callback for the response to a UCE request. After this callback is called
+ * by the framework, the reference to this callback will be discarded on the service side.
+ * @see #requestCapabilities(Executor, List, CapabilitiesCallback)
+ */
+ public static class CapabilitiesCallback {
+
+ /**
+ * Notify this application that the pending capability request has returned successfully.
+ * @param contactCapabilities List of capabilities associated with each contact requested.
+ */
+ public void onCapabilitiesReceived(
+ @NonNull List<RcsContactUceCapability> contactCapabilities) {
+
+ }
+
+ /**
+ * The pending request has resulted in an error and may need to be retried, depending on the
+ * error code.
+ * @param errorCode The reason for the framework being unable to process the request.
+ */
+ public void onError(@ErrorCode int errorCode) {
+
+ }
+ }
+
+ private final int mSubId;
+
+ /**
+ * Not to be instantiated directly, use
+ * {@link ImsRcsManager#createForSubscriptionId(Context, int)} and
+ * {@link ImsRcsManager#getUceAdapter()} to instantiate this manager class.
+ */
+ RcsUceAdapter(int subId) {
+ mSubId = subId;
+ }
+
+ /**
+ * Request the User Capability Exchange capabilities for one or more contacts.
+ * <p>
+ * Be sure to check the availability of this feature using
+ * {@link ImsRcsManager#isAvailable(int)} and ensuring
+ * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or
+ * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else
+ * this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
+ *
+ * @param executor The executor that will be used when the request is completed and the
+ * {@link CapabilitiesCallback} is called.
+ * @param contactNumbers A list of numbers that the capabilities are being requested for.
+ * @param c A one-time callback for when the request for capabilities completes or there is an
+ * error processing the request.
+ * @throws ImsException if the subscription associated with this instance of
+ * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+ * available. This can happen if the ImsService has crashed, for example, or if the subscription
+ * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void requestCapabilities(@CallbackExecutor Executor executor,
+ @NonNull List<Uri> contactNumbers,
+ @NonNull CapabilitiesCallback c) throws ImsException {
+ throw new UnsupportedOperationException("isUceSettingEnabled is not supported.");
+ }
+
+ /**
+ * Gets the last publish result from the UCE service if the device is using an RCS presence
+ * server.
+ * @return The last publish result from the UCE service. If the device is using SIP OPTIONS,
+ * this method will return {@link #PUBLISH_STATE_200_OK} as well.
+ * @throws ImsException if the subscription associated with this instance of
+ * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+ * available. This can happen if the ImsService has crashed, for example, or if the subscription
+ * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @PublishState int getUcePublishState() throws ImsException {
+ throw new UnsupportedOperationException("getPublishState is not supported.");
+ }
+
+ /**
+ * The user’s setting for whether or not Presence and User Capability Exchange (UCE) is enabled
+ * for the associated subscription.
+ *
+ * @return true if the user’s setting for UCE is enabled, false otherwise. If false,
+ * {@link ImsRcsManager#isCapable(int)} will return false for
+ * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} and
+ * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE}
+ * @see #setUceSettingEnabled(boolean)
+ * @throws ImsException if the subscription associated with this instance of
+ * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+ * available. This can happen if the ImsService has crashed, for example, or if the subscription
+ * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isUceSettingEnabled() throws ImsException {
+ // TODO: add SubscriptionController column for this property.
+ throw new UnsupportedOperationException("isUceSettingEnabled is not supported.");
+ }
+ /**
+ * Change the user’s setting for whether or not UCE is enabled for the associated subscription.
+ * @param isEnabled the user's setting for whether or not they wish for Presence and User
+ * Capability Exchange to be enabled. If false,
+ * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} and
+ * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} capability will be
+ * disabled, depending on which type of UCE the carrier supports.
+ * @see #isUceSettingEnabled()
+ * @throws ImsException if the subscription associated with this instance of
+ * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+ * available. This can happen if the ImsService has crashed, for example, or if the subscription
+ * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setUceSettingEnabled(boolean isEnabled) throws ImsException {
+ // TODO: add SubscriptionController column for this property.
+ throw new UnsupportedOperationException("setUceSettingEnabled is not supported.");
+ }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
index 4433c1c03c1f..53e459697958 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
@@ -17,6 +17,8 @@
package android.telephony.ims.aidl;
+import android.os.PersistableBundle;
+
import android.telephony.ims.aidl.IImsConfigCallback;
import com.android.ims.ImsConfigListener;
@@ -37,4 +39,5 @@ interface IImsConfig {
int setConfigInt(int item, int value);
// Return result code defined in ImsConfig#OperationStatusConstants
int setConfigString(int item, String value);
+ void updateImsCarrierConfigs(in PersistableBundle bundle);
}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index a637e16d0a48..5fae3eebbfc6 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -16,8 +16,14 @@
package android.telephony.ims.feature;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.telephony.ims.aidl.IImsRcsFeature;
+import android.telephony.ims.stub.RcsPresenceExchangeImplBase;
+import android.telephony.ims.stub.RcsSipOptionsImplBase;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
@@ -32,18 +38,165 @@ public class RcsFeature extends ImsFeature {
// Empty Default Implementation.
};
+ /**
+ * Contains the capabilities defined and supported by a {@link RcsFeature} in the
+ * form of a bitmask. The capabilities that are used in the RcsFeature are
+ * defined as:
+ * {@link RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE}
+ * {@link RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE}
+ *
+ * The enabled capabilities of this RcsFeature will be set by the framework
+ * using {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}.
+ * After the capabilities have been set, the RcsFeature may then perform the necessary bring up
+ * of the capability and notify the capability status as true using
+ * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the
+ * framework that the capability is available for usage.
+ * @hide
+ */
+ public static class RcsImsCapabilities extends Capabilities {
+ /** @hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = {
+ CAPABILITY_TYPE_OPTIONS_UCE,
+ CAPABILITY_TYPE_PRESENCE_UCE
+ })
+ public @interface RcsImsCapabilityFlag {}
- public RcsFeature() {
- super();
+ /**
+ * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the
+ * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS.
+ * If not set, this RcsFeature should not service capability requests.
+ * @hide
+ */
+ public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1 << 0;
+
+ /**
+ * This carrier supports User Capability Exchange using a presence server as defined by the
+ * framework. If set, the RcsFeature should support capability exchange using a presence
+ * server. If not set, this RcsFeature should not publish capabilities or service capability
+ * requests using presence.
+ * @hide
+ */
+ public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
+
+ /**@hide*/
+ public RcsImsCapabilities(@RcsImsCapabilityFlag int capabilities) {
+
+ }
+
+ /**@hide*/
+ @Override
+ public void addCapabilities(@RcsImsCapabilityFlag int capabilities) {
+
+ }
+
+ /**@hide*/
+ @Override
+ public void removeCapabilities(@RcsImsCapabilityFlag int capabilities) {
+
+ }
+
+ /**@hide*/
+ @Override
+ public boolean isCapable(@RcsImsCapabilityFlag int capabilities) {
+ return false;
+ }
+ }
+ /**
+ * Query the current {@link RcsImsCapabilities} status set by the RcsFeature. If a capability is
+ * set, the {@link RcsFeature} has brought up the capability and is ready for framework
+ * requests. To change the status of the capabilities
+ * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)} should be called.
+ * @hide
+ */
+ @Override
+ public final RcsImsCapabilities queryCapabilityStatus() {
+ throw new UnsupportedOperationException();
}
/**
- * {@inheritDoc}
+ * Notify the framework that the capabilities status has changed. If a capability is enabled,
+ * this signals to the framework that the capability has been initialized and is ready.
+ * Call {@link #queryCapabilityStatus()} to return the current capability status.
+ * @hide
+ */
+ public final void notifyCapabilitiesStatusChanged(RcsImsCapabilities c) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Provides the RcsFeature with the ability to return the framework capability configuration set
+ * by the framework. When the framework calls
+ * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} to
+ * enable or disable capability A, this method should return the correct configuration for
+ * capability A afterwards (until it has changed).
+ * @hide
+ */
+ public boolean queryCapabilityConfiguration(
+ @RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+ throw new UnsupportedOperationException();
+ }
+ /**
+ * Called from the framework when the {@link RcsImsCapabilities} that have been configured for
+ * this {@link RcsFeature} has changed.
+ * <p>
+ * For each newly enabled capability flag, the corresponding capability should be brought up in
+ * the {@link RcsFeature} and registered on the network. For each newly disabled capability
+ * flag, the corresponding capability should be brought down, and deregistered. Once a new
+ * capability has been initialized and is ready for usage, the status of that capability should
+ * also be set to true using {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This
+ * will notify the framework that the capability is ready.
+ * <p>
+ * If for some reason one or more of these capabilities can not be enabled/disabled,
+ * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError(int, int, int)} should
+ * be called for each capability change that resulted in an error.
+ * @hide
*/
@Override
public void changeEnabledCapabilities(CapabilityChangeRequest request,
CapabilityCallbackProxy c) {
- // Do nothing for base implementation.
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Retrieve the implementation of SIP OPTIONS for this {@link RcsFeature}.
+ * <p>
+ * Will only be requested by the framework if capability exchange via SIP OPTIONS is
+ * configured as capable during a
+ * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}
+ * operation and the RcsFeature sets the status of the capability to true using
+ * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}.
+ *
+ * @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if
+ * it is supported by the device.
+ * @hide
+ */
+ public RcsSipOptionsImplBase getOptionsExchangeImpl() {
+ // Base Implementation, override to implement functionality
+ return new RcsSipOptionsImplBase();
+ }
+
+ /**
+ * Retrieve the implementation of UCE presence for this {@link RcsFeature}.
+ * Will only be requested by the framework if presence exchang is configured as capable during
+ * a {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}
+ * operation and the RcsFeature sets the status of the capability to true using
+ * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}.
+ *
+ * @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence
+ * exchange if it is supported by the device.
+ * @hide
+ */
+ public RcsPresenceExchangeImplBase getPresenceExchangeImpl() {
+ // Base Implementation, override to implement functionality.
+ return new RcsPresenceExchangeImplBase();
+ }
+
+ /**
+ * Construct a new {@link RcsFeature} instance.
+ */
+ public RcsFeature() {
+ super();
}
/**{@inheritDoc}*/
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 321bfff40652..3e135cc9f048 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -19,6 +19,7 @@ package android.telephony.ims.stub;
import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.content.Context;
+import android.os.PersistableBundle;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.telephony.ims.aidl.IImsConfig;
@@ -182,6 +183,11 @@ public class ImsConfigImplBase {
return retVal;
}
+ @Override
+ public void updateImsCarrierConfigs(PersistableBundle bundle) throws RemoteException {
+ getImsConfigImpl().updateImsCarrierConfigs(bundle);
+ }
+
private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
ImsConfigImplBase ref = mImsConfigImplBaseWeakReference.get();
if (ref == null) {
@@ -342,6 +348,17 @@ public class ImsConfigImplBase {
}
/**
+ * The framework has received an RCS autoconfiguration XML file for provisioning.
+ *
+ * @param config The XML file to be read, if not compressed, it should be in ASCII/UTF8 format.
+ * @param isCompressed The XML file is compressed in gzip format and must be decompressed
+ * before being read.
+ * @hide
+ */
+ public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) {
+ }
+
+ /**
* Sets the configuration value for this ImsService.
*
* @param item an integer key.
@@ -387,4 +404,11 @@ public class ImsConfigImplBase {
// Base Implementation - To be overridden.
return null;
}
+
+ /**
+ * @hide
+ */
+ public void updateImsCarrierConfigs(PersistableBundle bundle) {
+ // Base Implementation - Should be overridden
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
new file mode 100644
index 000000000000..289fd4c8a134
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.ims.stub;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Base class for different types of Capability exchange, presence using
+ * {@link RcsPresenceExchangeImplBase} and SIP OPTIONS exchange using {@link RcsSipOptionsImplBase}.
+ *
+ * @hide
+ */
+public class RcsCapabilityExchange {
+
+ /** Service is unknown. */
+ public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0;
+ /** The command completed successfully. */
+ public static final int COMMAND_CODE_SUCCESS = 1;
+ /** The command failed with an unknown error. */
+ public static final int COMMAND_CODE_GENERIC_FAILURE = 2;
+ /** Invalid parameter(s). */
+ public static final int COMMAND_CODE_INVALID_PARAM = 3;
+ /** Fetch error. */
+ public static final int COMMAND_CODE_FETCH_ERROR = 4;
+ /** Request timed out. */
+ public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5;
+ /** Failure due to insufficient memory available. */
+ public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6;
+ /** Network connection is lost. */
+ public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7;
+ /** Requested feature/resource is not supported. */
+ public static final int COMMAND_CODE_NOT_SUPPORTED = 8;
+ /** Contact or resource is not found. */
+ public static final int COMMAND_CODE_NOT_FOUND = 9;
+ /** Service is not available. */
+ public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10;
+ /** No Change in Capabilities */
+ public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11;
+
+ /** @hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "COMMAND_CODE_", value = {
+ COMMAND_CODE_SERVICE_UNKNOWN,
+ COMMAND_CODE_SUCCESS,
+ COMMAND_CODE_GENERIC_FAILURE,
+ COMMAND_CODE_INVALID_PARAM,
+ COMMAND_CODE_FETCH_ERROR,
+ COMMAND_CODE_REQUEST_TIMEOUT,
+ COMMAND_CODE_INSUFFICIENT_MEMORY,
+ COMMAND_CODE_LOST_NETWORK_CONNECTION,
+ COMMAND_CODE_NOT_SUPPORTED,
+ COMMAND_CODE_NOT_FOUND,
+ COMMAND_CODE_SERVICE_UNAVAILABLE,
+ COMMAND_CODE_NO_CHANGE_IN_CAP
+ })
+ public @interface CommandCode {}
+
+ /**
+ * Provides the framework with an update as to whether or not a command completed successfully
+ * locally. This includes capabilities requests and updates from the network. If it does not
+ * complete successfully, then the framework may retry the command again later, depending on the
+ * error. If the command does complete successfully, the framework will then wait for network
+ * updates.
+ *
+ * @param code The result of the pending command. If {@link #COMMAND_CODE_SUCCESS}, further
+ * updates will be sent for this command using the associated operationToken.
+ * @param operationToken the token associated with the pending command.
+ */
+ public final void onCommandUpdate(@CommandCode int code, int operationToken) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
new file mode 100644
index 000000000000..44024703042d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.ims.stub;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.net.Uri;
+import android.telephony.ims.RcsContactUceCapability;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * Base implementation for RCS User Capability Exchange using Presence. Any ImsService implementing
+ * this service must implement the stub methods {@link #requestCapabilities(List, int)} and
+ * {@link #updateCapabilities(RcsContactUceCapability, int)}.
+ *
+ * @hide
+ */
+public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
+
+ private static final String LOG_TAG = "RcsPresenceExchangeIB";
+
+ /**
+ * The request has resulted in any other 4xx/5xx/6xx that is not covered below. No retry will be
+ * attempted.
+ */
+ public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1;
+
+ /**
+ * The request has succeeded with a “200” message from the network.
+ */
+ public static final int RESPONSE_SUCCESS = 0;
+
+ /**
+ * The request has resulted in a “403” (User Not Registered) error from the network. Will retry
+ * capability polling with an exponential backoff.
+ */
+ public static final int RESPONSE_NOT_REGISTERED = 1;
+
+ /**
+ * The request has resulted in a “403” (not authorized (Requestor)) error from the network. No
+ * retry will be attempted.
+ */
+ public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2;
+
+ /**
+ * The request has resulted in a "403” (Forbidden) or other “403” error from the network and
+ * will be handled the same as “404” Not found. No retry will be attempted.
+ */
+ public static final int RESPONSE_FORBIDDEN = 3;
+
+ /**
+ * The request has resulted in a “404” (Not found) result from the network. No retry will be
+ * attempted.
+ */
+ public static final int RESPONSE_NOT_FOUND = 4;
+
+ /**
+ * The request has resulted in a “408” response. Retry after exponential backoff.
+ */
+ public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5;
+
+ /**
+ * The network has responded with a “413” (Too Large) response from the network. Capability
+ * request contains too many items and must be shrunk before the request will be accepted.
+ */
+ public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6;
+
+ /**
+ * The request has resulted in a “423” response. Retry after exponential backoff.
+ */
+ public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7;
+
+ /**
+ * The request has resulted in a “503” response. Retry after exponential backoff.
+ */
+ public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8;
+
+ /** @hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "RESPONSE_", value = {
+ RESPONSE_SUBSCRIBE_GENERIC_FAILURE,
+ RESPONSE_SUCCESS,
+ RESPONSE_NOT_REGISTERED,
+ RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE,
+ RESPONSE_FORBIDDEN,
+ RESPONSE_NOT_FOUND,
+ RESPONSE_SIP_REQUEST_TIMEOUT,
+ RESPONSE_SUBSCRIBE_TOO_LARGE,
+ RESPONSE_SIP_INTERVAL_TOO_SHORT,
+ RESPONSE_SIP_SERVICE_UNAVAILABLE
+ })
+ public @interface PresenceResponseCode {}
+
+ /**
+ * Provide the framework with a subsequent network response update to
+ * {@link #updateCapabilities(RcsContactUceCapability, int)} and
+ * {@link #requestCapabilities(List, int)} operations.
+ * @param code The SIP response code sent from the network for the operation token specified.
+ * @param reason The optional reason response from the network. If the network provided no
+ * reason with the code, the string should be empty.
+ * @param operationToken The token associated with the operation this service is providing a
+ * response for.
+ */
+ public final void onNetworkResponse(@PresenceResponseCode int code, @NonNull String reason,
+ int operationToken) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Provides the framework with the requested contacts’ capabilities requested by the framework
+ * using {@link #requestCapabilities(List, int)} .
+ */
+ public final void onCapabilityRequestResponse(@NonNull List<RcsContactUceCapability> infos,
+ int operationToken) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Trigger the framework to provide a capability update using
+ * {@link #updateCapabilities(RcsContactUceCapability, int)}. This is typically used when trying
+ * to generate an initial PUBLISH for a new subscription to the network.
+ * <p>
+ * The device will cache all presence publications after boot until this method is called once.
+ */
+ public final void onNotifyUpdateCapabilites() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Notify the framework that the device’s capabilities have been unpublished from the network.
+ */
+ public final void onUnpublish() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * The user capabilities of one or multiple contacts have been requested.
+ * <p>
+ * This must be followed up with one call to {@link #onCommandUpdate(int, int)} with an update
+ * as to whether or not the command completed as well as subsequent network
+ * updates using {@link #onNetworkResponse(int, String, int)}. When the operation is completed,
+ * {@link #onCapabilityRequestResponse(List, int)} should be called with
+ * the presence information for the contacts specified.
+ * @param uris A {@link List} of the URIs that the framework is requesting the UCE capabilities
+ * for.
+ * @param operationToken The token associated with this operation. Updates to this request using
+ * {@link #onCommandUpdate(int, int)}, {@link #onNetworkResponse(int, String, int)}, and
+ * {@link #onCapabilityRequestResponse(List, int)} must use the same operation token
+ * in response.
+ */
+ public void requestCapabilities(@NonNull List<Uri> uris, int operationToken) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "requestCapabilities called with no implementation.");
+ onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ }
+
+ /**
+ * The capabilities of this device have been updated and should be published
+ * to the network. The framework will expect one {@link #onCommandUpdate(int, int)} call to
+ * indicate whether or not this operation failed first as well as network response
+ * updates to this update using {@link #onNetworkResponse(int, String, int)}.
+ * @param capabilities The capabilities for this device.
+ * @param operationToken The token associated with this operation. Any subsequent
+ * {@link #onCommandUpdate(int, int)} or {@link #onNetworkResponse(int, String, int)}
+ * calls regarding this update must use the same token.
+ */
+ public void updateCapabilities(@NonNull RcsContactUceCapability capabilities,
+ int operationToken) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "updateCapabilities called with no implementation.");
+ onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
new file mode 100644
index 000000000000..3343074ea52c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.ims.stub;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.telephony.ims.RcsContactUceCapability;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Base implementation for RCS User Capability Exchange using SIP OPTIONS.
+ *
+ * @hide
+ */
+public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
+
+ private static final String LOG_TAG = "RcsSipOptionsImplBase";
+
+ /**
+ * Indicates a SIP response from the remote user other than 200, 480, 408, 404, or 604.
+ */
+ public static final int RESPONSE_GENERIC_FAILURE = -1;
+
+ /**
+ * Indicates that the remote user responded with a 200 OK response.
+ */
+ public static final int RESPONSE_SUCCESS = 0;
+
+ /**
+ * Indicates that the remote user responded with a 480 TEMPORARY UNAVAILABLE response.
+ */
+ public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1;
+
+ /**
+ * Indicates that the remote user responded with a 408 REQUEST TIMEOUT response.
+ */
+ public static final int RESPONSE_REQUEST_TIMEOUT = 2;
+
+ /**
+ * Indicates that the remote user responded with a 404 NOT FOUND response.
+ */
+ public static final int RESPONSE_NOT_FOUND = 3;
+
+ /**
+ * Indicates that the remote user responded with a 604 DOES NOT EXIST ANYWHERE response.
+ */
+ public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4;
+
+ /** @hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "RESPONSE_", value = {
+ RESPONSE_GENERIC_FAILURE,
+ RESPONSE_SUCCESS,
+ RESPONSE_TEMPORARILY_UNAVAILABLE,
+ RESPONSE_REQUEST_TIMEOUT,
+ RESPONSE_NOT_FOUND,
+ RESPONSE_DOES_NOT_EXIST_ANYWHERE
+ })
+ public @interface SipResponseCode {}
+
+ /**
+ * Send the response of a SIP OPTIONS capability exchange to the framework. If {@code code} is
+ * {@link #RESPONSE_SUCCESS}, info must be non-null.
+ * @param code The SIP response code that was sent by the network in response to the request
+ * sent by {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+ * @param reason The optional SIP response reason sent by the network. If none was sent, this
+ * should be an empty string.
+ * @param info the contact's UCE capabilities associated with the capability request.
+ * @param operationToken The token associated with the original capability request, set by
+ * {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+ */
+ public final void onCapabilityRequestResponse(@SipResponseCode int code, @NonNull String reason,
+ @Nullable RcsContactUceCapability info, int operationToken) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Inform the framework of a query for this device's UCE capabilities.
+ * <p>
+ * The framework will respond via the
+ * {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)} or
+ * {@link #respondToCapabilityRequestWithError(Uri, int, String, int)} method.
+ * @param contactUri The URI associated with the remote contact that is requesting capabilities.
+ * @param remoteInfo The remote contact's capability information.
+ * @param operationToken An unique operation token that you have generated that will be returned
+ * by the framework in
+ * {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)}.
+ */
+ public final void onRemoteCapabilityRequest(@NonNull Uri contactUri,
+ @NonNull RcsContactUceCapability remoteInfo, int operationToken) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
+ * in order to receive the capabilities of the remote user in response.
+ * <p>
+ * The implementer must call
+ * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} to send the
+ * response of this query back to the framework.
+ * @param contactUri The URI of the remote user that we wish to get the capabilities of.
+ * @param capabilities The capabilities of this device to send to the remote user.
+ * @param operationToken A token generated by the framework that will be passed through
+ * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} when this
+ * operation has succeeded.
+ */
+ public void sendCapabilityRequest(@NonNull Uri contactUri,
+ @NonNull RcsContactUceCapability capabilities, int operationToken) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "sendCapabilityRequest called with no implementation.");
+ onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ }
+
+ /**
+ * Respond to a remote capability request from the contact specified with the capabilities of
+ * this device.
+ * <p>
+ * The framework will use the same token and uri as what was passed in to
+ * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+ * @param contactUri The URI of the remote contact.
+ * @param ownCapabilities The capabilities of this device.
+ * @param operationToken The token generated by the framework that this service obtained when
+ * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
+ */
+ public void respondToCapabilityRequest(@NonNull String contactUri,
+ @NonNull RcsContactUceCapability ownCapabilities, int operationToken) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "respondToCapabilityRequest called with no implementation.");
+ onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ }
+
+ /**
+ * Respond to a remote capability request from the contact specified with the specified error.
+ * <p>
+ * The framework will use the same token and uri as what was passed in to
+ * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}.
+ * @param contactUri A URI containing the remote contact.
+ * @param code The SIP response code to respond with.
+ * @param reason A non-null String containing the reason associated with the SIP code.
+ * @param operationToken The token provided by the framework when
+ * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
+ *
+ */
+ public void respondToCapabilityRequestWithError(@NonNull Uri contactUri,
+ @SipResponseCode int code, @NonNull String reason, int operationToken) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "respondToCapabiltyRequestWithError called with no implementation.");
+ onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
+ }
+}
diff --git a/test-base/Android.mk b/test-base/Android.mk
deleted file mode 100644
index a9d30cf3131a..000000000000
--- a/test-base/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (C) 2016 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-ifeq ($(HOST_OS),linux)
-# Build the legacy-performance-test-hostdex library
-# =================================================
-# This contains the android.test.PerformanceTestCase class only
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := src/android/test/PerformanceTestCase.java
-LOCAL_MODULE := legacy-performance-test-hostdex
-
-include $(BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY)
-endif # HOST_OS == linux
diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh
index fe3adf9b2a70..bc1aae03e9a6 100755
--- a/tests/Codegen/runTest.sh
+++ b/tests/Codegen/runTest.sh
@@ -10,7 +10,7 @@ else
return $?
}
- header_and_eval m -j16 codegen && \
+ header_and_eval m -j16 codegen_cli && \
header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java && \
cd $ANDROID_BUILD_TOP &&
header_and_eval mmma -j16 frameworks/base/tests/Codegen && \
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index 03127ec2814b..f69a092ed3f7 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -339,8 +339,8 @@ public final class SampleDataClass implements Parcelable {
- // Code below generated by codegen v0.0.1.
- // on Jul 17, 2019, 5:10:26 PM PDT
+ // Code below generated by codegen v1.0.0.
+ // on Jul 29, 2019, 2:50:21 PM PDT
//
// DO NOT MODIFY!
//
@@ -409,8 +409,8 @@ public final class SampleDataClass implements Parcelable {
public @interface StateName {}
@DataClass.Generated(
- time = 1563408627046L,
- codegenVersion = "0.0.1",
+ time = 1564437021513L,
+ codegenVersion = "1.0.0",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.DateParcelling.class) java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) java.util.regex.Pattern mPattern\nprivate java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate boolean mActive\nprivate @com.android.codegentest.SampleDataClass.StateName java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic java.lang.CharSequence charSeq\nprivate final android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=4L) int mLimited\nprivate @android.annotation.Size(2L) @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)")
diff --git a/tests/JobSchedulerPerfTests/Android.bp b/tests/JobSchedulerPerfTests/Android.bp
index 22308076d4ff..c51b811f0735 100644
--- a/tests/JobSchedulerPerfTests/Android.bp
+++ b/tests/JobSchedulerPerfTests/Android.bp
@@ -19,6 +19,7 @@ android_test {
"androidx.test.rules",
"apct-perftests-utils",
"services",
+ "jobscheduler-service",
],
platform_apis: true,
certificate: "platform",
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 11150dd8e882..b725920ba014 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -386,6 +386,9 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
manifest_action["package-verifier"];
manifest_action["meta-data"] = meta_data_action;
manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
+ manifest_action["queries"]["package"].Action(RequiredNameIsJavaPackage);
+ manifest_action["queries"]["intent"] = intent_filter_action;
+ // TODO: more complicated component name tag
manifest_action["key-sets"]["key-set"]["public-key"];
manifest_action["key-sets"]["upgrade-key-set"];
diff --git a/tools/codegen/Android.bp b/tools/codegen/Android.bp
index 805b2968bca0..677bee2cce81 100644
--- a/tools/codegen/Android.bp
+++ b/tools/codegen/Android.bp
@@ -1,5 +1,5 @@
java_binary_host {
- name: "codegen",
+ name: "codegen_cli",
manifest: "manifest.txt",
srcs: [
"src/**/*.kt",
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 41641f6dab47..175eea6ef0d0 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,4 +1,4 @@
package com.android.codegen
const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "0.0.1" \ No newline at end of file
+const val CODEGEN_VERSION = "1.0.0" \ No newline at end of file
diff --git a/tools/dump-coverage/README.md b/tools/dump-coverage/README.md
index 2bab4bc8c984..d1c10bc2e520 100644
--- a/tools/dump-coverage/README.md
+++ b/tools/dump-coverage/README.md
@@ -16,7 +16,7 @@ adb shell 'mkdir /data/data/com.android.deskclock/folder-to-use'
Then we can run the command to dump the data:
```
-adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so=dump:/data/data/com.android.deskclock/folder-to-use'
+adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so=dump:/data/data/com.android.deskclock/folder-to-use/coverage-file.ec'
```
We can also reset the coverage information with
@@ -28,10 +28,10 @@ adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so=
then perform more actions, then dump the data again. To get the files, we can get
```
-adb pull /data/data/com.android.deskclock/folder-to-use ~/path-on-your-computer
+adb pull /data/data/com.android.deskclock/folder-to-use/coverage-file.ec ~/path-on-your-computer
```
-And you should have timestamped `.exec` files on your machine under the folder `~/path-on-your-computer`
+And you should have `coverage-file.ec` on your machine under the folder `~/path-on-your-computer`
# Details
diff --git a/tools/dump-coverage/dump_coverage.cc b/tools/dump-coverage/dump_coverage.cc
index 3de1865b8018..0808e776f190 100644
--- a/tools/dump-coverage/dump_coverage.cc
+++ b/tools/dump-coverage/dump_coverage.cc
@@ -18,20 +18,10 @@
#include <jvmti.h>
#include <string.h>
-#include <atomic>
-#include <ctime>
#include <fstream>
-#include <iomanip>
-#include <iostream>
-#include <istream>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <vector>
using std::get;
using std::tuple;
-using std::chrono::system_clock;
namespace dump_coverage {
@@ -87,35 +77,11 @@ static jbyteArray GetExecutionData(JNIEnv* env) {
return java_result_array;
}
-// Gets the filename to write execution data to
-// dirname: the directory in which to place the file
-// outputs <dirname>/YYYY-MM-DD-HH-MM-SS.SSS.exec
-static std::string GetFilename(const std::string& dirname) {
- system_clock::time_point time_point = system_clock::now();
- auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(time_point);
- auto fractional_time = time_point - seconds;
- auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(fractional_time);
-
- std::time_t time = system_clock::to_time_t(time_point);
- auto tm = *std::gmtime(&time);
-
- std::ostringstream oss;
- oss
- << dirname
- << "/"
- << std::put_time(&tm, "%Y-%m-%d-%H-%M-%S.")
- << std::setfill('0') << std::setw(3) << millis.count()
- << ".ec";
- return oss.str();
-}
-
-// Writes the execution data to a file
-// data, length: represent the data, as a sequence of bytes
-// dirname: directory name to contain the file
+// Writes the execution data to a file.
+// data, length: represent the data, as a sequence of bytes.
+// filename: file to write coverage data to.
// returns JNI_ERR if there is an error in writing the file, otherwise JNI_OK.
-static jint WriteFile(const char* data, int length, const std::string& dirname) {
- auto filename = GetFilename(dirname);
-
+static jint WriteFile(const char* data, int length, const std::string& filename) {
LOG(INFO) << "Writing file of length " << length << " to '" << filename
<< "'";
std::ofstream file(filename, std::ios::binary);
@@ -136,11 +102,11 @@ static jint WriteFile(const char* data, int length, const std::string& dirname)
return JNI_OK;
}
-// Grabs execution data and writes it to a file
-// dirname: directory name to contain the file
+// Grabs execution data and writes it to a file.
+// filename: file to write coverage data to.
// returns JNI_ERR if there is an error writing the file.
// Will crash if the Agent isn't found or if any Java Exception occurs.
-static jint Dump(const std::string& dirname) {
+static jint Dump(const std::string& filename) {
LOG(INFO) << "Dumping file";
JNIEnv* env = GetJNIEnv();
@@ -152,12 +118,12 @@ static jint Dump(const std::string& dirname) {
int result_len = env->GetArrayLength(java_result_array);
- return WriteFile((const char*) result_ptr, result_len, dirname);
+ return WriteFile((const char*) result_ptr, result_len, filename);
}
// Resets execution data, performing the equivalent of
// Agent.getInstance().reset();
-// args: should be empty
+// args: should be empty.
// returns JNI_ERR if the arguments are invalid.
// Will crash if the Agent isn't found or if any Java Exception occurs.
static jint Reset(const std::string& args) {
diff --git a/tools/preload2/Android.bp b/tools/preload2/Android.bp
deleted file mode 100644
index 5809421da3e8..000000000000
--- a/tools/preload2/Android.bp
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (C) 2015 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.
-
-java_library_host {
- name: "preload2",
-
- srcs: ["src/**/*.java"],
-
- // To connect to devices (and take hprof dumps).
- static_libs: [
- "ddmlib-prebuilt",
- "tools-common-prebuilt",
-
- // To process hprof dumps.
- "perflib-prebuilt",
-
- "trove-prebuilt",
- "guavalib",
-
- // For JDWP access we use the framework in the JDWP tests from Apache Harmony, for
- // convenience (and to not depend on internal JDK APIs).
- "apache-harmony-jdwp-tests",
- "junit",
- ],
-
- // Copy to build artifacts
- dist: {
- targets: [
- "dist_files",
- ],
- },
-}
-
-// Copy the preload-tool shell script to the host's bin directory.
-sh_binary_host {
- name: "preload-tool",
- src: "preload-tool",
- required: ["preload2"],
-}
diff --git a/tools/preload2/preload-tool b/tools/preload2/preload-tool
deleted file mode 100644
index 322b62fda071..000000000000
--- a/tools/preload2/preload-tool
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2015 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.
-
-# This script is used on the host only. It uses a common subset
-# shell dialect that should work well. It is partially derived
-# from art/tools/art.
-
-function follow_links() {
- if [ z"$BASH_SOURCE" != z ]; then
- file="$BASH_SOURCE"
- else
- file="$0"
- fi
- while [ -h "$file" ]; do
- # On Mac OS, readlink -f doesn't work.
- file="$(readlink "$file")"
- done
- echo "$file"
-}
-
-
-PROG_NAME="$(follow_links)"
-PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-ANDROID_ROOT=$PROG_DIR/..
-
-java -cp $ANDROID_ROOT/framework/preload2.jar com.android.preload.Main $@
diff --git a/tools/preload2/src/com/android/preload/ClientUtils.java b/tools/preload2/src/com/android/preload/ClientUtils.java
deleted file mode 100644
index 71ef025d6587..000000000000
--- a/tools/preload2/src/com/android/preload/ClientUtils.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import com.android.ddmlib.AndroidDebugBridge;
-import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-
-/**
- * Helper class for common communication with a Client (the ddms name for a running application).
- *
- * Instances take a default timeout parameter that's applied to all functions without explicit
- * timeout. Timeouts are in milliseconds.
- */
-public class ClientUtils {
-
- private int defaultTimeout;
-
- public ClientUtils() {
- this(10000);
- }
-
- public ClientUtils(int defaultTimeout) {
- this.defaultTimeout = defaultTimeout;
- }
-
- /**
- * Shortcut for findClient with default timeout.
- */
- public Client findClient(IDevice device, String processName, int processPid) {
- return findClient(device, processName, processPid, defaultTimeout);
- }
-
- /**
- * Find the client with the given process name or process id. The name takes precedence over
- * the process id (if valid). Stop looking after the given timeout.
- *
- * @param device The device to communicate with.
- * @param processName The name of the process. May be null.
- * @param processPid The pid of the process. Values less than or equal to zero are ignored.
- * @param timeout The amount of milliseconds to wait, at most.
- * @return The client, if found. Otherwise null.
- */
- public Client findClient(IDevice device, String processName, int processPid, int timeout) {
- WaitForClient wfc = new WaitForClient(device, processName, processPid, timeout);
- return wfc.get();
- }
-
- /**
- * Shortcut for findAllClients with default timeout.
- */
- public Client[] findAllClients(IDevice device) {
- return findAllClients(device, defaultTimeout);
- }
-
- /**
- * Retrieve all clients known to the given device. Wait at most the given timeout.
- *
- * @param device The device to investigate.
- * @param timeout The amount of milliseconds to wait, at most.
- * @return An array of clients running on the given device. May be null depending on the
- * device implementation.
- */
- public Client[] findAllClients(IDevice device, int timeout) {
- if (device.hasClients()) {
- return device.getClients();
- }
- WaitForClients wfc = new WaitForClients(device, timeout);
- return wfc.get();
- }
-
- private static class WaitForClient implements IClientChangeListener {
-
- private IDevice device;
- private String processName;
- private int processPid;
- private long timeout;
- private Client result;
-
- public WaitForClient(IDevice device, String processName, int processPid, long timeout) {
- this.device = device;
- this.processName = processName;
- this.processPid = processPid;
- this.timeout = timeout;
- this.result = null;
- }
-
- public Client get() {
- synchronized (this) {
- AndroidDebugBridge.addClientChangeListener(this);
-
- // Maybe it's already there.
- if (result == null) {
- result = searchForClient(device);
- }
-
- if (result == null) {
- try {
- wait(timeout);
- } catch (InterruptedException e) {
- // Note: doesn't guard for spurious wakeup.
- }
- }
- }
-
- AndroidDebugBridge.removeClientChangeListener(this);
- return result;
- }
-
- private Client searchForClient(IDevice device) {
- if (processName != null) {
- Client tmp = device.getClient(processName);
- if (tmp != null) {
- return tmp;
- }
- }
- if (processPid > 0) {
- String name = device.getClientName(processPid);
- if (name != null && !name.isEmpty()) {
- Client tmp = device.getClient(name);
- if (tmp != null) {
- return tmp;
- }
- }
- }
- if (processPid > 0) {
- // Try manual search.
- for (Client cl : device.getClients()) {
- if (cl.getClientData().getPid() == processPid
- && cl.getClientData().getClientDescription() != null) {
- return cl;
- }
- }
- }
- return null;
- }
-
- private boolean isTargetClient(Client c) {
- if (processPid > 0 && c.getClientData().getPid() == processPid) {
- return true;
- }
- if (processName != null
- && processName.equals(c.getClientData().getClientDescription())) {
- return true;
- }
- return false;
- }
-
- @Override
- public void clientChanged(Client arg0, int arg1) {
- synchronized (this) {
- if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) {
- if (isTargetClient(arg0)) {
- result = arg0;
- notifyAll();
- }
- }
- }
- }
- }
-
- private static class WaitForClients implements IClientChangeListener {
-
- private IDevice device;
- private long timeout;
-
- public WaitForClients(IDevice device, long timeout) {
- this.device = device;
- this.timeout = timeout;
- }
-
- public Client[] get() {
- synchronized (this) {
- AndroidDebugBridge.addClientChangeListener(this);
-
- if (device.hasClients()) {
- return device.getClients();
- }
-
- try {
- wait(timeout); // Note: doesn't guard for spurious wakeup.
- } catch (InterruptedException exc) {
- }
-
- // We will be woken up when the first client data arrives. Sleep a little longer
- // to give (hopefully all of) the rest of the clients a chance to become available.
- // Note: a loop with timeout is brittle as well and complicated, just accept this
- // for now.
- try {
- Thread.sleep(500);
- } catch (InterruptedException exc) {
- }
- }
-
- AndroidDebugBridge.removeClientChangeListener(this);
-
- return device.getClients();
- }
-
- @Override
- public void clientChanged(Client arg0, int arg1) {
- synchronized (this) {
- if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) {
- notifyAll();
- }
- }
- }
- }
-}
diff --git a/tools/preload2/src/com/android/preload/DeviceUtils.java b/tools/preload2/src/com/android/preload/DeviceUtils.java
deleted file mode 100644
index 18cab7bee12d..000000000000
--- a/tools/preload2/src/com/android/preload/DeviceUtils.java
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import com.android.ddmlib.AdbCommandRejectedException;
-import com.android.ddmlib.AndroidDebugBridge;
-import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
-import com.android.preload.classdataretrieval.hprof.Hprof;
-import com.android.ddmlib.DdmPreferences;
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.IShellOutputReceiver;
-import com.android.ddmlib.SyncException;
-import com.android.ddmlib.TimeoutException;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Date;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Helper class for some device routines.
- */
-public class DeviceUtils {
-
- // Locations
- private static final String PRELOADED_CLASSES_FILE = "/etc/preloaded-classes";
- // Shell commands
- private static final String CREATE_EMPTY_PRELOADED_CMD = "touch " + PRELOADED_CLASSES_FILE;
- private static final String DELETE_CACHE_CMD = "rm /data/dalvik-cache/*/*boot.art";
- private static final String DELETE_PRELOADED_CMD = "rm " + PRELOADED_CLASSES_FILE;
- private static final String READ_PRELOADED_CMD = "cat " + PRELOADED_CLASSES_FILE;
- private static final String START_SHELL_CMD = "start";
- private static final String STOP_SHELL_CMD = "stop";
- private static final String REMOUNT_SYSTEM_CMD = "mount -o rw,remount /system";
- private static final String UNSET_BOOTCOMPLETE_CMD = "setprop dev.bootcomplete \"0\"";
-
- public static void init(int debugPort) {
- DdmPreferences.setSelectedDebugPort(debugPort);
-
- Hprof.init();
-
- AndroidDebugBridge.init(true);
-
- AndroidDebugBridge.createBridge();
- }
-
- /**
- * Run a command in the shell on the device.
- */
- public static void doShell(IDevice device, String cmdline, long timeout, TimeUnit unit) {
- doShell(device, cmdline, new NullShellOutputReceiver(), timeout, unit);
- }
-
- /**
- * Run a command in the shell on the device. Collects and returns the console output.
- */
- public static String doShellReturnString(IDevice device, String cmdline, long timeout,
- TimeUnit unit) {
- CollectStringShellOutputReceiver rec = new CollectStringShellOutputReceiver();
- doShell(device, cmdline, rec, timeout, unit);
- return rec.toString();
- }
-
- /**
- * Run a command in the shell on the device, directing all output to the given receiver.
- */
- public static void doShell(IDevice device, String cmdline, IShellOutputReceiver receiver,
- long timeout, TimeUnit unit) {
- try {
- device.executeShellCommand(cmdline, receiver, timeout, unit);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Run am start on the device.
- */
- public static void doAMStart(IDevice device, String name, String activity) {
- doShell(device, "am start -n " + name + " /." + activity, 30, TimeUnit.SECONDS);
- }
-
- /**
- * Find the device with the given serial. Give up after the given timeout (in milliseconds).
- */
- public static IDevice findDevice(String serial, int timeout) {
- WaitForDevice wfd = new WaitForDevice(serial, timeout);
- return wfd.get();
- }
-
- /**
- * Get all devices ddms knows about. Wait at most for the given timeout.
- */
- public static IDevice[] findDevices(int timeout) {
- WaitForDevice wfd = new WaitForDevice(null, timeout);
- wfd.get();
- return AndroidDebugBridge.getBridge().getDevices();
- }
-
- /**
- * Return the build type of the given device. This is the value of the "ro.build.type"
- * system property.
- */
- public static String getBuildType(IDevice device) {
- try {
- Future<String> buildType = device.getSystemProperty("ro.build.type");
- return buildType.get(500, TimeUnit.MILLISECONDS);
- } catch (Exception e) {
- }
- return null;
- }
-
- /**
- * Check whether the given device has a pre-optimized boot image. More precisely, checks
- * whether /system/framework/ * /boot.art exists.
- */
- public static boolean hasPrebuiltBootImage(IDevice device) {
- String ret =
- doShellReturnString(device, "ls /system/framework/*/boot.art", 500, TimeUnit.MILLISECONDS);
-
- return !ret.contains("No such file or directory");
- }
-
- /**
- * Write over the preloaded-classes file with an empty or existing file and regenerate the boot
- * image as necessary.
- *
- * @param device
- * @param pcFile
- * @param bootTimeout
- * @throws AdbCommandRejectedException
- * @throws IOException
- * @throws TimeoutException
- * @throws SyncException
- * @return true if successfully overwritten, false otherwise
- */
- public static boolean overwritePreloaded(IDevice device, File pcFile, long bootTimeout)
- throws AdbCommandRejectedException, IOException, TimeoutException, SyncException {
- boolean writeEmpty = (pcFile == null);
- if (writeEmpty) {
- // Check if the preloaded-classes file is already empty.
- String oldContent =
- doShellReturnString(device, READ_PRELOADED_CMD, 1, TimeUnit.SECONDS);
- if (oldContent.trim().equals("")) {
- System.out.println("Preloaded-classes already empty.");
- return true;
- }
- }
-
- // Stop the system server etc.
- doShell(device, STOP_SHELL_CMD, 1, TimeUnit.SECONDS);
- // Remount the read-only system partition
- doShell(device, REMOUNT_SYSTEM_CMD, 1, TimeUnit.SECONDS);
- // Delete the preloaded-classes file
- doShell(device, DELETE_PRELOADED_CMD, 1, TimeUnit.SECONDS);
- // Delete the dalvik cache files
- doShell(device, DELETE_CACHE_CMD, 1, TimeUnit.SECONDS);
- if (writeEmpty) {
- // Write an empty preloaded-classes file
- doShell(device, CREATE_EMPTY_PRELOADED_CMD, 500, TimeUnit.MILLISECONDS);
- } else {
- // Push the new preloaded-classes file
- device.pushFile(pcFile.getAbsolutePath(), PRELOADED_CLASSES_FILE);
- }
- // Manually reset the boot complete flag
- doShell(device, UNSET_BOOTCOMPLETE_CMD, 1, TimeUnit.SECONDS);
- // Restart system server on the device
- doShell(device, START_SHELL_CMD, 1, TimeUnit.SECONDS);
- // Wait for the boot complete flag and return the outcome.
- return waitForBootComplete(device, bootTimeout);
- }
-
- private static boolean waitForBootComplete(IDevice device, long timeout) {
- // Do a loop checking each second whether bootcomplete. Wait for at most the given
- // threshold.
- Date startDate = new Date();
- for (;;) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // Ignore spurious wakeup.
- }
- // Check whether bootcomplete.
- String ret =
- doShellReturnString(device, "getprop dev.bootcomplete", 500, TimeUnit.MILLISECONDS);
- if (ret.trim().equals("1")) {
- break;
- }
- System.out.println("Still not booted: " + ret);
-
- // Check whether we timed out. This is a simplistic check that doesn't take into account
- // things like switches in time.
- Date endDate = new Date();
- long seconds =
- TimeUnit.SECONDS.convert(endDate.getTime() - startDate.getTime(), TimeUnit.MILLISECONDS);
- if (seconds > timeout) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Enable method-tracing on device. The system should be restarted after this.
- */
- public static void enableTracing(IDevice device) {
- // Disable selinux.
- doShell(device, "setenforce 0", 100, TimeUnit.MILLISECONDS);
-
- // Make the profile directory world-writable.
- doShell(device, "chmod 777 /data/dalvik-cache/profiles", 100, TimeUnit.MILLISECONDS);
-
- // Enable streaming method tracing with a small 1K buffer.
- doShell(device, "setprop dalvik.vm.method-trace true", 100, TimeUnit.MILLISECONDS);
- doShell(device, "setprop dalvik.vm.method-trace-file "
- + "/data/dalvik-cache/profiles/zygote.trace.bin", 100, TimeUnit.MILLISECONDS);
- doShell(device, "setprop dalvik.vm.method-trace-file-siz 1024", 100, TimeUnit.MILLISECONDS);
- doShell(device, "setprop dalvik.vm.method-trace-stream true", 100, TimeUnit.MILLISECONDS);
- }
-
- private static class NullShellOutputReceiver implements IShellOutputReceiver {
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- @Override
- public void flush() {}
-
- @Override
- public void addOutput(byte[] arg0, int arg1, int arg2) {}
- }
-
- private static class CollectStringShellOutputReceiver implements IShellOutputReceiver {
-
- private StringBuilder builder = new StringBuilder();
-
- @Override
- public String toString() {
- String ret = builder.toString();
- // Strip trailing newlines. They are especially ugly because adb uses DOS line endings.
- while (ret.endsWith("\r") || ret.endsWith("\n")) {
- ret = ret.substring(0, ret.length() - 1);
- }
- return ret;
- }
-
- @Override
- public void addOutput(byte[] arg0, int arg1, int arg2) {
- builder.append(new String(arg0, arg1, arg2));
- }
-
- @Override
- public void flush() {}
-
- @Override
- public boolean isCancelled() {
- return false;
- }
- }
-
- private static class WaitForDevice {
-
- private String serial;
- private long timeout;
- private IDevice device;
-
- public WaitForDevice(String serial, long timeout) {
- this.serial = serial;
- this.timeout = timeout;
- device = null;
- }
-
- public IDevice get() {
- if (device == null) {
- WaitForDeviceListener wfdl = new WaitForDeviceListener(serial);
- synchronized (wfdl) {
- AndroidDebugBridge.addDeviceChangeListener(wfdl);
-
- // Check whether we already know about this device.
- IDevice[] devices = AndroidDebugBridge.getBridge().getDevices();
- if (serial != null) {
- for (IDevice d : devices) {
- if (serial.equals(d.getSerialNumber())) {
- // Only accept if there are clients already. Else wait for the callback informing
- // us that we now have clients.
- if (d.hasClients()) {
- device = d;
- }
-
- break;
- }
- }
- } else {
- if (devices.length > 0) {
- device = devices[0];
- }
- }
-
- if (device == null) {
- try {
- wfdl.wait(timeout);
- } catch (InterruptedException e) {
- // Ignore spurious wakeups.
- }
- device = wfdl.getDevice();
- }
-
- AndroidDebugBridge.removeDeviceChangeListener(wfdl);
- }
- }
-
- if (device != null) {
- // Wait for clients.
- WaitForClientsListener wfcl = new WaitForClientsListener(device);
- synchronized (wfcl) {
- AndroidDebugBridge.addDeviceChangeListener(wfcl);
-
- if (!device.hasClients()) {
- try {
- wfcl.wait(timeout);
- } catch (InterruptedException e) {
- // Ignore spurious wakeups.
- }
- }
-
- AndroidDebugBridge.removeDeviceChangeListener(wfcl);
- }
- }
-
- return device;
- }
-
- private static class WaitForDeviceListener implements IDeviceChangeListener {
-
- private String serial;
- private IDevice device;
-
- public WaitForDeviceListener(String serial) {
- this.serial = serial;
- }
-
- public IDevice getDevice() {
- return device;
- }
-
- @Override
- public void deviceChanged(IDevice arg0, int arg1) {
- // We may get a device changed instead of connected. Handle like a connection.
- deviceConnected(arg0);
- }
-
- @Override
- public void deviceConnected(IDevice arg0) {
- if (device != null) {
- // Ignore updates.
- return;
- }
-
- if (serial == null || serial.equals(arg0.getSerialNumber())) {
- device = arg0;
- synchronized (this) {
- notifyAll();
- }
- }
- }
-
- @Override
- public void deviceDisconnected(IDevice arg0) {
- // Ignore disconnects.
- }
-
- }
-
- private static class WaitForClientsListener implements IDeviceChangeListener {
-
- private IDevice myDevice;
-
- public WaitForClientsListener(IDevice myDevice) {
- this.myDevice = myDevice;
- }
-
- @Override
- public void deviceChanged(IDevice arg0, int arg1) {
- if (arg0 == myDevice && (arg1 & IDevice.CHANGE_CLIENT_LIST) != 0) {
- // Got a client list, done here.
- synchronized (this) {
- notifyAll();
- }
- }
- }
-
- @Override
- public void deviceConnected(IDevice arg0) {
- }
-
- @Override
- public void deviceDisconnected(IDevice arg0) {
- }
-
- }
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/DumpData.java b/tools/preload2/src/com/android/preload/DumpData.java
deleted file mode 100644
index d99722416a1d..000000000000
--- a/tools/preload2/src/com/android/preload/DumpData.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Holds the collected data for a process.
- */
-public class DumpData {
- /**
- * Name of the package (=application).
- */
- String packageName;
-
- /**
- * A map of class name to a string for the classloader. This may be a toString equivalent,
- * or just a unique ID.
- */
- Map<String, String> dumpData;
-
- /**
- * The Date when this data was captured. Mostly for display purposes.
- */
- Date date;
-
- /**
- * A cached value for the number of boot classpath classes (classloader value in dumpData is
- * null).
- */
- int bcpClasses;
-
- public DumpData(String packageName, Map<String, String> dumpData, Date date) {
- this.packageName = packageName;
- this.dumpData = dumpData;
- this.date = date;
-
- countBootClassPath();
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- public Date getDate() {
- return date;
- }
-
- public Map<String, String> getDumpData() {
- return dumpData;
- }
-
- public void countBootClassPath() {
- bcpClasses = 0;
- for (Map.Entry<String, String> e : dumpData.entrySet()) {
- if (e.getValue() == null) {
- bcpClasses++;
- }
- }
- }
-
- // Return an inverted mapping.
- public Map<String, Set<String>> invertData() {
- Map<String, Set<String>> ret = new HashMap<>();
- for (Map.Entry<String, String> e : dumpData.entrySet()) {
- if (!ret.containsKey(e.getValue())) {
- ret.put(e.getValue(), new HashSet<String>());
- }
- ret.get(e.getValue()).add(e.getKey());
- }
- return ret;
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/DumpDataIO.java b/tools/preload2/src/com/android/preload/DumpDataIO.java
deleted file mode 100644
index 28625c5531e4..000000000000
--- a/tools/preload2/src/com/android/preload/DumpDataIO.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
-
-import java.io.File;
-import java.io.FileReader;
-import java.text.DateFormat;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * Helper class for serialization and deserialization of a collection of DumpData objects to XML.
- */
-public class DumpDataIO {
-
- /**
- * Serialize the given collection to an XML document. Returns the produced string.
- */
- public static String serialize(Collection<DumpData> data) {
- // We'll do this by hand, constructing a DOM or similar is too complicated for our simple
- // use case.
-
- StringBuilder sb = new StringBuilder();
- sb.append("<preloaded-classes-data>\n");
-
- for (DumpData d : data) {
- serialize(d, sb);
- }
-
- sb.append("</preloaded-classes-data>\n");
- return sb.toString();
- }
-
- private static void serialize(DumpData d, StringBuilder sb) {
- sb.append("<data package=\"" + d.packageName + "\" date=\"" +
- DateFormat.getDateTimeInstance().format(d.date) +"\">\n");
-
- for (Map.Entry<String, String> e : d.dumpData.entrySet()) {
- sb.append("<class name=\"" + e.getKey() + "\" classloader=\"" + e.getValue() + "\"/>\n");
- }
-
- sb.append("</data>\n");
- }
-
- /**
- * Load a collection of DumpData objects from the given file.
- */
- public static Collection<DumpData> deserialize(File f) throws Exception {
- // Use SAX parsing. Our format is very simple. Don't do any schema validation or such.
-
- SAXParserFactory spf = SAXParserFactory.newInstance();
- spf.setNamespaceAware(false);
- SAXParser saxParser = spf.newSAXParser();
-
- XMLReader xmlReader = saxParser.getXMLReader();
- DumpDataContentHandler ddch = new DumpDataContentHandler();
- xmlReader.setContentHandler(ddch);
- xmlReader.parse(new InputSource(new FileReader(f)));
-
- return ddch.data;
- }
-
- private static class DumpDataContentHandler extends DefaultHandler {
- Collection<DumpData> data = new LinkedList<DumpData>();
- DumpData openData = null;
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes)
- throws SAXException {
- if (qName.equals("data")) {
- if (openData != null) {
- throw new IllegalStateException();
- }
- String pkg = attributes.getValue("package");
- String dateString = attributes.getValue("date");
-
- if (pkg == null || dateString == null) {
- throw new IllegalArgumentException();
- }
-
- try {
- Date date = DateFormat.getDateTimeInstance().parse(dateString);
- openData = new DumpData(pkg, new HashMap<String, String>(), date);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- } else if (qName.equals("class")) {
- if (openData == null) {
- throw new IllegalStateException();
- }
- String className = attributes.getValue("name");
- String classLoader = attributes.getValue("classloader");
-
- if (className == null || classLoader == null) {
- throw new IllegalArgumentException();
- }
-
- openData.dumpData.put(className, classLoader.equals("null") ? null : classLoader);
- }
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
- if (qName.equals("data")) {
- if (openData == null) {
- throw new IllegalStateException();
- }
- openData.countBootClassPath();
-
- data.add(openData);
- openData = null;
- }
- }
- }
-}
diff --git a/tools/preload2/src/com/android/preload/DumpTableModel.java b/tools/preload2/src/com/android/preload/DumpTableModel.java
deleted file mode 100644
index d97cbf0df5e5..000000000000
--- a/tools/preload2/src/com/android/preload/DumpTableModel.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.table.AbstractTableModel;
-
-/**
- * A table model for collected DumpData. This is both the internal storage as well as the model
- * for display.
- */
-public class DumpTableModel extends AbstractTableModel {
-
- private List<DumpData> data = new ArrayList<DumpData>();
-
- public void addData(DumpData d) {
- data.add(d);
- fireTableRowsInserted(data.size() - 1, data.size() - 1);
- }
-
- public void clear() {
- int size = data.size();
- if (size > 0) {
- data.clear();
- fireTableRowsDeleted(0, size - 1);
- }
- }
-
- public List<DumpData> getData() {
- return data;
- }
-
- @Override
- public int getRowCount() {
- return data.size();
- }
-
- @Override
- public int getColumnCount() {
- return 4;
- }
-
- @Override
- public String getColumnName(int column) {
- switch (column) {
- case 0:
- return "Package";
- case 1:
- return "Date";
- case 2:
- return "# All Classes";
- case 3:
- return "# Boot Classpath Classes";
-
- default:
- throw new IndexOutOfBoundsException(String.valueOf(column));
- }
- }
-
- @Override
- public Object getValueAt(int rowIndex, int columnIndex) {
- DumpData d = data.get(rowIndex);
- switch (columnIndex) {
- case 0:
- return d.packageName;
- case 1:
- return d.date;
- case 2:
- return d.dumpData.size();
- case 3:
- return d.bcpClasses;
-
- default:
- throw new IndexOutOfBoundsException(String.valueOf(columnIndex));
- }
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/Main.java b/tools/preload2/src/com/android/preload/Main.java
deleted file mode 100644
index 2265e9557c4b..000000000000
--- a/tools/preload2/src/com/android/preload/Main.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.actions.ClearTableAction;
-import com.android.preload.actions.ComputeThresholdAction;
-import com.android.preload.actions.ComputeThresholdXAction;
-import com.android.preload.actions.DeviceSpecific;
-import com.android.preload.actions.ExportAction;
-import com.android.preload.actions.ImportAction;
-import com.android.preload.actions.ReloadListAction;
-import com.android.preload.actions.RunMonkeyAction;
-import com.android.preload.actions.ScanAllPackagesAction;
-import com.android.preload.actions.ScanPackageAction;
-import com.android.preload.actions.ShowDataAction;
-import com.android.preload.actions.WritePreloadedClassesAction;
-import com.android.preload.classdataretrieval.ClassDataRetriever;
-import com.android.preload.classdataretrieval.hprof.Hprof;
-import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
-import com.android.preload.ui.IUI;
-import com.android.preload.ui.SequenceUI;
-import com.android.preload.ui.SwingUI;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import javax.swing.Action;
-import javax.swing.DefaultListModel;
-
-public class Main {
-
- /**
- * Enable tracing mode. This is a work-in-progress to derive compiled-methods data, so it is
- * off for now.
- */
- public final static boolean ENABLE_TRACING = false;
-
- /**
- * Ten-second timeout.
- */
- public final static int DEFAULT_TIMEOUT_MILLIS = 10 * 1000;
-
- /**
- * Hprof timeout. Two minutes.
- */
- public final static int HPROF_TIMEOUT_MILLIS = 120 * 1000;
-
- private IDevice device;
- private static ClientUtils clientUtils;
-
- private DumpTableModel dataTableModel;
- private DefaultListModel<Client> clientListModel;
-
- private IUI ui;
-
- // Actions that need to be updated once a device is selected.
- private Collection<DeviceSpecific> deviceSpecificActions;
-
- // Current main instance.
- private static Main top;
- private static boolean useJdwpClassDataRetriever = false;
-
- public final static String CLASS_PRELOAD_BLACKLIST = "android.app.AlarmManager$" + "|"
- + "android.app.SearchManager$" + "|" + "android.os.FileObserver$" + "|"
- + "com.android.server.PackageManagerService\\$AppDirObserver$" + "|" +
-
-
- // Threads
- "android.os.AsyncTask$" + "|" + "android.pim.ContactsAsyncHelper$" + "|"
- + "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|"
- + "(.*\\$NoPreloadHolder$)";
-
- public final static String SCAN_ALL_CMD = "scan-all";
- public final static String SCAN_PACKAGE_CMD = "scan";
- public final static String COMPUTE_FILE_CMD = "comp";
- public final static String EXPORT_CMD = "export";
- public final static String IMPORT_CMD = "import";
- public final static String WRITE_CMD = "write";
-
- /**
- * @param args
- */
- public static void main(String[] args) {
- Main m;
- if (args.length > 0 && args[0].equals("--seq")) {
- m = createSequencedMain(args);
- } else {
- m = new Main(new SwingUI());
- }
-
- top = m;
- m.startUp();
- }
-
- public Main(IUI ui) {
- this.ui = ui;
-
- clientListModel = new DefaultListModel<Client>();
- dataTableModel = new DumpTableModel();
-
- clientUtils = new ClientUtils(DEFAULT_TIMEOUT_MILLIS); // Client utils with 10s timeout.
-
- List<Action> actions = new ArrayList<Action>();
- actions.add(new ReloadListAction(clientUtils, null, clientListModel));
- actions.add(new ClearTableAction(dataTableModel));
- actions.add(new RunMonkeyAction(null, dataTableModel));
- actions.add(new ScanPackageAction(clientUtils, null, dataTableModel));
- actions.add(new ScanAllPackagesAction(clientUtils, null, dataTableModel));
- actions.add(new ComputeThresholdAction("Compute preloaded-classes", dataTableModel, 2,
- CLASS_PRELOAD_BLACKLIST));
- actions.add(new ComputeThresholdAction("Compute compiled-classes", dataTableModel, 1,
- null));
- actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel,
- CLASS_PRELOAD_BLACKLIST));
- actions.add(new WritePreloadedClassesAction(clientUtils, null, dataTableModel));
- actions.add(new ShowDataAction(dataTableModel));
- actions.add(new ImportAction(dataTableModel));
- actions.add(new ExportAction(dataTableModel));
-
- deviceSpecificActions = new ArrayList<DeviceSpecific>();
- for (Action a : actions) {
- if (a instanceof DeviceSpecific) {
- deviceSpecificActions.add((DeviceSpecific)a);
- }
- }
-
- ui.prepare(clientListModel, dataTableModel, actions);
- }
-
- /**
- * @param args
- * @return
- */
- private static Main createSequencedMain(String[] args) {
- SequenceUI ui = new SequenceUI();
- Main main = new Main(ui);
-
- Iterator<String> it = Arrays.asList(args).iterator();
- it.next(); // --seq
- // Setup
- ui.choice("#" + it.next()); // Device.
- ui.confirmNo(); // Prepare: no.
- // Actions
- try {
- while (it.hasNext()) {
- String op = it.next();
- // Operation: Scan a single package
- if (SCAN_PACKAGE_CMD.equals(op)) {
- System.out.println("Scanning package.");
- ui.action(ScanPackageAction.class);
- ui.client(it.next());
- // Operation: Scan all packages
- } else if (SCAN_ALL_CMD.equals(op)) {
- System.out.println("Scanning all packages.");
- ui.action(ScanAllPackagesAction.class);
- // Operation: Export the output to a file
- } else if (EXPORT_CMD.equals(op)) {
- System.out.println("Exporting data.");
- ui.action(ExportAction.class);
- ui.output(new File(it.next()));
- // Operation: Import the input from a file or directory
- } else if (IMPORT_CMD.equals(op)) {
- System.out.println("Importing data.");
- File file = new File(it.next());
- if (!file.exists()) {
- throw new RuntimeException(
- String.format("File does not exist, %s.", file.getAbsolutePath()));
- } else if (file.isFile()) {
- ui.action(ImportAction.class);
- ui.input(file);
- } else if (file.isDirectory()) {
- for (File content : file.listFiles()) {
- ui.action(ImportAction.class);
- ui.input(content);
- }
- }
- // Operation: Compute preloaded classes with specific threshold
- } else if (COMPUTE_FILE_CMD.equals(op)) {
- System.out.println("Compute preloaded classes.");
- ui.action(ComputeThresholdXAction.class);
- ui.input(it.next());
- ui.confirmYes();
- ui.output(new File(it.next()));
- // Operation: Write preloaded classes from a specific file
- } else if (WRITE_CMD.equals(op)) {
- System.out.println("Writing preloaded classes.");
- ui.action(WritePreloadedClassesAction.class);
- ui.input(new File(it.next()));
- }
- }
- } catch (NoSuchElementException e) {
- System.out.println("Failed to parse action sequence correctly.");
- throw e;
- }
-
- return main;
- }
-
- public static IUI getUI() {
- return top.ui;
- }
-
- public static ClassDataRetriever getClassDataRetriever() {
- if (useJdwpClassDataRetriever) {
- return new JDWPClassDataRetriever();
- } else {
- return new Hprof(HPROF_TIMEOUT_MILLIS);
- }
- }
-
- public IDevice getDevice() {
- return device;
- }
-
- public void setDevice(IDevice device) {
- this.device = device;
- for (DeviceSpecific ds : deviceSpecificActions) {
- ds.setDevice(device);
- }
- }
-
- public DefaultListModel<Client> getClientListModel() {
- return clientListModel;
- }
-
- static class DeviceWrapper {
- IDevice device;
-
- public DeviceWrapper(IDevice d) {
- device = d;
- }
-
- @Override
- public String toString() {
- return device.getName() + " (#" + device.getSerialNumber() + ")";
- }
- }
-
- private void startUp() {
- getUI().showWaitDialog();
- initDevice();
-
- // Load clients.
- new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
-
- getUI().hideWaitDialog();
- getUI().ready();
- }
-
- private void initDevice() {
- DeviceUtils.init(DEFAULT_TIMEOUT_MILLIS);
-
- IDevice devices[] = DeviceUtils.findDevices(DEFAULT_TIMEOUT_MILLIS);
- if (devices == null || devices.length == 0) {
- throw new RuntimeException("Could not find any devices...");
- }
-
- getUI().hideWaitDialog();
-
- DeviceWrapper deviceWrappers[] = new DeviceWrapper[devices.length];
- for (int i = 0; i < devices.length; i++) {
- deviceWrappers[i] = new DeviceWrapper(devices[i]);
- }
-
- DeviceWrapper ret = Main.getUI().showChoiceDialog("Choose a device", "Choose device",
- deviceWrappers);
- if (ret != null) {
- setDevice(ret.device);
- } else {
- System.exit(0);
- }
-
- boolean prepare = Main.getUI().showConfirmDialog("Prepare device?",
- "Do you want to prepare the device? This is highly recommended.");
- if (prepare) {
- String buildType = DeviceUtils.getBuildType(device);
- if (buildType == null || (!buildType.equals("userdebug") && !buildType.equals("eng"))) {
- Main.getUI().showMessageDialog("Need a userdebug or eng build! (Found " + buildType
- + ")");
- return;
- }
- if (DeviceUtils.hasPrebuiltBootImage(device)) {
- Main.getUI().showMessageDialog("Cannot prepare a device with pre-optimized boot "
- + "image!");
- return;
- }
-
- if (ENABLE_TRACING) {
- DeviceUtils.enableTracing(device);
- }
-
- Main.getUI().showMessageDialog("The device will reboot. This will potentially take a "
- + "long time. Please be patient.");
- boolean success = false;
- try {
- success = DeviceUtils.overwritePreloaded(device, null, 15 * 60);
- } catch (Exception e) {
- System.err.println(e);
- } finally {
- if (!success) {
- Main.getUI().showMessageDialog(
- "Removing preloaded-classes failed unexpectedly!");
- }
- }
- }
- }
-
- public static Map<String, String> findAndGetClassData(IDevice device, String packageName)
- throws Exception {
- Client client = clientUtils.findClient(device, packageName, -1);
- if (client == null) {
- throw new RuntimeException("Could not find client...");
- }
- System.out.println("Found client: " + client);
-
- return getClassDataRetriever().getClassData(client);
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
deleted file mode 100644
index 5787d8507230..000000000000
--- a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.Main;
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-
-public abstract class AbstractThreadedAction extends AbstractAction implements Runnable {
-
- protected AbstractThreadedAction(String title) {
- super(title);
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (Main.getUI().isSingleThreaded()) {
- run();
- } else {
- new Thread(this).start();
- }
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java
deleted file mode 100644
index 7906417b7a8d..000000000000
--- a/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.IDevice;
-
-import java.awt.event.ActionEvent;
-
-public abstract class AbstractThreadedDeviceSpecificAction extends AbstractThreadedAction
- implements DeviceSpecific {
-
- protected IDevice device;
-
- protected AbstractThreadedDeviceSpecificAction(String title, IDevice device) {
- super(title);
- this.device = device;
- }
-
- @Override
- public void setDevice(IDevice device) {
- this.device = device;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (device == null) {
- return;
- }
- super.actionPerformed(e);
- }
-}
diff --git a/tools/preload2/src/com/android/preload/actions/ClearTableAction.java b/tools/preload2/src/com/android/preload/actions/ClearTableAction.java
deleted file mode 100644
index c0e4795b6d90..000000000000
--- a/tools/preload2/src/com/android/preload/actions/ClearTableAction.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpTableModel;
-
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-
-public class ClearTableAction extends AbstractAction {
- private final DumpTableModel dataTableModel;
-
- public ClearTableAction(DumpTableModel dataTableModel) {
- super("Clear");
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- dataTableModel.clear();
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
deleted file mode 100644
index 3a7f7f74d755..000000000000
--- a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.regex.Pattern;
-
-import javax.swing.AbstractAction;
-
-/**
- * Compute an intersection of classes from the given data. A class is in the intersection if it
- * appears in at least the number of threshold given packages. An optional blacklist can be
- * used to filter classes from the intersection.
- */
-public class ComputeThresholdAction extends AbstractThreadedAction {
- protected int threshold;
- private Pattern blacklist;
- private DumpTableModel dataTableModel;
-
- /**
- * Create an action with the given parameters. The blacklist is a regular expression
- * that filters classes.
- */
- public ComputeThresholdAction(String name, DumpTableModel dataTableModel, int threshold,
- String blacklist) {
- super(name);
- this.dataTableModel = dataTableModel;
- this.threshold = threshold;
- if (blacklist != null) {
- this.blacklist = Pattern.compile(blacklist);
- }
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- List<DumpData> data = dataTableModel.getData();
- if (data.size() == 0) {
- Main.getUI().showMessageDialog("No data available, please scan packages or run "
- + "monkeys.");
- return;
- }
- if (data.size() == 1) {
- Main.getUI().showMessageDialog("Cannot compute list from only one data set, please "
- + "scan packages or run monkeys.");
- return;
- }
-
- super.actionPerformed(e);
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- Map<String, Set<String>> uses = new HashMap<String, Set<String>>();
- for (DumpData d : dataTableModel.getData()) {
- Main.getUI().updateWaitDialog("Merging " + d.getPackageName());
- updateClassUse(d.getPackageName(), uses, getBootClassPathClasses(d.getDumpData()));
- }
-
- Main.getUI().updateWaitDialog("Computing thresholded set");
- Set<String> result = fromThreshold(uses, blacklist, threshold);
- Main.getUI().hideWaitDialog();
-
- boolean ret = Main.getUI().showConfirmDialog("Computed a set with " + result.size()
- + " classes, would you like to save to disk?", "Save?");
- if (ret) {
- File f = Main.getUI().showSaveDialog();
- if (f != null) {
- saveSet(result, f);
- }
- }
- }
-
- private Set<String> fromThreshold(Map<String, Set<String>> classUses, Pattern blacklist,
- int threshold) {
- TreeSet<String> ret = new TreeSet<>(); // TreeSet so it's nicely ordered by name.
-
- for (Map.Entry<String, Set<String>> e : classUses.entrySet()) {
- if (e.getValue().size() >= threshold) {
- if (blacklist == null || !blacklist.matcher(e.getKey()).matches()) {
- ret.add(e.getKey());
- }
- }
- }
-
- return ret;
- }
-
- private static void updateClassUse(String pkg, Map<String, Set<String>> classUses,
- Set<String> classes) {
- for (String className : classes) {
- Set<String> old = classUses.get(className);
- if (old == null) {
- classUses.put(className, new HashSet<String>());
- }
- classUses.get(className).add(pkg);
- }
- }
-
- private static Set<String> getBootClassPathClasses(Map<String, String> source) {
- Set<String> ret = new HashSet<>();
- for (Map.Entry<String, String> e : source.entrySet()) {
- if (e.getValue() == null) {
- ret.add(e.getKey());
- }
- }
- return ret;
- }
-
- private static void saveSet(Set<String> result, File f) {
- try {
- PrintWriter out = new PrintWriter(f);
- for (String s : result) {
- out.println(s);
- }
- out.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java
deleted file mode 100644
index 3ec0a4c18db1..000000000000
--- a/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-public class ComputeThresholdXAction extends ComputeThresholdAction {
-
- public ComputeThresholdXAction(String name, DumpTableModel dataTableModel,
- String blacklist) {
- super(name, dataTableModel, 1, blacklist);
- }
-
- @Override
- public void run() {
- String value = Main.getUI().showInputDialog("Threshold?");
-
- if (value != null) {
- try {
- threshold = Integer.parseInt(value);
- super.run();
- } catch (Exception exc) {
- }
- }
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java b/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java
deleted file mode 100644
index 35a8f26a99fe..000000000000
--- a/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.IDevice;
-
-/**
- * Marks an action as being device-specific. The user must set the device through the specified
- * method if the device selection changes.
- *
- * Implementors must tolerate a null device (for example, with a no-op). This includes calling
- * any methods before setDevice has been called.
- */
-public interface DeviceSpecific {
-
- /**
- * Set the device that should be used. Note that there is no restriction on calling other
- * methods of the implementor before a setDevice call. Neither is device guaranteed to be
- * non-null.
- *
- * @param device The device to use going forward.
- */
- public void setDevice(IDevice device);
-}
diff --git a/tools/preload2/src/com/android/preload/actions/ExportAction.java b/tools/preload2/src/com/android/preload/actions/ExportAction.java
deleted file mode 100644
index 848a56826788..000000000000
--- a/tools/preload2/src/com/android/preload/actions/ExportAction.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpDataIO;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.PrintWriter;
-
-public class ExportAction extends AbstractThreadedAction {
- private File lastSaveFile;
- private DumpTableModel dataTableModel;
-
- public ExportAction(DumpTableModel dataTableModel) {
- super("Export data");
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- lastSaveFile = Main.getUI().showSaveDialog();
- if (lastSaveFile != null) {
- super.actionPerformed(e);
- }
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- String serialized = DumpDataIO.serialize(dataTableModel.getData());
-
- if (serialized != null) {
- try {
- PrintWriter out = new PrintWriter(lastSaveFile);
- out.println(serialized);
- out.close();
-
- Main.getUI().hideWaitDialog();
- } catch (Exception e) {
- Main.getUI().hideWaitDialog();
- Main.getUI().showMessageDialog("Failed writing: " + e.getMessage());
- }
- }
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ImportAction.java b/tools/preload2/src/com/android/preload/actions/ImportAction.java
deleted file mode 100644
index bfeeb836fd45..000000000000
--- a/tools/preload2/src/com/android/preload/actions/ImportAction.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpData;
-import com.android.preload.DumpDataIO;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.util.Collection;
-
-import javax.swing.AbstractAction;
-
-public class ImportAction extends AbstractThreadedAction {
- private File[] lastOpenFiles;
- private DumpTableModel dataTableModel;
-
- public ImportAction(DumpTableModel dataTableModel) {
- super("Import data");
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- lastOpenFiles = Main.getUI().showOpenDialog(true);
- if (lastOpenFiles != null) {
- super.actionPerformed(e);
- }
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- try {
- for (File f : lastOpenFiles) {
- try {
- Collection<DumpData> data = DumpDataIO.deserialize(f);
-
- for (DumpData d : data) {
- dataTableModel.addData(d);
- }
- } catch (Exception e) {
- Main.getUI().showMessageDialog("Failed reading: " + e.getMessage());
- }
- }
- } finally {
- Main.getUI().hideWaitDialog();
- }
-
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ReloadListAction.java b/tools/preload2/src/com/android/preload/actions/ReloadListAction.java
deleted file mode 100644
index 29f055700dfa..000000000000
--- a/tools/preload2/src/com/android/preload/actions/ReloadListAction.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-
-import java.util.Arrays;
-import java.util.Comparator;
-
-import javax.swing.DefaultListModel;
-
-public class ReloadListAction extends AbstractThreadedDeviceSpecificAction {
-
- private ClientUtils clientUtils;
- private final DefaultListModel<Client> clientListModel;
-
- public ReloadListAction(ClientUtils utils, IDevice device,
- DefaultListModel<Client> clientListModel) {
- super("Reload", device);
- this.clientUtils = utils;
- this.clientListModel = clientListModel;
- }
-
- @Override
- public void run() {
- Client[] clients = clientUtils.findAllClients(device);
- if (clients != null) {
- Arrays.sort(clients, new ClientComparator());
- }
- clientListModel.removeAllElements();
- for (Client c : clients) {
- clientListModel.addElement(c);
- }
- }
-
- private static class ClientComparator implements Comparator<Client> {
-
- @Override
- public int compare(Client o1, Client o2) {
- String s1 = o1.getClientData().getClientDescription();
- String s2 = o2.getClientData().getClientDescription();
-
- if (s1 == null || s2 == null) {
- // Not good, didn't get all data?
- return (s1 == null) ? -1 : 1;
- }
-
- return s1.compareTo(s2);
- }
-
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
deleted file mode 100644
index 29464fc7abdf..000000000000
--- a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.IDevice;
-import com.android.preload.DeviceUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.util.Date;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import javax.swing.AbstractAction;
-
-public class RunMonkeyAction extends AbstractAction implements DeviceSpecific {
-
- private final static String DEFAULT_MONKEY_PACKAGES =
- "com.android.calendar,com.android.gallery3d";
-
- private IDevice device;
- private DumpTableModel dataTableModel;
-
- public RunMonkeyAction(IDevice device, DumpTableModel dataTableModel) {
- super("Run monkey");
- this.device = device;
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void setDevice(IDevice device) {
- this.device = device;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- String packages = Main.getUI().showInputDialog("Please enter packages name to run with"
- + " the monkey, or leave empty for default.");
- if (packages == null) {
- return;
- }
- if (packages.isEmpty()) {
- packages = DEFAULT_MONKEY_PACKAGES;
- }
- Runnable r = new RunMonkeyRunnable(packages);
- if (Main.getUI().isSingleThreaded()) {
- r.run();
- } else {
- new Thread(r).start();
- }
- }
-
- private class RunMonkeyRunnable implements Runnable {
-
- private String packages;
- private final static int ITERATIONS = 1000;
-
- public RunMonkeyRunnable(String packages) {
- this.packages = packages;
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- try {
- String pkgs[] = packages.split(",");
-
- for (String pkg : pkgs) {
- Main.getUI().updateWaitDialog("Running monkey on " + pkg);
-
- try {
- // Stop running app.
- forceStop(pkg);
-
- // Little bit of breather here.
- try {
- Thread.sleep(1000);
- } catch (Exception e) {
- }
-
- DeviceUtils.doShell(device, "monkey -p " + pkg + " " + ITERATIONS, 1,
- TimeUnit.MINUTES);
-
- Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
- Map<String, String> data = Main.findAndGetClassData(device, pkg);
- DumpData dumpData = new DumpData(pkg, data, new Date());
- dataTableModel.addData(dumpData);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- // Stop running app.
- forceStop(pkg);
- }
- }
- } finally {
- Main.getUI().hideWaitDialog();
- }
- }
-
- private void forceStop(String packageName) {
- // Stop running app.
- DeviceUtils.doShell(device, "force-stop " + packageName, 5, TimeUnit.SECONDS);
- DeviceUtils.doShell(device, "kill " + packageName, 5, TimeUnit.SECONDS);
- DeviceUtils.doShell(device, "kill `pid " + packageName + "`", 5, TimeUnit.SECONDS);
- }
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java b/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java
deleted file mode 100644
index d74b8a3f6cfb..000000000000
--- a/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.util.Date;
-import java.util.Map;
-
-public class ScanAllPackagesAction extends AbstractThreadedDeviceSpecificAction {
-
- private ClientUtils clientUtils;
- private DumpTableModel dataTableModel;
-
- public ScanAllPackagesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
- super("Scan all packages", device);
- this.clientUtils = utils;
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- try {
- Client[] clients = clientUtils.findAllClients(device);
- for (Client c : clients) {
- String pkg = c.getClientData().getClientDescription();
- Main.getUI().showWaitDialog();
- Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
-
- try {
- Map<String, String> data = Main.getClassDataRetriever().getClassData(c);
- DumpData dumpData = new DumpData(pkg, data, new Date());
- dataTableModel.addData(dumpData);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- } finally {
- Main.getUI().hideWaitDialog();
- }
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java b/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java
deleted file mode 100644
index 98492bd951bf..000000000000
--- a/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.util.Date;
-import java.util.Map;
-
-public class ScanPackageAction extends AbstractThreadedDeviceSpecificAction {
-
- private ClientUtils clientUtils;
- private DumpTableModel dataTableModel;
-
- public ScanPackageAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
- super("Scan package", device);
- this.clientUtils = utils;
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- try {
- Client client = Main.getUI().getSelectedClient();
- if (client != null) {
- work(client);
- } else {
- Client[] clients = clientUtils.findAllClients(device);
- if (clients.length > 0) {
- ClientWrapper[] clientWrappers = new ClientWrapper[clients.length];
- for (int i = 0; i < clientWrappers.length; i++) {
- clientWrappers[i] = new ClientWrapper(clients[i]);
- }
- Main.getUI().hideWaitDialog();
-
- ClientWrapper ret = Main.getUI().showChoiceDialog("Choose a package to scan",
- "Choose package",
- clientWrappers);
- if (ret != null) {
- work(ret.client);
- }
- }
- }
- } finally {
- Main.getUI().hideWaitDialog();
- }
- }
-
- private void work(Client c) {
- String pkg = c.getClientData().getClientDescription();
- Main.getUI().showWaitDialog();
- Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
-
- try {
- Map<String, String> data = Main.findAndGetClassData(device, pkg);
- DumpData dumpData = new DumpData(pkg, data, new Date());
- dataTableModel.addData(dumpData);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private static class ClientWrapper {
- private Client client;
-
- public ClientWrapper(Client c) {
- client = c;
- }
-
- @Override
- public String toString() {
- return client.getClientData().getClientDescription() + " (pid "
- + client.getClientData().getPid() + ")";
- }
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ShowDataAction.java b/tools/preload2/src/com/android/preload/actions/ShowDataAction.java
deleted file mode 100644
index 2bb175f60772..000000000000
--- a/tools/preload2/src/com/android/preload/actions/ShowDataAction.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.swing.AbstractAction;
-import javax.swing.JFrame;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-
-public class ShowDataAction extends AbstractAction {
- private DumpTableModel dataTableModel;
-
- public ShowDataAction(DumpTableModel dataTableModel) {
- super("Show data");
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- // TODO(agampe): Auto-generated method stub
- int selRow = Main.getUI().getSelectedDataTableRow();
- if (selRow != -1) {
- DumpData data = dataTableModel.getData().get(selRow);
- Map<String, Set<String>> inv = data.invertData();
-
- StringBuilder builder = new StringBuilder();
-
- // First bootclasspath.
- add(builder, "Boot classpath:", inv.get(null));
-
- // Now everything else.
- for (String k : inv.keySet()) {
- if (k != null) {
- builder.append("==================\n\n");
- add(builder, k, inv.get(k));
- }
- }
-
- JFrame newFrame = new JFrame(data.getPackageName() + " " + data.getDate());
- newFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
- newFrame.getContentPane().add(new JScrollPane(new JTextArea(builder.toString())),
- BorderLayout.CENTER);
- newFrame.setSize(800, 600);
- newFrame.setLocationRelativeTo(null);
- newFrame.setVisible(true);
- }
- }
-
- private void add(StringBuilder builder, String head, Set<String> set) {
- builder.append(head);
- builder.append('\n');
- addSet(builder, set);
- builder.append('\n');
- }
-
- private void addSet(StringBuilder builder, Set<String> set) {
- if (set == null) {
- builder.append(" NONE\n");
- return;
- }
- List<String> sorted = new ArrayList<>(set);
- Collections.sort(sorted);
- for (String s : sorted) {
- builder.append(s);
- builder.append('\n');
- }
- }
-} \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java b/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java
deleted file mode 100644
index 9b97f1168df9..000000000000
--- a/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-import com.android.preload.DeviceUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.util.Date;
-import java.util.Map;
-
-public class WritePreloadedClassesAction extends AbstractThreadedDeviceSpecificAction {
- private File preloadedClassFile;
-
- public WritePreloadedClassesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
- super("Write preloaded classes action", device);
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- File[] files = Main.getUI().showOpenDialog(true);
- if (files != null && files.length > 0) {
- preloadedClassFile = files[0];
- super.actionPerformed(e);
- }
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
- try {
- // Write the new file with a 5-minute timeout
- DeviceUtils.overwritePreloaded(device, preloadedClassFile, 5 * 60);
- } catch (Exception e) {
- System.err.println(e);
- } finally {
- Main.getUI().hideWaitDialog();
- }
- }
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java
deleted file mode 100644
index 8d797ee00128..000000000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.classdataretrieval.hprof;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData.IHprofDumpHandler;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class GeneralHprofDumpHandler implements IHprofDumpHandler {
-
- private List<IHprofDumpHandler> handlers = new ArrayList<>();
-
- public void addHandler(IHprofDumpHandler h) {
- synchronized (handlers) {
- handlers.add(h);
- }
- }
-
- public void removeHandler(IHprofDumpHandler h) {
- synchronized (handlers) {
- handlers.remove(h);
- }
- }
-
- private List<IHprofDumpHandler> getIterationList() {
- synchronized (handlers) {
- return new ArrayList<>(handlers);
- }
- }
-
- @Override
- public void onEndFailure(Client arg0, String arg1) {
- List<IHprofDumpHandler> iterList = getIterationList();
- for (IHprofDumpHandler h : iterList) {
- h.onEndFailure(arg0, arg1);
- }
- }
-
- @Override
- public void onSuccess(String arg0, Client arg1) {
- List<IHprofDumpHandler> iterList = getIterationList();
- for (IHprofDumpHandler h : iterList) {
- h.onSuccess(arg0, arg1);
- }
- }
-
- @Override
- public void onSuccess(byte[] arg0, Client arg1) {
- List<IHprofDumpHandler> iterList = getIterationList();
- for (IHprofDumpHandler h : iterList) {
- h.onSuccess(arg0, arg1);
- }
- }
- } \ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java
deleted file mode 100644
index 84ec8b7d0fdd..000000000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.classdataretrieval.hprof;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-import com.android.ddmlib.ClientData.IHprofDumpHandler;
-import com.android.preload.classdataretrieval.ClassDataRetriever;
-import com.android.preload.ui.NullProgressMonitor;
-import com.android.tools.perflib.captures.MemoryMappedFileBuffer;
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Queries;
-import com.android.tools.perflib.heap.Snapshot;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-public class Hprof implements ClassDataRetriever {
-
- private static GeneralHprofDumpHandler hprofHandler;
-
- public static void init() {
- synchronized(Hprof.class) {
- if (hprofHandler == null) {
- ClientData.setHprofDumpHandler(hprofHandler = new GeneralHprofDumpHandler());
- }
- }
- }
-
- public static File doHprof(Client client, int timeout) {
- GetHprof gh = new GetHprof(client, timeout);
- return gh.get();
- }
-
- /**
- * Return a map of class names to class-loader names derived from the hprof dump.
- *
- * @param hprofLocalFile
- */
- public static Map<String, String> analyzeHprof(File hprofLocalFile) throws Exception {
- Snapshot snapshot = Snapshot.createSnapshot(new MemoryMappedFileBuffer(hprofLocalFile));
-
- Map<String, Set<ClassObj>> classes = Queries.classes(snapshot, null);
- Map<String, String> retValue = new HashMap<String, String>();
- for (Map.Entry<String, Set<ClassObj>> e : classes.entrySet()) {
- for (ClassObj c : e.getValue()) {
- String cl = c.getClassLoader() == null ? null : c.getClassLoader().toString();
- String cName = c.getClassName();
- int aDepth = 0;
- while (cName.endsWith("[]")) {
- cName = cName.substring(0, cName.length()-2);
- aDepth++;
- }
- String newName = transformPrimitiveClass(cName);
- if (aDepth > 0) {
- // Need to use kind-a descriptor syntax. If it was transformed, it is primitive.
- if (newName.equals(cName)) {
- newName = "L" + newName + ";";
- }
- for (int i = 0; i < aDepth; i++) {
- newName = "[" + newName;
- }
- }
- retValue.put(newName, cl);
- }
- }
-
- // Free up memory.
- snapshot.dispose();
-
- return retValue;
- }
-
- private static Map<String, String> primitiveMapping;
-
- static {
- primitiveMapping = new HashMap<>();
- primitiveMapping.put("boolean", "Z");
- primitiveMapping.put("byte", "B");
- primitiveMapping.put("char", "C");
- primitiveMapping.put("double", "D");
- primitiveMapping.put("float", "F");
- primitiveMapping.put("int", "I");
- primitiveMapping.put("long", "J");
- primitiveMapping.put("short", "S");
- primitiveMapping.put("void", "V");
- }
-
- private static String transformPrimitiveClass(String name) {
- String rep = primitiveMapping.get(name);
- if (rep != null) {
- return rep;
- }
- return name;
- }
-
- private static class GetHprof implements IHprofDumpHandler {
-
- private File target;
- private long timeout;
- private Client client;
-
- public GetHprof(Client client, long timeout) {
- this.client = client;
- this.timeout = timeout;
- }
-
- public File get() {
- synchronized (this) {
- hprofHandler.addHandler(this);
- client.dumpHprof();
- if (target == null) {
- try {
- wait(timeout);
- } catch (Exception e) {
- System.out.println(e);
- }
- }
- }
-
- hprofHandler.removeHandler(this);
- return target;
- }
-
- private void wakeUp() {
- synchronized (this) {
- notifyAll();
- }
- }
-
- @Override
- public void onEndFailure(Client arg0, String arg1) {
- System.out.println("GetHprof.onEndFailure");
- if (client == arg0) {
- wakeUp();
- }
- }
-
- private static File createTargetFile() {
- try {
- return File.createTempFile("ddms", ".hprof");
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void onSuccess(String arg0, Client arg1) {
- System.out.println("GetHprof.onSuccess");
- if (client == arg1) {
- try {
- target = createTargetFile();
- arg1.getDevice().getSyncService().pullFile(arg0,
- target.getAbsoluteFile().toString(), new NullProgressMonitor());
- } catch (Exception e) {
- if (target != null) {
- target.delete();
- }
- e.printStackTrace();
- target = null;
- }
- wakeUp();
- }
- }
-
- @Override
- public void onSuccess(byte[] arg0, Client arg1) {
- System.out.println("GetHprof.onSuccess");
- if (client == arg1) {
- try {
- target = createTargetFile();
- BufferedOutputStream out =
- new BufferedOutputStream(new FileOutputStream(target));
- out.write(arg0);
- out.close();
- } catch (Exception e) {
- if (target != null) {
- target.delete();
- }
- e.printStackTrace();
- target = null;
- }
- wakeUp();
- }
- }
- }
-
- private int timeout;
-
- public Hprof(int timeout) {
- this.timeout = timeout;
- }
-
- @Override
- public Map<String, String> getClassData(Client client) {
- File hprofLocalFile = Hprof.doHprof(client, timeout);
- if (hprofLocalFile == null) {
- throw new RuntimeException("Failed getting dump...");
- }
- System.out.println("Dump file is " + hprofLocalFile);
-
- try {
- return analyzeHprof(hprofLocalFile);
- } catch (Exception e) {
- throw new RuntimeException(e);
- } finally {
- hprofLocalFile.delete();
- }
- }
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java
deleted file mode 100644
index dbd4c89b27cf..000000000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.classdataretrieval.jdwp;
-
-import com.android.ddmlib.Client;
-import com.android.preload.classdataretrieval.ClassDataRetriever;
-
-import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
-import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
-import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
-import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
-import org.apache.harmony.jpda.tests.jdwp.share.JDWPTestCase;
-import org.apache.harmony.jpda.tests.jdwp.share.JDWPUnitDebuggeeWrapper;
-import org.apache.harmony.jpda.tests.share.JPDALogWriter;
-import org.apache.harmony.jpda.tests.share.JPDATestOptions;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class JDWPClassDataRetriever extends JDWPTestCase implements ClassDataRetriever {
-
- private final Client client;
-
- public JDWPClassDataRetriever() {
- this(null);
- }
-
- public JDWPClassDataRetriever(Client client) {
- this.client = client;
- }
-
-
- @Override
- protected String getDebuggeeClassName() {
- return "<unset>";
- }
-
- @Override
- public Map<String, String> getClassData(Client client) {
- return new JDWPClassDataRetriever(client).retrieve();
- }
-
- private Map<String, String> retrieve() {
- if (client == null) {
- throw new IllegalStateException();
- }
-
- settings = createTestOptions("localhost:" + String.valueOf(client.getDebuggerListenPort()));
- settings.setDebuggeeSuspend("n");
-
- logWriter = new JPDALogWriter(System.out, "", false);
-
- try {
- internalSetUp();
-
- return retrieveImpl();
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- } finally {
- internalTearDown();
- }
- }
-
- private Map<String, String> retrieveImpl() {
- try {
- // Suspend the app.
- {
- CommandPacket packet = new CommandPacket(
- JDWPCommands.VirtualMachineCommandSet.CommandSetID,
- JDWPCommands.VirtualMachineCommandSet.SuspendCommand);
- ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
- if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
- return null;
- }
- }
-
- // List all classes.
- CommandPacket packet = new CommandPacket(
- JDWPCommands.VirtualMachineCommandSet.CommandSetID,
- JDWPCommands.VirtualMachineCommandSet.AllClassesCommand);
- ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
-
- if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
- return null;
- }
-
- int classCount = reply.getNextValueAsInt();
- System.out.println("Runtime reported " + classCount + " classes.");
-
- Map<Long, String> classes = new HashMap<Long, String>();
- Map<Long, String> arrayClasses = new HashMap<Long, String>();
-
- for (int i = 0; i < classCount; i++) {
- byte refTypeTag = reply.getNextValueAsByte();
- long typeID = reply.getNextValueAsReferenceTypeID();
- String signature = reply.getNextValueAsString();
- /* int status = */ reply.getNextValueAsInt();
-
- switch (refTypeTag) {
- case JDWPConstants.TypeTag.CLASS:
- case JDWPConstants.TypeTag.INTERFACE:
- classes.put(typeID, signature);
- break;
-
- case JDWPConstants.TypeTag.ARRAY:
- arrayClasses.put(typeID, signature);
- break;
- }
- }
-
- Map<String, String> result = new HashMap<String, String>();
-
- // Parse all classes.
- for (Map.Entry<Long, String> entry : classes.entrySet()) {
- long typeID = entry.getKey();
- String signature = entry.getValue();
-
- if (!checkClass(typeID, signature, result)) {
- System.err.println("Issue investigating " + signature);
- }
- }
-
- // For arrays, look at the leaf component type.
- for (Map.Entry<Long, String> entry : arrayClasses.entrySet()) {
- long typeID = entry.getKey();
- String signature = entry.getValue();
-
- if (!checkArrayClass(typeID, signature, result)) {
- System.err.println("Issue investigating " + signature);
- }
- }
-
- return result;
- } finally {
- // Resume the app.
- {
- CommandPacket packet = new CommandPacket(
- JDWPCommands.VirtualMachineCommandSet.CommandSetID,
- JDWPCommands.VirtualMachineCommandSet.ResumeCommand);
- /* ReplyPacket reply = */ debuggeeWrapper.vmMirror.performCommand(packet);
- }
- }
- }
-
- private boolean checkClass(long typeID, String signature, Map<String, String> result) {
- CommandPacket packet = new CommandPacket(
- JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
- JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand);
- packet.setNextValueAsReferenceTypeID(typeID);
- ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
- if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
- return false;
- }
-
- long classLoaderID = reply.getNextValueAsObjectID();
-
- // TODO: Investigate the classloader to have a better string?
- String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID);
-
- result.put(getClassName(signature), classLoaderString);
-
- return true;
- }
-
- private boolean checkArrayClass(long typeID, String signature, Map<String, String> result) {
- // Classloaders of array classes are the same as the component class'.
- CommandPacket packet = new CommandPacket(
- JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
- JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand);
- packet.setNextValueAsReferenceTypeID(typeID);
- ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
- if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
- return false;
- }
-
- long classLoaderID = reply.getNextValueAsObjectID();
-
- // TODO: Investigate the classloader to have a better string?
- String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID);
-
- // For array classes, we *need* the signature directly.
- result.put(signature, classLoaderString);
-
- return true;
- }
-
- private static String getClassName(String signature) {
- String withoutLAndSemicolon = signature.substring(1, signature.length() - 1);
- return withoutLAndSemicolon.replace('/', '.');
- }
-
-
- private static JPDATestOptions createTestOptions(String address) {
- JPDATestOptions options = new JPDATestOptions();
- options.setAttachConnectorKind();
- options.setTimeout(1000);
- options.setWaitingTime(1000);
- options.setTransportAddress(address);
- return options;
- }
-
- @Override
- protected JDWPUnitDebuggeeWrapper createDebuggeeWrapper() {
- return new PreloadDebugeeWrapper(settings, logWriter);
- }
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java
deleted file mode 100644
index b9df6d0aeb93..000000000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.classdataretrieval.jdwp;
-
-import org.apache.harmony.jpda.tests.framework.LogWriter;
-import org.apache.harmony.jpda.tests.jdwp.share.JDWPManualDebuggeeWrapper;
-import org.apache.harmony.jpda.tests.share.JPDATestOptions;
-
-import java.io.IOException;
-
-public class PreloadDebugeeWrapper extends JDWPManualDebuggeeWrapper {
-
- public PreloadDebugeeWrapper(JPDATestOptions options, LogWriter writer) {
- super(options, writer);
- }
-
- @Override
- protected Process launchProcess(String cmdLine) throws IOException {
- return null;
- }
-
- @Override
- protected void WaitForProcessExit(Process process) {
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/ui/IUI.java b/tools/preload2/src/com/android/preload/ui/IUI.java
deleted file mode 100644
index 9371463e9a79..000000000000
--- a/tools/preload2/src/com/android/preload/ui/IUI.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.android.preload.ui;
-
-import com.android.ddmlib.Client;
-import java.io.File;
-import java.util.List;
-import javax.swing.Action;
-import javax.swing.ListModel;
-import javax.swing.table.TableModel;
-
-/**
- * UI abstraction for the tool. This allows a graphical mode, command line mode,
- * or silent mode.
- */
-public interface IUI {
-
- void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
- List<Action> actions);
-
- void ready();
-
- boolean isSingleThreaded();
-
- Client getSelectedClient();
-
- int getSelectedDataTableRow();
-
- void showWaitDialog();
-
- void updateWaitDialog(String s);
-
- void hideWaitDialog();
-
- void showMessageDialog(String s);
-
- boolean showConfirmDialog(String title, String message);
-
- String showInputDialog(String message);
-
- <T> T showChoiceDialog(String title, String message, T[] choices);
-
- File showSaveDialog();
-
- File[] showOpenDialog(boolean multi);
-
-}
diff --git a/tools/preload2/src/com/android/preload/ui/SequenceUI.java b/tools/preload2/src/com/android/preload/ui/SequenceUI.java
deleted file mode 100644
index dc6a4f389b10..000000000000
--- a/tools/preload2/src/com/android/preload/ui/SequenceUI.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package com.android.preload.ui;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-import java.io.File;
-import java.util.LinkedList;
-import java.util.List;
-import javax.swing.Action;
-import javax.swing.ListModel;
-import javax.swing.table.TableModel;
-
-public class SequenceUI implements IUI {
-
- private ListModel<Client> clientListModel;
- @SuppressWarnings("unused")
- private TableModel dataTableModel;
- private List<Action> actions;
-
- private List<Object> sequence = new LinkedList<>();
-
- public SequenceUI() {
- }
-
- @Override
- public boolean isSingleThreaded() {
- return true;
- }
-
- @Override
- public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
- List<Action> actions) {
- this.clientListModel = clientListModel;
- this.dataTableModel = dataTableModel;
- this.actions = actions;
- }
-
- public SequenceUI action(Action a) {
- sequence.add(a);
- return this;
- }
-
- public SequenceUI action(Class<? extends Action> actionClass) {
- for (Action a : actions) {
- if (actionClass.equals(a.getClass())) {
- sequence.add(a);
- return this;
- }
- }
- throw new IllegalArgumentException("No action of class " + actionClass + " found.");
- }
-
- public SequenceUI confirmYes() {
- sequence.add(Boolean.TRUE);
- return this;
- }
-
- public SequenceUI confirmNo() {
- sequence.add(Boolean.FALSE);
- return this;
- }
-
- public SequenceUI input(String input) {
- sequence.add(input);
- return this;
- }
-
- public SequenceUI input(File... f) {
- sequence.add(f);
- return this;
- }
-
- public SequenceUI output(File f) {
- sequence.add(f);
- return this;
- }
-
- public SequenceUI tableRow(int i) {
- sequence.add(i);
- return this;
- }
-
- private class ClientSelector {
- private String pkg;
-
- public ClientSelector(String pkg) {
- this.pkg = pkg;
- }
-
- public Client getClient() {
- for (int i = 0; i < clientListModel.getSize(); i++) {
- ClientData cd = clientListModel.getElementAt(i).getClientData();
- if (cd != null) {
- String s = cd.getClientDescription();
- if (pkg.equals(s)) {
- return clientListModel.getElementAt(i);
- }
- }
- }
- throw new RuntimeException("Didn't find client " + pkg);
- }
- }
-
- public SequenceUI client(String pkg) {
- sequence.add(new ClientSelector(pkg));
- return this;
- }
-
- public SequenceUI choice(String pattern) {
- sequence.add(pattern);
- return this;
- }
-
- @Override
- public void ready() {
- // Run the actions.
- // No iterator or foreach loop as the sequence will be emptied while running.
- try {
- while (!sequence.isEmpty()) {
- Object next = sequence.remove(0);
- if (next instanceof Action) {
- ((Action)next).actionPerformed(null);
- } else {
- throw new IllegalStateException("Didn't expect a non-action: " + next);
- }
- }
- } catch (Exception e) {
- e.printStackTrace(System.out);
- }
-
- // Now shut down.
- System.exit(0);
- }
-
- @Override
- public Client getSelectedClient() {
- Object next = sequence.remove(0);
- if (next instanceof ClientSelector) {
- return ((ClientSelector)next).getClient();
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public int getSelectedDataTableRow() {
- Object next = sequence.remove(0);
- if (next instanceof Integer) {
- return ((Integer)next).intValue();
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public void showWaitDialog() {
- }
-
- @Override
- public void updateWaitDialog(String s) {
- System.out.println(s);
- }
-
- @Override
- public void hideWaitDialog() {
- }
-
- @Override
- public void showMessageDialog(String s) {
- System.out.println(s);
- }
-
- @Override
- public boolean showConfirmDialog(String title, String message) {
- Object next = sequence.remove(0);
- if (next instanceof Boolean) {
- return ((Boolean)next).booleanValue();
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public String showInputDialog(String message) {
- Object next = sequence.remove(0);
- if (next instanceof String) {
- return (String)next;
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public <T> T showChoiceDialog(String title, String message, T[] choices) {
- Object next = sequence.remove(0);
- if (next instanceof String) {
- String s = (String)next;
- for (T t : choices) {
- if (t.toString().contains(s)) {
- return t;
- }
- }
- return null;
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public File showSaveDialog() {
- Object next = sequence.remove(0);
- if (next instanceof File) {
- System.out.println(next);
- return (File)next;
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public File[] showOpenDialog(boolean multi) {
- Object next = sequence.remove(0);
- if (next instanceof File[]) {
- return (File[])next;
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/ui/SwingUI.java b/tools/preload2/src/com/android/preload/ui/SwingUI.java
deleted file mode 100644
index cab3744ad74c..000000000000
--- a/tools/preload2/src/com/android/preload/ui/SwingUI.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.ui;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.io.File;
-import java.util.List;
-
-import javax.swing.Action;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JDialog;
-import javax.swing.JFileChooser;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JProgressBar;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.JToolBar;
-import javax.swing.ListModel;
-import javax.swing.SwingUtilities;
-import javax.swing.table.TableModel;
-
-public class SwingUI extends JFrame implements IUI {
-
- private JList<Client> clientList;
- private JTable dataTable;
-
- // Shared file chooser, means the directory is retained.
- private JFileChooser jfc;
-
- public SwingUI() {
- super("Preloaded-classes computation");
- }
-
- @Override
- public boolean isSingleThreaded() {
- return false;
- }
-
- @Override
- public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
- List<Action> actions) {
- getContentPane().add(new JScrollPane(clientList = new JList<Client>(clientListModel)),
- BorderLayout.WEST);
- clientList.setCellRenderer(new ClientListCellRenderer());
- // clientList.addListSelectionListener(listener);
-
- dataTable = new JTable(dataTableModel);
- getContentPane().add(new JScrollPane(dataTable), BorderLayout.CENTER);
-
- JToolBar toolbar = new JToolBar(JToolBar.HORIZONTAL);
- for (Action a : actions) {
- if (a == null) {
- toolbar.addSeparator();
- } else {
- toolbar.add(a);
- }
- }
- getContentPane().add(toolbar, BorderLayout.PAGE_START);
-
- setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- setBounds(100, 100, 800, 600);
-
- setVisible(true);
- }
-
- @Override
- public void ready() {
- }
-
- @Override
- public Client getSelectedClient() {
- return clientList.getSelectedValue();
- }
-
- @Override
- public int getSelectedDataTableRow() {
- return dataTable.getSelectedRow();
- }
-
- private JDialog currentWaitDialog = null;
-
- @Override
- public void showWaitDialog() {
- if (currentWaitDialog == null) {
- currentWaitDialog = new JDialog(this, "Please wait...", true);
- currentWaitDialog.getContentPane().add(new JLabel("Please be patient."),
- BorderLayout.CENTER);
- JProgressBar progress = new JProgressBar(JProgressBar.HORIZONTAL);
- progress.setIndeterminate(true);
- currentWaitDialog.getContentPane().add(progress, BorderLayout.SOUTH);
- currentWaitDialog.setSize(200, 100);
- currentWaitDialog.setLocationRelativeTo(null);
- showWaitDialogLater();
- }
- }
-
- private void showWaitDialogLater() {
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(true); // This is blocking.
- }
- }
- });
- }
-
- @Override
- public void updateWaitDialog(String s) {
- if (currentWaitDialog != null) {
- ((JLabel) currentWaitDialog.getContentPane().getComponent(0)).setText(s);
- Dimension prefSize = currentWaitDialog.getPreferredSize();
- Dimension curSize = currentWaitDialog.getSize();
- if (prefSize.width > curSize.width || prefSize.height > curSize.height) {
- currentWaitDialog.setSize(Math.max(prefSize.width, curSize.width),
- Math.max(prefSize.height, curSize.height));
- currentWaitDialog.invalidate();
- }
- }
- }
-
- @Override
- public void hideWaitDialog() {
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- currentWaitDialog = null;
- }
- }
-
- @Override
- public void showMessageDialog(String s) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try {
- JOptionPane.showMessageDialog(this, s);
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- public boolean showConfirmDialog(String title, String message) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try {
- return JOptionPane.showConfirmDialog(this, title, message, JOptionPane.YES_NO_OPTION)
- == JOptionPane.YES_OPTION;
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- public String showInputDialog(String message) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try {
- return JOptionPane.showInputDialog(message);
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public <T> T showChoiceDialog(String title, String message, T[] choices) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try{
- return (T)JOptionPane.showInputDialog(this,
- title,
- message,
- JOptionPane.QUESTION_MESSAGE,
- null,
- choices,
- choices[0]);
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- public File showSaveDialog() {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try{
- if (jfc == null) {
- jfc = new JFileChooser();
- }
-
- int ret = jfc.showSaveDialog(this);
- if (ret == JFileChooser.APPROVE_OPTION) {
- return jfc.getSelectedFile();
- } else {
- return null;
- }
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- public File[] showOpenDialog(boolean multi) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try{
- if (jfc == null) {
- jfc = new JFileChooser();
- }
-
- jfc.setMultiSelectionEnabled(multi);
- int ret = jfc.showOpenDialog(this);
- if (ret == JFileChooser.APPROVE_OPTION) {
- return jfc.getSelectedFiles();
- } else {
- return null;
- }
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- private class ClientListCellRenderer extends DefaultListCellRenderer {
-
- @Override
- public Component getListCellRendererComponent(JList<?> list, Object value, int index,
- boolean isSelected, boolean cellHasFocus) {
- ClientData cd = ((Client) value).getClientData();
- String s = cd.getClientDescription() + " (pid " + cd.getPid() + ")";
- return super.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
- }
- }
-}
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index 9e51180509a8..e5ec17a1d18d 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -125,6 +125,7 @@ class StaleDataclassProcessor: AbstractProcessor() {
val lastGenerated = annotationParams["time"] as Long
val codegenVersion = annotationParams["codegenVersion"] as String
+ val codegenMajorVersion = codegenVersion.substringBefore(".")
val sourceRelative = File(annotationParams["sourceFile"] as String)
val lastGenInputSignatures = (annotationParams["inputSignatures"] as String).lines().toSet()
@@ -151,7 +152,7 @@ class StaleDataclassProcessor: AbstractProcessor() {
stale += Stale(clazz, source, lastGenerated)
}
- if (codegenVersion != CODEGEN_VERSION) {
+ if (codegenMajorVersion != CODEGEN_VERSION.substringBefore(".")) {
stale += Stale(clazz, source, lastGenerated)
}
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 89ed0800e31c..2f7400d001aa 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -671,6 +671,14 @@ public class WifiManager {
public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
/**
+ * Broadcast intent action indicating that the wifi network settings
+ * had been reset.
+ * @hide
+ */
+ public static final String WIFI_NETWORK_SETTINGS_RESET_ACTION =
+ "android.net.wifi.action.NETWORK_SETTINGS_RESET";
+
+ /**
* Broadcast intent action indicating that a connection to the supplicant has
* been established (and it is now possible
* to perform Wi-Fi operations) or the connection to the supplicant has been